[BUG] Headless session start reports already-authorized claude.ai connectors as requiring authentication; tool calls then succeed
Environment
- Claude Code 2.1.226 (native installer), Linux (Ubuntu 26.04, headless)
- Headless SDK session:
claude --print --sdk-url … --input-format stream-json --output-format stream-json(launched by Claude Code Remote Control) - MCP servers: claude.ai-managed connectors (Vercel, GitHub, Gmail, Google Calendar, Google Drive, Supabase, Claude Code Remote), several authorized in claude.ai connector settings well before the session
Observed
At session start, the injected context states:
The following MCP servers require authentication before their tools can be used: Claude_Code_Remote, Github, Gmail, Google_Calendar, Google_Drive, Supabase, Vercel, claude.ai Microsoft 365 … This session is non-interactive, so Claude cannot run the OAuth flow here. Tell the user that these servers need to be authorized …
Later in the same session, with no authentication action taken by anyone in between:
mcp__claude_ai_Vercel__list_teams→ succeeds (returns the account's team)mcp__claude_ai_Github__get_me→ succeeds (returns the authenticated login)
So the banner misreported at least two connectors that were fully usable. ~/.claude/mcp-needs-auth-cache.json gained fresh entries for exactly the listed servers, timestamped at session start — the state is recomputed each session, so this is a startup misclassification rather than a stale cache, and clearing the file does not help.
Expected
The session-start needs-auth list reflects actual usability. If startup-time verification is not possible (e.g. token refresh is deferred to first tool call), the message should say the status is unverified rather than instructing the model to tell the user re-authorization is required.
Impact
The banner explicitly instructs the model to tell users these capabilities are unavailable until re-authorized. Agents that trust it report false unavailability and send users to re-run OAuth flows that are already complete. We now carry a standing operating rule to make a live read call before believing the banner, which works but shouldn't be necessary.
Hypothesis
The startup evaluation classifies a connector as needs-auth without attempting a token refresh; the refresh happens lazily on the first tool call, which is why calls succeed while the banner says otherwise.
Related (not duplicates)
#78220, #80635, #80822 cover the needs-auth cache wrongly blocking servers; #82527 covers interactive OAuth completing while the CLI still reports needs-auth. This report is the false-positive banner in headless sessions for claude.ai-managed connectors whose tools work on first call.
Showing cached comments. Read the full discussion on GitHub ↗
3 Comments
Additional data point from a different launch path. For Remote Control sessions this looks like parent-process-lifetime state, not per-session recomputation.
Environment: Claude Code 2.1.247, Linux (NixOS), sessions hosted by
claude remote-control— the same multiplexer as in the report; children are spawned as--print --sdk-url … --input-format stream-json --resume=https://api.anthropic.com/v1/code/sessions/cse_….| Launch path | Banner |
|---|---|
| Plain
claude -p, resumed across 4 turns | never appeared || RC-hosted session | appeared on 2 of 5 turns; list shrank 4 → 3 within one parent's lifetime |
Three things that narrow it down:
~/.claude/mcp-needs-auth-cache.jsonmid-session; the banner still appeared on a later turn with the file absent, and the file was never regenerated afterwards — not by new-psessions, not by a full service restart. This is consistent with your "clearing the file does not help", but also rules the file out as the source rather than merely as a fix.systemctl --user restart claude-rc, 6 consecutive turns clean.settings.jsoncarries"disableClaudeAiConnectors": trueand was last modified five months before the affected parent started, so this is not a recently-changed setting that the process failed to pick up. Two parent processes with byte-identical config behaved differently.An extra wrinkle for the connectors-disabled case: no
mcp__*tools were loaded in any of these sessions. The listed servers were not merely mis-flagged as needing auth — they were disabled outright, and the banner still instructed the model to tell the user to go authorize them. That makes the false-unavailability problem worse than in your repro: there is no live read call available to disprove the banner, because the tools do not exist. An agent that trusts the banner has nothing to check it against.The intermittency also seems informative — 2 of 5 turns, and the set shrinking 4 → 3 without any authentication action — which suggests something partially refreshes this state rather than computing it once at startup.
Same shape from cloud code routines, with one difference: here the tools genuinely are absent, not just mis-flagged.
Our setup: scheduled routine,
CustomHTTP MCP connector behind Cloudflare MCP Portal + Cloudflare Access OAuth (29 tools), authorized in claude.ai with every toolAlways allowand enabled in the routine's "Runs with".The same connector works in Claude Web at the same moment (29 tools listed, live tool call returns data). A local interactive Claude Code session fails identically, so the split is Claude Web vs Claude Code, not interactive vs headless.
Also I told the routine to distrust the notice and call anyway; it did, and reported the tools were not found via ToolSearch. Matches @aster-void's wrinkle, so no live read call can disprove the banner when the tools don't exist. Unlike that report, connectors are not disabled here: built-ins load fine in the same session
Additional data point: same symptom on Windows, with a Remote Control session driven from claude.ai/code in the browser.
Environment
claude-code-remoteamong the servers. That name does not appear inclaude mcp liston the host.Observed
mcp__claude_ai_Google_Drive__search_files,mcp__claude_ai_Gmail__search_threadsandmcp__claude_ai_Notion__notion-searchall succeeded, including against a Google shared drive.claude mcp liston the host, run at the same time, shows every one of those connectors as✔ Connected.Freeeandclaude.ai Freee.~/.claude/mcp-needs-auth-cache.jsonstill holds entries timestamped at the previous day's session start (2026-10-06 09:22 local) for Google_Drive, Gmail, Google_Calendar, Notion, Slack, Figma, Claude_Docs and claude-code-remote. The only fresh entries are for Freee. So the long-lived Remote Control host seems to keep re-announcing a stale needs-auth snapshot rather than the current state. This matches @aster-void's parent-process-lifetime observation.Impact
The agent faithfully relays the notice ("tell the user these need authorization"). The user is often away from the machine, on mobile, so they lose real time re-checking connector settings that were never broken. We now work around it by always making one cheap real tool call before reporting a connector as unavailable.
Expected