[BUG] headersHelper not re-run on mid-session 401 (2.1.197): client falls into OAuth /register fallback and stays wedged until manual /mcp reconnect
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 (observed on desktop-bundled 2.1.197; brew CLI 2.1.198 also installed — see Environment)
What's Wrong?
The v2.1.193 changelog says:
Improved headersHelper auth: the helper now re-runs and reconnects automatically when a tool call returns 401/403
On a long-lived session, this re-run does not happen. Instead, when the short-lived token minted by headersHelper expires mid-session, the client falls into the OAuth discovery / dynamic-client-registration fallback (POST {base}/register) and stays wedged for the rest of the session — every subsequent tool call fails identically until a manual /mcp → reconnect.
Setup: HTTP MCP server hosted on Google Cloud Run with --no-allow-unauthenticated (Cloud Run IAM, requires a Google OIDC identity token). ~/.claude.json:
{
"mcpServers": {
"my-server": {
"type": "http",
"url": "https://<service>-<hash>.<region>.run.app/mcp",
"headersHelper": "/Users/<me>/.claude/scripts/gcp-mcp-headers.sh"
}
}
}
The helper prints {"Authorization":"Bearer <gcloud auth print-identity-token>"} (exit 0). Google OIDC identity tokens expire after ~1h.
Timeline observed (single session, desktop app, bundled Claude Code 2.1.197):
- Session start: helper runs, server connects, tool calls work for ~1h. ✅
- Token expires (~1h). Next tool call → the error below. The helper is apparently not re-run: repeated tool calls over the following minutes all fail identically, while a fresh
gcloud auth print-identity-tokenused viacurlagainst the same/mcpendpoint returns 200 at the same moment. If the helper had been re-run + retried per the changelog, the retry would have succeeded. - Only recovery: manual
/mcp→ reconnect (or a new session). Nothing inside the session self-heals.
Note: Cloud Run IAM rejects unauthenticated requests at the infrastructure layer with an HTML 401 page and (afaict) no WWW-Authenticate/OAuth metadata — POST /register can never succeed there. Hypothesis: the OAuth-fallback path pre-empts the 2.1.193 headersHelper re-run+retry path when the 401 body is non-JSON/non-OAuth.
What Should Happen?
Per the v2.1.193 changelog: on a tool-call 401/403, re-run headersHelper, reconnect with the fresh headers, retry once. For servers where a headersHelper is configured, that should take precedence over (or at least be attempted before) OAuth discovery/dynamic client registration — especially when the 401 response carries no OAuth metadata.
Error Messages/Logs
Every tool call after token expiry returns:
HTTP 401: Invalid OAuth error response: SyntaxError: JSON Parse error: Unrecognized token '<'. Raw body:
<html><head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<title>401 Unauthorized</title>
</head>
<body text=#000000 bgcolor=#ffffff>
<h1>Error: Unauthorized</h1>
<h2>Your client does not have permission to the requested URL <code>/register</code>.</h2>
</body></html>
Helper health verified independently at the time of failure:
$ env -i HOME="$HOME" ~/.claude/scripts/gcp-mcp-headers.sh ; echo "exit=$?"
{"Authorization":"Bearer eyJhbGciOiJSUzI1NiIs..."} # valid token
exit=0
$ curl -s -X POST "$MCP_URL" -H "Authorization: Bearer $(gcloud auth print-identity-token)" \
-H "Content-Type: application/json" -H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"...","arguments":{}}}'
# → 200 OK, while the in-session client 401s on the same server
Steps to Reproduce
- Host any MCP server on Cloud Run with
--no-allow-unauthenticated(Cloud Run IAM/OIDC). - Configure it as
type: httpwith aheadersHelperthat prints{"Authorization":"Bearer $(gcloud auth print-identity-token)"}. - Start a session; confirm tools work.
- Keep the session alive past the ~60 min token expiry.
- Call any tool → observe the
/registerOAuth error above instead of a helper re-run + successful retry. All subsequent calls fail identically until manual/mcpreconnect.
Environment
- macOS (Darwin 25.5.0)
- Claude desktop app 1.17377.2, bundled Claude Code runtime 2.1.197 (where the bug was observed live)
- Homebrew CLI 2.1.198 also installed — fresh connections there work (helper runs at connect); the mid-session 401 path is the part that misbehaves
- Server: Google Cloud Run,
--no-allow-unauthenticated(IAM OIDC); infra-layer 401 is an HTML page with no OAuth metadata
Related
- #64894 — headersHelper output not applied at connect time (SDK), falls through to OAuth 2.1 flow. Different lifecycle point (this report: helper works at connect; the 401-triggered re-run doesn't fire mid-session), same OAuth-fallback fingerprint — plausibly the same underlying precedence problem between the OAuth fallback and headersHelper.
- #52200 — docs request for the
/mcpreconnect recovery flow, which is currently the only recovery for this wedge.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗