[BUG] HTTP MCP OAuth tokens written to macOS Keychain but not loaded at session start — re-auth required every session
What's Wrong?
Every Claude Code session starts with all HTTP MCP servers in ! Needs authentication state, even when valid OAuth tokens are present in the macOS Keychain from a successful prior auth flow. The runtime appears to write tokens on auth completion but not read them on subsequent startups, so each new session requires manual re-auth via /mcp → server → Authenticate.
This is the same pattern reported in the prior issues #16957, #20785, #21333, #25245, #27509, and currently-open #47540 — but those reports either closed quickly as "fixed" / "duplicate of fixed," or describe the symptom without the Keychain-level evidence that distinguishes the underlying mechanism. Local session history shows this issue has been recurring continuously since at least 2026-03-01 (60+ days, 83+ distinct sessions matched a Needs authentication search across my Claude Code history). The 2026-05-04 stdio→HTTP transport migration changed the storage surface (Keychain service name Codex MCP Credentials) but did not introduce the underlying behavior.
What Should Happen?
After a successful OAuth flow, the token should be read from the Keychain at next session start and the MCP server should connect automatically without requiring manual re-auth, until the token genuinely expires. When refresh tokens are present (as they are for Notion), the client should refresh silently rather than mark the server as needing re-auth.
Error Messages/Logs
$ claude mcp list
notion: https://mcp.notion.com/mcp (HTTP) - ! Needs authentication
glean_default: https://<redacted>.glean.com/mcp/default (HTTP) - ! Needs authentication
plugin:linear:linear: https://mcp.linear.app/mcp (HTTP) - ! Needs authentication
plugin:vercel:vercel: https://mcp.vercel.com (HTTP) - ! Needs authentication
plugin:slack:slack: https://mcp.slack.com/mcp (HTTP) - ! Needs authentication
[...]
$ security find-generic-password -s "Codex MCP Credentials" -a "notion|<hash>"
"acct"<blob>="notion|eac663db915250e7"
"cdat"<timedate>="20260407182057Z\000"
"mdat"<timedate>="20260509042212Z\000"
"svce"<blob>="Codex MCP Credentials"
# Token IS in Keychain (mdat = today). Yet:
$ cat ~/.claude/mcp-needs-auth-cache.json
{"notion":{"timestamp":1778348802503}}
# Runtime stamped this flag despite a valid Keychain entry existing.
# ~/Library/Logs/Claude/main.log: zero entries matching notion|mcp.notion.com|oauth|401|refresh
Steps to Reproduce
- Configure an HTTP MCP server, e.g. Notion:
```
claude mcp add --scope user --transport http notion https://mcp.notion.com/mcp
~/.claude.json
Both and ~/.claude/settings.json end up with notion: { type: "http", url: "https://mcp.notion.com/mcp" }`.
- Run
/mcp→ notion → Authenticate. Complete browser OAuth flow. - Verify it works:
claude mcp listshowsnotion: ✓ Connected.security find-generic-password -s "Codex MCP Credentials" -a "notion|<hash>"shows a stored credential with currentmdat.- A test tool call (e.g.
mcp__notion__findfor a known page) succeeds.
- Quit Claude Code. Relaunch in a new session.
- Bug:
claude mcp listimmediately showsnotion: ! Needs authentication. The Keychain entry is unchanged (still has the valid token), but~/.claude/mcp-needs-auth-cache.jsonhas been re-stamped with a new timestamp. No log line about token load failure, no refresh attempt observed in~/Library/Logs/Claude/main.log. No browser opens automatically — the user must manually re-trigger via/mcp.
This reproduces deterministically every restart. Affects Notion, Glean, and other HTTP MCP servers that use the same Codex MCP Credentials Keychain service.
Is this a regression?
I don't know — earliest evidence in my local Claude Code session history is 2026-03-01, predating my use of Notion MCP specifically. The same OAuth-not-persisting pattern has been filed and closed multiple times across Jan–May 2026 (#16957, #20785, #21333, #25245, #27509, #47540), so the underlying behavior appears to be a long-running issue with intermittent surface-level fixes that don't durably resolve it.
Last Working Version
N/A — predates my installation history.
Claude Code Version
2.1.138 (Claude Code)
Platform
Anthropic API
Operating System
macOS (26.4.1)
Terminal/Shell
iTerm2 (with tmux)
Additional Information
Distinguishing detail vs. prior reports: most prior issues describe the symptom ("re-auth required every session") without ruling out "no persistence layer at all." The macOS Keychain entry under service Codex MCP Credentials with account <server>|<hash> confirms tokens are being written at auth completion. The bug is therefore not "tokens not stored" but "stored tokens not read at startup" (or "stored tokens not trusted at startup"). This narrows the fix surface considerably.
Cross-server: any HTTP MCP server that uses Codex MCP Credentials Keychain service shows the same behavior. Notion and Glean both have stored Keychain entries; both show Needs authentication at every fresh session.
Logs are silent: ~/Library/Logs/Claude/main.log has zero entries matching notion, mcp.notion.com, oauth, 401, or refresh across multiple session-start cycles. Whatever decides "this server needs auth" doesn't log its decision, which makes self-diagnosis difficult for users.
Related issues for triage context: #16957, #20785, #21333, #25245, #27509 (all closed Jan–Feb 2026), #47540 (open since 2026-04-13 on Windows). #52922 (Notion-specific, closed 2026-05-06) is a different bug — it was a redirect_uri / OAuth-state mismatch during initial handshake, not a persistence issue.
My local config is clean: no registration collisions, no stdio entries, no empty plugin .mcp.json shadowing, lowercase server names, both ~/.claude.json and ~/.claude/settings.json agree. The bug is in the runtime, not user configuration.
This issue has 5 comments on GitHub. Read the full discussion on GitHub ↗