anthropics / anthropics/claude-code
claude.ai connectors and local stdio servers yield zero tools at session start (desktop); only a manual connector re-toggle — which uses a different registration path (UUID vs display-name) — makes them appear
- Dominant language
- Python
- Stars
- 145k
- Forks
- 23.1k
- PR merge metrics
- PR metrics pending
Description
## Environment
- Claude Desktop app 1.24012.9 on Windows 11 Pro (10.0.26200), Claude Code (CCD) 2.1.219 running inside it (`CLAUDE_CODE_ENTRYPOINT=claude-desktop`)
- 9 claude.ai OAuth connectors previously connected (Slack, Notion, Dropbox, Gmail, Google Calendar, Google Drive, Supabase, + 2 more), plus local stdio servers (an in-house file server, a desktop-automation server, a PDF viewer)
## Symptom
When a new session starts, **none of the claude.ai connectors' tools are loaded — and neither are several local stdio servers' tools** — even though every connector toggle is ON in the UI. The session runs indefinitely in this state (observed: 8.5 hours, 7+ sessions in a row). Toggling any connector OFF→ON mid-session makes **all** of them (connectors AND local stdio servers) appear at once. Sometimes one OFF→ON cycle is not enough (reproduced on 2026-07-26 and 2026-07-31).
There are **no auth errors**: no 401/403, no token-refresh failures, nothing in `[oauth-v2]` besides `using cached token`. The `needsAuthMcpServers` list contains only `plugin:` servers — the connectors are simply absent, silently.
## What the app's own logs show (`%APPDATA%\Claude\logs\main.log`)
Three code paths push MCP server lists to the SDK. Counts are from one day (2026-07-31):
| path | calls | servers passed | name format | ever yields tools? |
|---|---|---|---|---|
| `LocalSessions.replaceEnabledMcpTools` | 634 | 11 (no connectors) | display name | no |
| `LocalSessions.replaceRemoteMcpServers` | 438 | 18 | **display name** (`'Slack'`, `'Notion'`, …) | **no** |
| `LocalSessions.setMcpServers` (1 server per call) | 222 | 11→18 stepwise | **UUID** (`7984213a-…`) | **yes** |
1. **At session start only the first two run.** Example block (session start, 13:32:13 local):
```
[replaceEnabledMcpTools] Calling SDK with 11 total servers
LocalSessions.replaceRemoteMcpServers: serverCount=7
[replaceRemoteMcpServers] Calling SDK with 18 total servers
[CCD start-timing] preflight=16ms worktree=101ms mcp=436ms query=8ms enqueue=26ms init=11927ms
```
The CCD log says "18 total servers", but the session transcript's `deferred_tools_delta` attachment for that same session records **66 tools from 9 servers — zero connectors, zero affected stdio servers**.
2. **Tools only ever materialize via the UUID path.** Across 2,009 local session transcripts, tool-use references with UUID-prefixed names (`mcp____*`): **364,585**. References with display-name prefixes (`mcp__Slack__*` etc.): effectively **0**. The display-name registration path appears to never produce usable tools.
3. **The toggle workaround works because it uses the UUID path.** On toggle, `setMcpServers` fires once per server: the count walks down 18→11 (all connectors removed) then back 11→18 (re-added, now with UUID names). ~90 s later the transcript records a single `deferred_tools_delta` adding **172 tools** (7 connectors + the missing stdio servers together).
4. **A concurrency bug explains "one toggle is sometimes not enough".** The three paths each push a full list computed independently (last-writer-wins). Observed: count recovers to 17, then two seconds later a competing push rolls it back to 14; `n=11` (all connectors lost) occurred **20 times in one day**. A toggle's re-add steps can be clobbered by a stale competing push.
5. The toggle was performed in one session but the tools appeared in a *different* concurrently-running session, and afterwards brand-new sessions get tools without any toggle — the server list looks app-global, so one repair fixes all subsequent sessions until it breaks again.
Note: `MCP_CONNECTION_NONBLOCKING=true` is injected into the CCD process env by the desktop app; it never appears in either log, so its involvement is unconfirmed. `%APPDATA%\Claude\logs\mcp.log` only covers the desktop app's own MCP client (bursts once per app start), not CCD sessions — CCD-side connection success/failure is not logged anywhere we could find, which made this hard to diagnose.
## Expected
Session start should register connectors via the same (working) path the toggle uses, or at least retry/self-heal when the initial registration yields no tools; and the SDK-side connection outcome should be logged.
## Actual
Zero connector/stdio tools at session start; silent; no retry; manual OFF→ON per-connector is the only recovery, and it randomly needs repeating due to the last-writer-wins races above.
## Repro
1. Windows desktop app with several claude.ai connectors ON.
2. Open new Code sessions over a day; when the list breaks (observed at app start and 20× during one day), every new session has no connector tools.
3. Toggle any connector OFF→ON → ~1-3 min later all missing servers' tools appear in running sessions.
Contributor guide
No contributing guide indexed for this repository
Research direction
Start by comparing the named LocalSessions.replaceEnabledMcpTools, replaceRemoteMcpServers, and setMcpServers paths with the session-start entries in %APPDATA%\Claude\logs\main.log. Trace how their independently computed server lists reach the SDK and inspect the deferred_tools_delta records. Done means session start reliably exposes connector and stdio tools without a toggle, competing updates do not restore stale lists, and SDK connection outcomes are logged.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- backend, tooling
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100