claude-code - ✅(Solved) Fix MCP OAuth writes corrupt shared credential store, causing Team plan logout across all sessions [1 pull requests, 2 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
anthropics/claude-code#45551Fetched 2026-04-09 08:02:45
View on GitHub
Comments
2
Participants
2
Timeline
7
Reactions
0
Author
Timeline (top)
labeled ×5commented ×2

Authenticating an HTTP MCP server (e.g. Linear at https://mcp.linear.app/mcp) causes Claude Code to lose its Team plan authentication across all active sessions. All sessions display "you've been logged out" and CC falls back to API billing.

Root Cause

Claude Code stores both its own subscription OAuth (claudeAiOauth) and all MCP server OAuth tokens (mcpOAuth) in a single macOS Keychain entry (Claude Code-credentials, one JSON blob). When an MCP OAuth write occurs with a stale cache, null Keychain read, or concurrent read-modify-write race, the resulting JSON is written back without valid claudeAiOauth — logging out all sessions.

Fix Action

Fix / Workaround

Local Workaround

PR fix notes

PR #183: fix(plugin): env-var fallback for ENGRAM_API_TOKEN (engram#83)

Description (problem / solution / changelog)

Closes engram issue #83.

Plugin-side workaround for the shared credential-store race in Claude Code (anthropics/claude-code#45551) that periodically wipes pluginSecrets[\ngram@engram]. Mirrors the existing ENGRAM_URL / ENGRAM_URL_LEGACY pattern.

Changes

  1. plugin.json — \pi_token.required: true -> false\ + version \4.5.0 -> 4.5.1\
  2. .mcp.json — adds \ENGRAM_API_TOKEN_LEGACY = \
  3. run-engram.js — symmetric fallback: copy \ENGRAM_API_TOKEN_LEGACY\ → \ENGRAM_API_TOKEN\ when the user_config value is empty. Plus stderr WARN when both are empty.
  4. commands/setup.md — explicit 'Why settings.json env vars' note citing anthropics/claude-code#45551.

Verified


  • ode --check plugin/engram/scripts/run-engram.js\ — clean
  • plugin.json + .mcp.json parse; version 4.5.1, api_token required false, ENGRAM_API_TOKEN_LEGACY present.

Independent of US3

Off \main\ — zero overlap with PR #181 (US3 observations split) or PR #182 (muxcore bump). Different files, different scope.

Marketplace sync (follow-up, not this PR)

After merge, sync ~/Dev/engram-marketplace/engram/\ files per project-plugin-onboarding-lessons.md.

Changed files

  • plugin/engram/.claude-plugin/plugin.json (modified, +4/-4)
  • plugin/engram/.mcp.json (modified, +2/-1)
  • plugin/engram/commands/setup.md (modified, +16/-0)
  • plugin/engram/scripts/run-engram.js (modified, +14/-0)

Code Example

# Before:
security find-generic-password -a "$USER" -s "Claude Code-credentials" -w | python3 -c "import json,sys; d=json.load(sys.stdin); print(list(d.keys()), len(json.dumps(d)), 'bytes')"
# Output: ['claudeAiOauth', 'mcpOAuth'] 1261 bytes

# Trigger Linear MCP auth via /mcp...

# After:
# Expected smoking gun: mcpOAuth present, claudeAiOauth missing
RAW_BUFFERClick to expand / collapse

Summary

Authenticating an HTTP MCP server (e.g. Linear at https://mcp.linear.app/mcp) causes Claude Code to lose its Team plan authentication across all active sessions. All sessions display "you've been logged out" and CC falls back to API billing.

Root Cause

Claude Code stores both its own subscription OAuth (claudeAiOauth) and all MCP server OAuth tokens (mcpOAuth) in a single macOS Keychain entry (Claude Code-credentials, one JSON blob). When an MCP OAuth write occurs with a stale cache, null Keychain read, or concurrent read-modify-write race, the resulting JSON is written back without valid claudeAiOauth — logging out all sessions.

Environment

  • CC version: 2.1.96 (macOS ARM64)
  • Plan: Team (Stripe subscription)
  • Concurrent sessions: 5 interactive + 1 headless + MCP companions = 36-47 processes sharing one Keychain entry
  • MCP servers: Linear (HTTP/OAuth), Vercel (HTTP/OAuth, disabled), 7 stdio servers

Reproduction

  1. Have 2+ CC sessions running with Team plan auth
  2. Run /mcp and authenticate Linear MCP (https://mcp.linear.app/mcp)
  3. After OAuth callback completes, all sessions show "logged out"
  4. claude auth status reports loggedIn: false
  5. Keychain entry either missing entirely, or contains only mcpOAuth (no claudeAiOauth)

Repro protocol (before/after measurement)

# Before:
security find-generic-password -a "$USER" -s "Claude Code-credentials" -w | python3 -c "import json,sys; d=json.load(sys.stdin); print(list(d.keys()), len(json.dumps(d)), 'bytes')"
# Output: ['claudeAiOauth', 'mcpOAuth'] 1261 bytes

# Trigger Linear MCP auth via /mcp...

# After:
# Expected smoking gun: mcpOAuth present, claudeAiOauth missing

Contributing Bugs

This is not a single bug but at least 5 interacting issues:

#IssueMechanism
1#24317Concurrent session race condition. proper-lockfile with 7.5s max lock budget is insufficient for 10+ processes. Single-use refresh token: one session refreshing invalidates all others.
2#33995Token refresh never persists to disk. refreshOAuthToken() succeeds in memory but update() is never called to write back.
3#36779MCP OAuth write drops claudeAiOauth. Only mcpOAuth persisted, auth token missing. Closest exact-match to this symptom.
4#28542JSON truncation. Discovery metadata bloats shared Keychain JSON past ~2010 bytes → truncation → JSON.parse() fails → full credential reset.
5#37512CLAUDE_CODE_OAUTH_TOKEN silently deletes Keychain. Write to plaintext backend triggers delete from Keychain backend.

Additional Related Issues

  • #5706 — MCP refresh tokens stored but never used (OPEN since 2025, 29 comments)
  • #43000 — Multi-terminal MCP OAuth: storage key includes callback port, causing duplicate entries
  • #44830 — RFC 9728 discovery poisoning: one transient failure permanently blocks OAuth
  • #40834 — Switching auth modes invalidates ALL HTTP MCP OAuth tokens
  • #38074 — Background ccr_inference sessions disrupt CLI sessions every ~10 min
  • #42603 — Plugin hooks can read/refresh CC credentials with zero permission checks
  • #1757 — Users constantly required to re-login (130+ comments, oldest auth issue)

Proposed Fix

The fundamental issue is the shared credential store. claudeAiOauth and mcpOAuth should not be in the same Keychain entry. Either:

  1. Separate Keychain entries for CC auth vs MCP auth (eliminates the clobber entirely)
  2. Atomic read-modify-write with proper locking (the current proper-lockfile budget is too low for typical multi-session environments)
  3. Per-session MCP OAuth state that doesn't touch the shared credential store

Local Workaround

I built a credential backup/restore system (cc-auth-guard.sh) that:

  • Snapshots the Keychain JSON at each SessionStart
  • Detects when claudeAiOauth disappears after MCP auth
  • Auto-restores from the most recent good backup (merging current mcpOAuth with backed-up claudeAiOauth)

This mitigates the symptom but doesn't fix the race condition.

extent analysis

TL;DR

Separate Keychain entries for CC auth and MCP auth to prevent overwriting of claudeAiOauth credentials.

Guidance

  1. Implement separate Keychain entries: Store claudeAiOauth and mcpOAuth in distinct Keychain entries to eliminate the clobbering issue.
  2. Use atomic read-modify-write with proper locking: Increase the proper-lockfile budget to accommodate multi-session environments and prevent concurrent modifications.
  3. Develop per-session MCP OAuth state: Design a system where each session manages its own MCP OAuth state without touching the shared credential store.
  4. Test the local workaround: Utilize the cc-auth-guard.sh script as a temporary solution to mitigate the symptom and gather feedback for a more permanent fix.
  5. Address interacting issues: Tackle the five identified bugs (#24317, #33995, #36779, #28542, #37512) to ensure a comprehensive resolution.

Example

# Example of separate Keychain entries
security add-generic-password -a "$USER" -s "ClaudeCodeAuth" -w "$claudeAiOauth"
security add-generic-password -a "$USER" -s "MCPAuth" -w "$mcpOAuth"

Notes

The proposed fix requires careful consideration of the interacting issues and a thorough testing process to ensure the solution is robust and reliable.

Recommendation

Apply the workaround using separate Keychain entries, as it directly addresses the root cause of the issue and provides a clear path towards a permanent fix. This approach allows for a more controlled and incremental resolution of the problem.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING