[BUG] CCR proxy returns -32003 needs_approval and the retroactive approval card cannot succeed — root cause analysis from the shipped client (2.1.220)
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
MCP tool calls fail with MCP error -32003: MCP tool call requires approval after the user has already approved them — twice.
-32003 is not raised by the client's permission layer. It is returned by the CCR MCP proxy (api.anthropic.com/v2/ccr-sessions/{session}/mcp) as needs_approval. The client answers it by surfacing a second, retroactive approval card and retrying the identical arguments. In the failing case the retry is refused again, so the user has approved twice and still sees -32003.
That card is constructed with suppressAlwaysAllowRule: true hardcoded, so no "Always allow" is ever offered and permissions.allow entries in settings.json cannot affect this path. Several open issues advise users to fix their allowlist; the allowlist provably cannot help here.
What I see inside a single session:
| Server registration | Result | Approval dialogs |
| --- | --- | --- |
| Friendly name (e.g. Claude_Code_Remote) early in the session | works | one |
| Same server, UUID registration, after a mid-session reconnect | MCP error -32003 | two |
| Friendly name after that reconnect | No such tool available | zero |
| A different connector (Gmail, Drive) under its UUID, same moment | works | one |
The last row matters: the UUID naming itself is harmless. Something else distinguishes this server — see Additional information.
Existing reports of the same fault: #61015, #61027, #61044, #61097, #61143, #79711, #79983.
What Should Happen?
Either the retroactive approval should actually satisfy the proxy on retry, or — better — a connector the user has already authorised should not require per-call approval at all.
Today the user approves twice and the call still fails, with an error message that names approval as the problem when approval has already been given.
Specifically:
- Once the retroactive approval card is accepted, the retry should be accepted by the proxy rather than returning
needs_approvalagain. - The friendly-name registration of a
statsig-origin server should be restored after an MCP reconnect, instead of leaving only the UUID-keyed duplicate that cannot be approved. - If per-call approval genuinely is required by design, the error should say so, and
permissions.allowshould either work or be documented as inapplicable — right now users are repeatedly advised to fix an allowlist that cannot reach this code path.
For unattended Routines this is the difference between annoying and fatal: there is nobody present to tap the retroactive card, so an affected connector cannot be used at all.
Error Messages/Logs
The error returned to the model, verbatim:
MCP error -32003: MCP tool call requires approval
Recognised by the client as `error.code === -32003` together with `"args_sha256" in error.data`.
Log line in the shipped bundle (2.1.220):
Tool '${tool}' returned -32003 needs_approval (tool_name=…) — surfacing retroactive approval card
Telemetry: `tengu_mcp_proxy_needs_approval_retry`
Metric: `mcp_ccr_needs_approval`, with outcomes `retry_failed`, `no_prompt_surface`, `arm_not_fired`, `edited_input`, `denied`
The permission card the client raises:
{
behavior: "ask",
suppressAlwaysAllowRule: true,
message: `The ${fullyQualifiedName} connector requires approval for this call.`,
decisionReason: { type: "other", reason: "This connector call requires your approval to proceed." }
}
On `allow` it retries the **identical** arguments; any edited input aborts with `ccr_proxy_needs_approval_edited_input`. The retry is armed once per call.
For the same server under its friendly name after the reconnect, no dialog appears at all and the call returns:
No such tool available
Steps to Reproduce
- Start a Claude Code on the web session with connectors attached.
- Within the first minutes, call a tool on the harness-injected remote/meta MCP server (e.g. a routine tool such as
list_triggers). Approve the single dialog — it succeeds. - Keep working. At some point the MCP servers reconnect on their own — no restart, no config change, no user action.
- Call the same tool again:
- under the friendly name →
No such tool available, no dialog at all - under the connector UUID → two dialogs, both approved, then
MCP error -32003
- In the same session, call a Gmail or Drive tool under its UUID — it succeeds with one dialog, which shows the UUID naming itself is not the fault.
Measured in one session: last success at +4m36s from session start, first failure at +16m, with the reconnect in between. After that the affected server stays unusable for the rest of the session; only starting a new session restores it.
Claude Model
Opus
Is this a regression?
I don't know
Last Working Version
_No response_
Claude Code Version
2.1.220
Platform
Anthropic API
Operating System
Ubuntu/Debian Linux
Terminal/Shell
Other
Additional Information
Why one server dies and the others survive the same reconnect
The client writes /tmp/mcp-config-{session_id}.json. In an affected session it contains:
| Server key | Proxied mcp_url | X-MCP-Server-Origin |
| --- | --- | --- |
| bf7c680d-… (routine/meta server) | https://api.anthropic.com/v1/code/mcp/meta | statsig |
| 2de66761-… (Gmail) | https://gmailmcp.googleapis.com/mcp/v1 | custom |
| github | — (its own path /ccr-sessions/{id}/github/mcp) | — |
- Every proxied connector is keyed by connector UUID; only
githubgets a literal name. That is exactly why, after a reconnect, connectors reappear asmcp__<uuid>__*while GitHub keepsmcp__github__*. The "servers renamed themselves" effect several issues mention is just this file. - The friendly-named registration is not in that file at all. The working registration comes from session bootstrap; what survives a reconnect is the UUID-keyed, proxy-routed duplicate of the same backend — i.e. the one that must pass
needs_approval. - The meta/routine server is injected with
X-MCP-Server-Origin: statsig, not as a user connector. That is the clearest difference from the connectors that keep working.
Impact
- On web and mobile there is no terminal to fall back to, so once this hits, the affected server is unusable for the rest of the session.
- For Routines (unattended runs) it is fatal rather than annoying: there is nobody to tap the retroactive card, so an affected connector simply cannot be used. I believe that is what #61015 / #61027 / #61044 are describing.
permissions.allowinsettings.jsoncannot help, for the hardcoded reason above. Several issues contain advice to fix the allowlist; it is a dead end and worth correcting in those threads.
Questions that would confirm or refute this
- Under what conditions does the proxy return
needs_approvalfor a connector the user has already authorised — is it keyed to the tool's_meta["anthropic/requiresUserInteraction"]? - On the retry, what is
args_sha256compared against, and does a change of server registration (bootstrap name → UUID key) invalidate the match? - Is the friendly-name registration of a
statsig-origin server expected to be restored after a reconnect? Right now it is not, and the surviving duplicate is the one that cannot be approved.
Related
#61015 (closed, "should be addressed", no cause or version given), #61027, #61143, #61097, #61044 (open — "no approval UI shown, reconnect does not resolve"), #79711, #79983. I think this analysis explains all of them; happy to have it merged into whichever is the canonical thread.
Account context: personal claude.ai subscription, no organization tool policies. Affected server: the harness-injected remote/meta MCP server (routine tools).
---
_Generated by Claude Code_
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗