MCP stdio server intermittently reports CONNECTION_CLOSED on session start, then works fine seconds later

Status Open
Reported on v2.1.247
Maintainer reply None cached
Activity 0 comments · opened Aug 30, 2026

Summary

A locally-configured stdio MCP server (a Python script registered in mcpServers in ~/.claude.json, surfaced internally as plugin:<name>:<name>) intermittently reports CONNECTION_CLOSED / MCP error -32000: Connection closed at session start, even though the underlying server process is healthy and works correctly when a tool call is retried a few seconds later. After a failure, subsequent session starts within a ~15 minute window skip reconnecting entirely and report the same cached failure ("Skipping connection (recent failure cached retries automatically in 15 min, or edit the plugin config to retry now)"), which makes one transient hiccup look like a much longer, repeated outage.

Environment

  • macOS (Apple Silicon)
  • Claude Code CLI, version reporting as 2.1.247
  • MCP server: a local Python 3.11 script (command: "python3.11", single args entry pointing at the script), registered under mcpServers in ~/.claude.json and also in the desktop app's claude_desktop_config.json (identical registration in both)

What I observed

  • Grepping local session transcripts (~/.claude/projects/-Users-gbd/*.jsonl) for CONNECTION_CLOSED found the failure recorded in at least 15 separate sessions spanning 3 different days (28–30 Aug), not tied to any particular time of day or to a code/config change (the server script had not been modified in weeks).
  • The failure is reported against the internal name plugin:apple-mail-calendar:apple-mail-calendar — i.e. the harness surfaces a simple user-registered mcpServers entry as a "plugin" internally.
  • In several sessions the error was the generic "errorCode":"CONNECTION_CLOSED","error":"Connection closed"; in others it was "errorCode":"-32000","error":"MCP error -32000: Connection closed".
  • In several other sessions, no connection attempt appears to have been made at all — instead: "error":"Skipping connection (recent failure cached retries automatically in 15 min, or edit the plugin config to retry now)". This confirms a negative-result cache exists and is keyed broadly enough that it suppresses reconnection attempts across separate session starts for ~15 minutes after one failure.
  • Investigating the server itself turned up nothing wrong:
  • python3.11 -m py_compile on the script succeeds.
  • Importing the module directly (python3.11 -c "import ...") succeeds in ~0.15–0.25s single-process, ~0.44s under 6-way concurrent load — nowhere near slow enough to obviously explain a hard connection timeout.
  • No entries in ~/Library/Logs/DiagnosticReports/ for the Python process around any failure timestamp.
  • log show (macOS unified log) for process == "Python" around a failure timestamp returns no entries at all.
  • The process that the harness actually spawned for the session in question was alive and responding correctly seconds later when a tool call was made against it directly.
  • No TCC/permission denial found.
  • I could not find any client-side log capturing the specific handshake attempt/failure for a CLI (claude) session — the desktop app's own ~/Library/Logs/Claude/mcp-server-<name>.log only captures the desktop app's own MCP client connections (e.g. Cowork), not each separate headless/CLI claude process's MCP client, so there's no first-party log trail to inspect for the actual failed handshake.

Impact

Low in practice, since the connection reliably self-heals as soon as any tool from the server is actually invoked — but it makes an agent session (especially an unattended scheduled task) believe a whole class of tools is unavailable for the entire session when it isn't, unless it happens to retry. It also produces a misleading "the server is down" signal to the end user that doesn't reflect reality.

Request

  • Any visibility into why the initial connection to a locally-spawned Python stdio MCP server occasionally reports CONNECTION_CLOSED on the very first attempt, when the same command reliably succeeds moments later.
  • Ideally: a single automatic retry of the initial handshake before marking a server as failed for the session, given the failure appears to be transient rather than a real unavailability.
  • A way to inspect the actual spawn/handshake failure for a CLI session (equivalent to the desktop app's per-server mcp-server-<name>.log), so a genuine one-off failure vs. a real persistent breakage can be told apart without guesswork.

Happy to provide the raw transcript excerpts if useful (redacted of unrelated project content).

View original on GitHub ↗