[BUG] Claude Desktop: hardcoded 60s initialize timeout drops stdio MCP servers whose package-runner cold start exceeds it
Summary
Claude Desktop cancels the MCP initialize request after exactly 60 seconds and there is no way to raise that limit. For stdio servers launched through a package runner (uvx, npx, pipx run), the download+install of dependencies happens inside that 60s window, before the server process exists. Any dependency refresh that pushes cold start past 60s therefore drops the server permanently for that session.
This is not a hypothetical: a routine upstream release of a transitive dependency (botocore, which ships a new version every business day) is enough to take a working configuration to a fully broken one overnight, with no change on the user's side.
Environment
- Claude Desktop 1.25927.0 (macOS 26.5.2, arm64)
- 3 ×
stdioMCP servers, identical launcher:uvx --with 'mcp[cli]<2' opensearch-mcp-server-py uv0.8.3
What happens
From ~/Library/Logs/Claude/mcp-server-<name>.log, identical in all three servers:
10:42:46.158Z [info] Initializing server...
10:42:46.170Z [info] Server started and connected successfully
10:42:46.194Z [info] Message from client: method="initialize" id=0
Downloading botocore (14.8MiB)
10:43:46.215Z [info] Message from client: method="notifications/cancelled" <-- +60.000s
10:43:46.216Z [info] Client transport closed
10:43:48.229Z [info] Server transport closed
The cancellation lands 60.000s after initialize — a fixed deadline, not a network failure. The servers' tools are then absent from the session entirely.
Measured by hand, same command, same env:
| Condition | Time to initialize response |
|---|---|
| Cold (dependency resolution + download of 68 packages) | 110 s |
| Warm (uv cache populated) | 7–26 s |
Warm start succeeds and the servers work perfectly. So the only thing standing between "works" and "silently gone" is whether an upstream package published a release since the last launch.
Root cause chain
- The MCP server package declares
boto3>=1.39.0— an open upper bound. botocorereleases daily (24 releases in July 2026 alone).uvxresolves to the newest match on each launch; a newbotocoreinvalidates the cached environment and triggers a fresh 14.8 MB download (occasionallynumpy/scipy/scikit-learntoo, ~50 MB total, 68 packages).- Cold install takes ~110 s > 60 s deadline →
notifications/cancelled. - All three servers race for the same uplink simultaneously, making each slower.
Evidence that step 3 happens routinely: the local uv cache holds 42 separate environments spanning 15 botocore versions (1.43.46 … 1.43.64), and has grown to 11 GB. botocore 1.43.64 was published at 20:12 the previous day; the failure above is from the next morning's first launch.
Why notifications/progress cannot solve this
The usual answer to a slow initialize is for the server to emit progress notifications and let the client extend its deadline. That is structurally impossible here. During the download there is no server process yet — uvx is still assembling the environment that will contain the server. Nothing exists that could send a notification. A client-side configurable deadline is the only thing that can help.
Why existing issues don't cover this
- #43791, #22542, #16837, #3033, #20335 — all about tool call / request timeouts, not the
initializehandshake. - #60224 — closest, but Claude Code CLI on Windows and a session-init probe; closed as not planned.
- #26666 — lazy init to unblock the prompt; closed as duplicate. Related but orthogonal: lazy init alone would still cancel this handshake.
- #64671 — Windows
UtilityProcessspawn timeout (5 s, OS-level), a different stage.
What is specific here: Claude Desktop, the initialize stage, and a server that has not started yet because its package manager is still installing it.
Steps to reproduce
- Configure a
stdioMCP server launched viauvxwith a package whose dependency tree is large and unpinned (any package depending onboto3works). - Run
uv cache cleanto simulate the state after an upstream dependency release. - Start Claude Desktop.
- Observe
Downloading …in the server log, thennotifications/cancelledat exactly +60 s, and the server's tools missing from the session.
Expected behaviour
Any one of these would resolve it:
- A configurable initialization timeout — honour a
timeout(orinitTimeout) field per server inclaude_desktop_config.json, or anMCP_TIMEOUTenv var, for theinitializephase. - Treat stderr activity as liveness — the child process is demonstrably alive and writing
Downloading botocore (14.8MiB)to stderr throughout. Resetting the deadline on output would fix the common package-runner case with no config. - Retry / late attach — if a server completes
initializeafter cancellation, register its tools rather than discarding them. The install finishes ~50 s later and the server sits there fully functional but unreachable. - At minimum, surface the cause in the UI. The server currently shows as failed with no hint that a download was cut short; a user reasonably concludes their backend is down and investigates in the wrong place.
Current workaround
Pin the package version so resolution stops picking up new transitive releases, and pre-warm the cache manually before starting the app. Both require knowing about the 60 s deadline in the first place, which is only discoverable by reading the logs closely enough to notice the timestamps are exactly 60.000 s apart.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗