MCP re-authenticate still clears stored tokens before sign-in completes (regression of 2.1.216 fix), breaking concurrent sessions
Preflight Checklist
- [x] I have searched existing issues — this is a regression of a fix that shipped in 2.1.216
- [x] This is a single bug report
- [x] I am using the latest version of Claude Code (2.1.241; evidence captured on 2.1.238)
What's Wrong?
The 2.1.216 changelog contains:
Fixed MCP re-authenticate revoking working credentials before the new sign-in succeeds
That behaviour is back, or the fix is incomplete. On 2.1.238, /mcp re-authentication still clears the stored token as its first action, roughly 19 seconds before the new token is saved:
18:50:15.230 Using redirect port: 3118 (reusing registered port)
18:50:15.376 Cleared stored tokens (preserved client registration)
18:50:15.641 No access token in storage
18:50:15.642 Authorization URL: https://mcp.linear.app/authorize?...
18:50:15.643 Initial auth result: REDIRECT
18:50:34.252 Completing auth flow with authorization code
18:50:34.954 Saving tokens
18:50:35.127 Auth result: AUTHORIZED
Because MCP credentials are shared across all local sessions, that clear destroys the credential every other running session is using. The practical result is a cascade: re-authenticating one stuck session breaks the sessions that were working, so the user re-authenticates those, which breaks the first. With several sessions open it feels like auth "never sticks".
Observed cascade
Same machine, same day, single MCP server (linear-server, https://mcp.linear.app/mcp):
| Time | Session | Event |
| --- | --- | --- |
| 14:48:45 | A (<project-a>) | re-auth via /mcp → connected |
| 14:49:40 | B (<project-b>) | connected, no re-auth — shared credential works |
| 14:50:16 | C (<project-b>) | connected, no re-auth |
| 18:48:19 | D (<project-a>) | /mcp → Cleared stored tokens → re-auth |
| 18:50:15 | E (<project-c>) | now broken → Cleared stored tokens → re-auth |
Session D had been running for ~3 days (HTTP connection dropped after 261733s uptime) and had been sitting in cached needs-auth state for ~30 hours. Touching it destroyed the credential obtained four hours earlier at 14:48.
Steps to Reproduce
- Configure an OAuth HTTP MCP server (any; observed with Linear at
https://mcp.linear.app/mcp). - Open two Claude Code sessions in different directories.
- Cause an auth failure — e.g. suspend the machine until the access token expires past the server's refresh grace window.
- Re-authenticate session 1 via
/mcp. It connects. - Open a fresh session — it connects on the stored credential, confirming the credential is shared and valid.
- Re-authenticate session 2 via
/mcp. - Observe
Cleared stored tokens (preserved client registration)in session 2's log, followed by the fresh session from step 5 losing access.
Expected Behavior
Re-authentication should obtain and validate the new token before discarding the existing one, so a failed or abandoned sign-in leaves working credentials intact and concurrent sessions are unaffected. This is what 2.1.216 claims to have fixed.
Additional context
This compounds with two other known problems, which is why it is hard to escape:
- #85236 — the refresh lock is per-process, so concurrent sessions race the refresh; against rotation-strict servers this revokes the token family. Linear is rotation-strict (24h access tokens, rotating refresh tokens, 30-minute grace), so it is a second confirmed server for that issue.
- #48670 (closed not-planned) — a session that has cached needs-auth never retries, so the only in-session recovery is
/mcp, which triggers the destructive clear described here.
The combination means: the only way to recover N stuck sessions is N re-authentications, and each one can invalidate the others.
Environment
- Claude Code 2.1.241 (native install); evidence captured on 2.1.238
- macOS (darwin 25.6.0), Node v26.3.0 (bundled runtime)
- Server:
linear-server, HTTP transport, OAuth, scoperead write, 24h access tokens with rotating refresh tokens - Logs:
~/Library/Caches/claude-cli-nodejs/<project>/mcp-logs-linear-server/*.jsonl