Skip to content

[BUG] Claude Desktop: hardcoded 60s initialize timeout drops stdio MCP servers whose package-runner cold start exceeds it #84136

Open

Description

@MelnikovTimofey

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 × stdio MCP servers, identical launcher: uvx --with 'mcp[cli]<2' opensearch-mcp-server-py
  • uv 0.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

  1. The MCP server package declares boto3>=1.39.0 — an open upper bound.
  2. botocore releases daily (24 releases in July 2026 alone).
  3. uvx resolves to the newest match on each launch; a new botocore invalidates the cached environment and triggers a fresh 14.8 MB download (occasionally numpy/scipy/scikit-learn too, ~50 MB total, 68 packages).
  4. Cold install takes ~110 s > 60 s deadline → notifications/cancelled.
  5. 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

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

  1. Configure a stdio MCP server launched via uvx with a package whose dependency tree is large and unpinned (any package depending on boto3 works).
  2. Run uv cache clean to simulate the state after an upstream dependency release.
  3. Start Claude Desktop.
  4. Observe Downloading … in the server log, then notifications/cancelled at exactly +60 s, and the server's tools missing from the session.

Expected behaviour

Any one of these would resolve it:

  1. A configurable initialization timeout — honour a timeout (or initTimeout) field per server in claude_desktop_config.json, or an MCP_TIMEOUT env var, for the initialize phase.
  2. 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.
  3. Retry / late attach — if a server completes initialize after cancellation, register its tools rather than discarding them. The install finishes ~50 s later and the server sits there fully functional but unreachable.
  4. 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.

Activity

  1. qasimsethi1-svg commented on Aug 14, 2026

    @qasimsethi1-svg

    Data point connecting this to #16837: the same 60 s initialize deadline exists on the Claude Code CLI / local-agent path too, not just Claude Desktop — so a fix scoped to the desktop config file alone would leave the other half of the problem standing.

    On Windows (Claude Code 2.1.220, stdio server with env.MCP_TIMEOUT = "180000" set in ~/.claude/settings.json), the per-session MCP log shows the raised value being read as the connection budget while the initialize request is still killed at ~60 s:

    {"debug":"Starting connection with timeout of 180000ms",...}
    {"debug":"Connection failed after 60040ms (-32001): MCP error -32001: Request timed out",...}
    

    Full details in #16837 (comment) (cold start ~80 s from AV-scanned node_modules; the same server connects in 12.7 s warm).

    Two takeaways for this issue:

    1. The "Why existing issues don't cover this" section lists [BUG] Claude code does not obey values of MCP_TIMEOUT longer than 60 seconds #16837 under tool-call timeouts, but its original repro (sleep infinity, Connection failed after 60031ms) and the log above are both failures of the connect/initialize stage — same deadline as here, different launcher. The issues are the same underlying cap on two surfaces.
    2. It strengthens ask 1 (configurable init timeout): MCP_TIMEOUT already appears to govern this phase — the debug line prints the configured value as the connection budget — but the value never reaches the initialize request's own timer. So today the env var over-promises on both CLI and Desktop.

    The AV-cold-start case here is also a second everyday trigger besides package-runner downloads: real-time-scanned node_modules (~12k files) pushes the first spawn past 60 s daily on managed corporate machines, and — like the uvx download — there's no progress notification to lean on for most of that window.

  2. alterbusinessmethod-afk commented on Aug 24, 2026

    @alterbusinessmethod-afk

    Independent confirmation of this from a different trigger: boot-time resource contention, not just package-runner cold-download time.

    Environment: Windows 365 Cloud PC, 4 vCPU, Claude Desktop (MSIX). Two stdio MCP servers measured: a Docker MCP gateway and a large Python-based server.

    Data — same server, cold (first ~60-90s post-logon) vs warm (steady state), several runs:

    Condition initialize response time
    Cold (post-boot contention) 65–159 s
    Warm (same config, machine settled) 3–15 s

    The failure signature matches the one already documented in this issue exactly: the renderer sends notifications/cancelled at ~63s (fixed 60s deadline + a few seconds of transport overhead) and marks the server failed — not a network error, a clock. On a small cloud VM, the boot minute is enough contention on its own (CPU, disk, and process-table pressure from every other autostart item and MCP server initializing simultaneously) to blow a 60s budget that the same exact process clears in single digits of seconds once the machine settles. This is a different root cause than the "upstream dependency bumped, cold install exceeds 60s" case above, but the same defect: there is no way to raise the initialize deadline for Desktop's stdio servers, so any source of one-time-slow startup (dependency refresh, or simply the machine being busy for the first minute after logon) permanently drops the server for the session with no retry.

    On the "why can't the server just send progress" question: it's worth noting the client side of that mechanism isn't actually wired up to help even in principle. resetTimeoutOnProgress in the reference TypeScript SDK still defaults to false on main today (two PRs proposing to flip the default — modelcontextprotocol/typescript-sdk#849 and modelcontextprotocol/typescript-sdk#1393 — were both closed without merging; the tracking issue, modelcontextprotocol/typescript-sdk#192, is still open). So even a server that does emit initialize-phase progress notifications is relying on the client opting in to honor them, which neither the SDK default nor (going by the fixed ~63s cutoff observed here) Claude Desktop's client currently does.

    Given #43791 was closed as a duplicate of #16837 (the CLI-side MCP_TIMEOUT-not-honored issue) and #16837's own thread has a Windows repro showing the raised timeout value being read for the connection budget but the initialize request still cut at exactly 60040ms — this looks like the same underlying fixed-60s ceiling on both the CLI and Desktop paths, just surfaced two different ways (env var ignored vs. no config knob at all). A per-server initialize-timeout override for Desktop (config-file field, same shape as the existing per-server tool-call timeout in .mcp.json per #76283) would fix both the dependency-cold-start case above and the boot-contention case here — neither is a network failure that should be treated as fatal-and-final.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions