[BUG] Cowork: MCP tool approval "Accept" never dispatches the tool call; stopping the run reports "user denied"
[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'ingnpx 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
- In a Cowork session, ask for anything that needs an MCP tool from the desktop-configured server (e.g. "List all magnolia cloud templates").
- Cowork discovers the tools fine ("Loaded tools", "Found tools") and shows the per-call approval prompt: "Using remote-devices magnolia-cloud…".
- Click Accept.
- The tool call hangs indefinitely (several minutes, no progress).
- 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
CanUseToolnever 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.jsonpermissions.allowrules (e.g."mcp__magnolia-cloud") never reach the VM, because--setting-sources userresolves 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
- Configure any stdio MCP server in
claude_desktop_config.json(anmcp-remoteOAuth bridge in my case, but the transport seems irrelevant — the call never reaches the server process). - Start a Cowork session and prompt something that requires one of that server's tools.
- Click Accept on the approval prompt.
- Observe the indefinite hang; stop the run and observe the false "user denied approval" message.
- (Optional, decisive) Tee the MCP server's stderr/stdin traffic to a log: no
tools/callis 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.jsonpermission allow rules inside the Cowork VM.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗