[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

Open 💬 1 comment Opened Jul 2, 2026 by toddmcmullen-cpu

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):

  1. Session start: helper runs, server connects, tool calls work for ~1h. ✅
  2. 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-token used via curl against the same /mcp endpoint returns 200 at the same moment. If the helper had been re-run + retried per the changelog, the retry would have succeeded.
  3. 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

  1. Host any MCP server on Cloud Run with --no-allow-unauthenticated (Cloud Run IAM/OIDC).
  2. Configure it as type: http with a headersHelper that prints {"Authorization":"Bearer $(gcloud auth print-identity-token)"}.
  3. Start a session; confirm tools work.
  4. Keep the session alive past the ~60 min token expiry.
  5. Call any tool → observe the /register OAuth error above instead of a helper re-run + successful retry. All subsequent calls fail identically until manual /mcp reconnect.

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 /mcp reconnect recovery flow, which is currently the only recovery for this wedge.

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗