anthropics / anthropics/claude-code
[BUG] .credentials.json mcpOAuth grows unbounded: claude.ai connector tokens re-stored under a session-scoped serverUrl every session (1,681 records / 906 KB, same token ×113)
- Langage dominant
- Python
- Étoiles
- 145k
- Forks
- 23.1k
- Métriques de merge des PR
- Métriques de PR en attente
Description
## Summary
`~/.claude/.credentials.json` → `mcpOAuth` grows without bound. Every new session re-stores the OAuth record for each claude.ai connector under a **new key and a new `serverUrl`**, even though the access/refresh token is identical to the previous record. Nothing is ever pruned.
## Environment
- Claude Code 2.1.265 (native install, `~/.local/share/claude/versions/2.1.265`)
- macOS 26 (Darwin 25.3.0), Apple Silicon
- Auth: claude.ai login (no API key); ~29 connectors enabled on the account
- Heavy multi-session use (interactive sessions, subagents, headless `claude -p` from launchd)
## Observed
- `.credentials.json` is **906 KB** with **1,681 `mcpOAuth` records** across **29 distinct connectors**.
- The claude.ai connectors each have **~113 records** (Gmail 113, Slack 113, Zoom 113, QuickBooks 113, Netlify 113, Google Drive 113, Google Calendar 113, Plaud 113, Tally 113, Claude_Code_Remote 112, Notion 111, Microsoft_365 111, …). The count matches the number of sessions started since each connector was added.
- For the 113 Gmail records: **113 distinct `serverUrl`, 113 distinct `clientId`, but exactly 1 distinct `accessToken` and 1 distinct `refreshToken`** (compared by hash). It is the same token stored 113 times.
- The `serverUrl` is session-scoped: `https://api.anthropic.com/v2/ccr-sessions//mcp?mcp_server_id=…&mcp_url=…&toolbox_mcp_server_id=…`. Records differ only in the `ccr-sessions/` path segment and the query params. The record key is `|<16-hex hash>`, presumably derived from that URL, so every session produces a fresh key.
- Only 2 of 1,681 records carry `expiresAt`; the rest have no expiry metadata that would allow cleanup.
- Growth observed over one day: 1,653 → 1,681 records (28 new = 2 sessions × 14 connectors).
## Expected
- One record per connector (key by connector / `mcp_server_id`, not by the session-scoped URL), updated in place on refresh.
- Or: prune records whose session has ended, and dedupe identical tokens on write.
## Impact
- File parsed on every session start keeps growing (already ~1 MB; ~14 records added per session).
- The same refresh token is duplicated ~113× on disk, which widens the blast radius of any credential-file exposure and makes manual cleanup risky (unclear which record a live session reads).
- Users cannot safely hand-edit the file without risking a re-login on every connector.
## Repro
1. Log in via claude.ai with several connectors enabled.
2. Note `python3 -c "import json;print(len(json.load(open('$HOME/.claude/.credentials.json'))['mcpOAuth']))"`.
3. Start and end a new `claude` session (interactive or `claude -p "hi"`).
4. Re-run step 2: the count increases by the number of enabled connectors; `serverUrl` of the new records contains the new session id; token values match the previous records.
No secrets included above; token comparison was done by hash locally.
Guide de contribution
Aucun guide de contribution indexé pour ce dépôt
Piste de recherche
Start with ~/.claude/.credentials.json and the supplied Python count command, then trace where mcpOAuth records are written and how connector identity and serverUrl are used. Reproduce across sessions and verify that growth stops, duplicate token records are avoided or expired sessions are pruned, and existing connector authentication remains usable.
Rédigé par le modèle d'indexation à partir du texte de l'issue.
Évaluation
- Domaine
- authentication, security
- Type d'issue
- Bug
- Difficulté
- 4/5
- Temps estimé
- 3-5 jours
- Activité
- Active
- Clarté
- Plutôt claire
- Accessibilité débutants
- 48/100