Skip to content

Add force_unlock_workspace MCP tool #372

@sebin

Description

@sebin

Use-cases

When a Terraform workspace lock gets stuck (e.g. a run crashes or is interrupted and the lock isn't released, or the locking session times out without releasing), there is no way today to recover from inside an AI assistant context.

Operators have to leave their MCP-driven flow and either:

  • Click "Force unlock" in the HCP Terraform/TFE UI, or
  • Hand-roll POST /api/v2/workspaces/:id/actions/force-unlock via curl with their TFE token.

Both options break the assistant loop and the second is the kind of action operators tend to get wrong under pressure (correct URL, correct headers, correct method on the right workspace ID).

Attempted Solutions

  • delete_workspace_safely doesn't apply — the workspace is healthy, just locked.
  • action_run (cancel/discard) only helps if the lock is held by a specific run that is still active. A stuck or orphaned lock can't be cleared this way.
  • The go-tfe client already exposes the operation as client.Workspaces.ForceUnlock(ctx, workspaceID), so it's a small wrap of an existing primitive.

We're already running a bespoke Lambda + Bedrock AgentCore gateway target internally at Aircall to expose this single operation. It would be much simpler to retire that and rely on a first-class tool here.

Proposal

Add a force_unlock_workspace MCP tool patterned on delete_workspace_safely:

  • Input: workspace_id (required, e.g. ws-abc123…).
  • Behaviour: call tfeClient.Workspaces.ForceUnlock(ctx, workspaceID).
  • Annotations: ReadOnlyHint=false, DestructiveHint=true, OpenWorldHint=true.
  • Toolset: Terraform.
  • Gated behind ENABLE_TF_OPERATIONS=true, same opt-in flag as delete_workspace_safely and action_run. Default off.
  • TFE-side authorisation is enforced by the existing can-force-unlock permission on the workspace, so the tool inherits that.
  • Description should explicitly warn that force-unlocking while a run is still active can leave state inconsistent, and that the safe fallback is to cancel/discard the run via action_run first.

Implementation is in PR #371.

Open questions for maintainers (happy to adjust in review):

  1. Input shape. I went with workspace_id to match delete_workspace_safely and the underlying go-tfe API. get_workspace_details instead takes terraform_org_name + workspace_name. If maintainers would rather accept org+name here (the recovery use case often starts from a name, not an ID), I'll change it.
  2. Gating. Reusing ENABLE_TF_OPERATIONS keeps the matrix simple. If a finer-grained flag is preferred (e.g. ENABLE_TF_FORCE_UNLOCK), happy to add it.

Metadata

Metadata

Assignees

No one assigned

    Labels

    TriagedIssues has been triaged and captured by the TF MCP team

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions