[BUG] Cowork: MCP tool approval "Accept" never dispatches the tool call; stopping the run reports "user denied"

Status Open
Reported on v2.1.221
Maintainer reply None cached
Activity 2 comments · opened Aug 6, 2026

[BUG] Cowork: MCP tool approval "Accept" never dispatches the tool call; stopping the run reports "user denied"

Environment

  • Claude Desktop 1.25927.0 (macOS), Cowork session
  • Claude Code SDK installed into the Cowork VM: 2.1.221
  • macOS 26.5.2 (Darwin 25.5.0), Apple Silicon
  • MCP server: stdio bridge configured in claude_desktop_config.json — a shell script exec'ing npx mcp-remote <https-url> 16400 --transport http-only --static-oauth-client-info <json> (mcp-remote 0.1.37, OAuth against a Keycloak realm, Streamable HTTP upstream)
  • The same server is reached fine from desktop Chat and from Claude Code local-agent sessions (see control test below)

Symptom

  1. In a Cowork session, ask for anything that needs an MCP tool from the desktop-configured server (e.g. "List all magnolia cloud templates").
  2. Cowork discovers the tools fine ("Loaded tools", "Found tools") and shows the per-call approval prompt: "Using remote-devices magnolia-cloud…".
  3. Click Accept.
  4. The tool call hangs indefinitely (several minutes, no progress).
  5. Stop the run → Cowork reports that the user denied the approval — which never happened.

There is no way to get any MCP tool result in Cowork from this server. Reproduced 100% across multiple sessions and a full app restart.

Evidence: the approved call is never dispatched to the MCP server

The bridge script duplicates stderr of every spawned mcp-remote instance into one combined log (the desktop app spawns two instances — one for the chat runtime, one for the Cowork/remote-devices runtime — and only captures stderr of one of them into mcp-server-<name>.log, so a combined log is needed to see both).

During every stuck attempt, the combined log shows the Cowork-side instance completing the handshake and then receiving nothing — not a single tools/call ever arrives at the bridge:

13:43:13 [42903] [43002] Proxy established successfully between local STDIO and remote StreamableHTTPClientTransport
13:43:13 [42903] [43002] [Local→Remote] initialize
13:43:13 [42903]     "clientInfo": { "name": "local-agent-mode-magnolia-cloud (via mcp-remote 0.1.37)", ... }
13:43:13 [42903] [43002] [Remote→Local] 0
13:43:13 [42903] [43002] [Local→Remote] notifications/initialized
13:43:13 [42903] [43002] [Local→Remote] tools/list
13:43:13 [42903] [43002] [Remote→Local] 1
13:43:51 [42903] [43002] [Local→Remote] notifications/roots/list_changed
                         ... (nothing further — the "accepted" tools/call never arrives)

mcp.log confirms the same from the app side: initialize, tools/list, resources/list round-trip fine; no tools/call is ever logged for the stuck attempts.

Control test (same minute, same bridge instance): a tools/call issued from a Claude Code local-agent session went through the identical local-agent-mode-magnolia-cloud bridge instance and returned a full result in ~1 s:

13:35:30 [37958] [37996] [Local→Remote] tools/call
13:35:31 [37958] [37996] [Remote→Local] 2

So the MCP server, the OAuth bridge, and token refresh are all healthy. The call dies inside Cowork's approval → dispatch plumbing, before the MCP layer.

Analysis

cowork_vm_node.log shows Cowork sessions run claude inside an isolated VM with --permission-prompt-tool stdio and --setting-sources user:

  • The permission request round-trips VM → host UI → VM over stdio. The return leg after clicking Accept appears to be broken for remote-devices-proxied MCP servers: the pending CanUseTool never resolves, the call is never dispatched, and when the run is stopped the pending request is resolved as denied — misattributing Cowork's own stuck state to the user.
  • No configuration workaround exists: host ~/.claude/settings.json permissions.allow rules (e.g. "mcp__magnolia-cloud") never reach the VM, because --setting-sources user resolves to the VM-local user settings.

This looks like the same class of defect as #56243 (Cowork VM bridge auto-cancels MCP elicitation/create that works in Claude Code CLI): an interactive VM↔host round-trip wired up for the CLI but not completed for Cowork. Related: #24433 ("Always allow" does not persist in Cowork — closed as not planned), #44006, #61027/#61097.

Steps to reproduce

  1. Configure any stdio MCP server in claude_desktop_config.json (an mcp-remote OAuth bridge in my case, but the transport seems irrelevant — the call never reaches the server process).
  2. Start a Cowork session and prompt something that requires one of that server's tools.
  3. Click Accept on the approval prompt.
  4. Observe the indefinite hang; stop the run and observe the false "user denied approval" message.
  5. (Optional, decisive) Tee the MCP server's stderr/stdin traffic to a log: no tools/call is ever received.

Expected behavior

  • Accept dispatches the tool call; the result comes back (as it does in desktop Chat and Claude Code sessions using the very same server process).
  • If a pending approval is aborted by stopping the run, it should be reported as cancelled/timed out, not as denied by the user.
  • Ideally: a working "always allow" for Cowork (see #24433), or honoring host ~/.claude/settings.json permission allow rules inside the Cowork VM.

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗