headersHelper silently ignored since v2.1.85 — Claude Code skips to OAuth discovery instead
What's Wrong?
A transient headersHelper failure permanently poisons the MCP connection state. Once poisoned, headersHelper is never called again and the server is permanently stuck in "needs authentication" — the only recovery is manually clearing the macOS keychain, which isn't discoverable.
Root cause: When headersHelper fails (even transiently), the server returns 401. Claude Code then:
- Enters the OAuth flow (because an
authProvideris always attached to HTTP servers) - Discovers an "auth server" at the MCP server URL and saves that discovery state to the macOS keychain
- Fails to complete OAuth (the server doesn't support it)
From that point on, every startup, hasMcpDiscoveryButNoToken() checks the keychain, finds discovery state but no tokens, returns true, and the connection is skipped entirely with "Skipping connection (cached needs-auth)". The headersHelper is never invoked again.
What Should Happen?
- A transient
headersHelperfailure should not permanently poison the connection state - If
headersHelperis configured, it should always be retried on subsequent connections - Stale OAuth discovery state should not prevent
headersHelperfrom running - At minimum, there should be an automatic way to recover (e.g., clearing stale discovery state on retry, or
headersHelpertaking priority over cached OAuth state)
Steps to Reproduce
- Configure an HTTP MCP server with
headersHelper:
{
"mcpServers": {
"my-server": {
"type": "http",
"url": "https://my-server.example.com/mcp",
"headersHelper": "/path/to/my-auth-script"
}
}
}
- Cause the
headersHelperto fail once (e.g., network issue, expired token cache, script error) - Restart Claude Code
- The server is now permanently stuck in "needs authentication"
headersHelperis never called again (verified via marker file logging)- Clicking "Authenticate" shows "A browser will open for authentication" briefly, then fails silently
Only workaround:
security delete-generic-password -s "Claude Code-credentials" 2>/dev/null
rm ~/.claude/mcp-needs-auth-cache.json 2>/dev/null
Error Messages/Logs
Status: ⚠ needs authentication
Auth: ✗ not authenticated
Error: SDK auth failed: HTTP 401: Invalid OAuth error response: SyntaxError: JSON Parse error:
Unexpected identifier "Missing". Raw body: Missing or invalid Authorization header.
Earlier in logs (when the poisoning occurred):
Error getting headers from headersHelper: did not return a valid value
Skipping connection (cached needs-auth)
Is this a regression?
Yes. Works on v2.1.81, broken on v2.1.85+.
The v2.1.85 changelog added "MCP OAuth Standards: MCP OAuth now follows RFC 9728 Protected Resource Metadata discovery" — this change introduced the OAuth discovery that poisons the connection state after a headersHelper failure.
Note on #41690
Issue #41690 reports the same root cause but was incorrectly auto-closed as a duplicate of #16143 (which is about inline mcpServers in plugin.json manifest parsing — a completely different problem).
Claude Code Version
2.1.85 (also reproduced on 2.1.92)
Platform
Anthropic API
Operating System
macOS, also reproduced on Linux (Ubuntu 24.04 in Domino)
Terminal/Shell
Terminal.app (macOS), bash (Linux)
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗