[BUG] Claude account logout/switch discards all MCP OAuth grants (mcpOAuth is stored inside the account credential)

Status Open
Reported on v2.1.251
Maintainer reply None cached
Activity 3 comments · opened Aug 29, 2026

Summary

Logging out of my Claude account and logging back in — including switching between Claude accounts, which I do routinely — discards every MCP OAuth grant. All HTTP MCP servers come back unauthenticated and each one has to be re-authorized through a separate browser round trip.

Nothing on the MCP server side expired. The authorizations are with Cloudflare and Figma; they have nothing to do with which Anthropic account is signed in, but their lifetime is tied to that account session.

Environment

  • Claude Code 2.1.251 (Homebrew cask), macOS 26.5.2, arm64
  • 7 remote MCP servers configured with "type": "http":
  • https://mcp.cloudflare.com/mcp and 5 sibling *.mcp.cloudflare.com/mcp servers (project .mcp.json)
  • https://mcp.figma.com/mcp (official figma plugin 2.2.96, plugin:figma:figma)

Steps to reproduce

  1. Authorize one or more HTTP MCP servers via /mcp.
  2. /logout, then log in again (same account, or a different one).
  3. Every HTTP MCP server is unauthenticated again; /mcp + browser OAuth is required once per server.

Today (2026-08-30) this cost 7 consecutive /mcp authorizations in a single session.

Evidence: MCP grants are stored inside the account credential

macOS Keychain, generic-password items. Structure only, values omitted:

service "Claude Code-credentials"
  claudeAiOauth : { accessToken, refreshToken, expiresAt, refreshTokenExpiresAt, scopes, ... }
  mcpOAuth      :
    "cloudflare-api|<hash>"      : { serverName, serverUrl, accessToken, refreshToken,
                                     clientId, issuer, redirectUri, expiresAt, scope,
                                     discoveryState }
    "cloudflare-observability|…" : { ... }        # 6 Cloudflare servers total
    "plugin:figma:figma|<hash>"  : { serverUrl: https://mcp.figma.com/mcp, ... }

service "Claude Code-credentials-<8 hex>"    # 5 of these, one per account signed in on this machine
  claudeAiOauth : { ... }
  (no mcpOAuth key at all)

Two things follow from this layout:

  • mcpOAuth lives in the same Keychain item as claudeAiOauth, so anything that resets the account credential takes the MCP grants with it.
  • The per-account items carry no mcpOAuth at all, so switching accounts cannot reuse an existing grant even though the grant is valid.

Token lifetimes measured at the moment of forced re-auth, i.e. none of these had expired:

  • Cloudflare: access token ~1 h TTL, refresh token present
  • Figma: access token ~2160 h (~90 days) remaining, refresh token present

The refresh tokens that would have made this a non-event are discarded along with the item.

Impact

  • One browser OAuth round trip per server per account switch; it scales linearly with the number of remote servers (7 here).
  • Parallel sessions lose their MCP tools mid-flight after an unrelated account change.
  • It pushes users toward avoiding logout entirely, or toward abandoning OAuth for static tokens where the server happens to allow it.

Proposed solution

In order of preference:

  1. Store mcpOAuth in its own store, keyed by server URL (plus scope where a server needs it), independent of claudeAiOauth. Logging out clears the Anthropic credential only. This matches the trust model: the grant belongs to the user↔MCP-server pair, not to the Anthropic session.
  2. If MCP grants must stay account-scoped, at minimum preserve them across a logout/login of the same account, and carry existing grants over when a per-account credential item is created.
  3. Failing both, provide an escape hatch: claude mcp auth export / import, or a documented setting such as preserveMcpAuthOnLogout.

Alternatives considered

Configuring servers with a static bearer token instead of OAuth, which works for Cloudflare's hosted servers but is undocumented for general clients, and is not offered at all by Figma's remote server. That is a per-vendor workaround, not a fix.

Related issues

Different mechanisms, same class of failure — MCP authorization state is fragile and expensive to rebuild:

  • #88487 — desktop app update wipes claudeAiOauth from .credentials.json
  • #87405 — MCP servers silently unavailable when a tokenless credential stub blocks Keychain refresh
  • #84331 — macOS CLI login loop, Keychain blob with blanked tokens
  • #84274 — MCP OAuth access token never persisted; server reverts to unauthenticated after restart
  • #84614 — stale dynamic client registration replayed forever
  • #89671 — valid token corrupted by the status check

None of them covers logout / account switching discarding otherwise-valid mcpOAuth grants.

View original on GitHub ↗

3 Comments

ryofukutani · 1 month ago

Cross-references, for anyone hitting the same thing from the server side.

The two vendors whose grants are wiped in my setup now have matching requests open, both asking for an auth path that does not depend on the client's token store:

I have since moved the six Cloudflare servers to headers.Authorization with a read-only API token, which does survive a Claude account logout. Two things worth noting from that migration, since they bear on the design here:

  1. Setting headers.Authorization disables the OAuth fallback entirely. That is the right call, but it means the static-token path is all-or-nothing per server — there is no "use OAuth, and keep it across logout" middle ground today.
  2. It only works because Cloudflare happens to offer static tokens. Figma does not, so that server still has to re-authorize on every logout. A per-vendor workaround cannot close this; the fix has to be in how mcpOAuth is scoped.

Filed from a Claude Code session (dev-project-fb).

suchipi · 1 month ago

This is affecting me as well. It's particularly painful because my work Claude account forces me to re-log-in periodically.

marcindulak · 25 days ago

To prevent this issue from gettting stale, and eventually auto-closed, you'll need to add a comment every time before the 14 days stale interval expires, or collect at least 10 thumbs up. See https://github.com/anthropics/claude-code/issues/87647 for details, and consider upvoting that for visibility.