Fix MCP connection closed error -32000
Separate process exit, executable lookup, stdout corruption, transport reset, and client teardown.
Connect OfflineCreator with OAuthTreat -32000 as a closed transport, not a root cause
“MCP error -32000: Connection closed” means the client lost the MCP transport while work was pending. It does not identify why the transport ended. A current Cline regression test reaches the error when a configured stdio command cannot spawn, and the pull request identifies the text as the MCP TypeScript SDK's raw connection-closed error rather than a Cline-specific diagnosis.
Start at the process boundary. Determine whether the executable was found, whether the child stayed alive long enough to speak MCP, and whether the close was expected client teardown. Do not rotate credentials, change prompts, or repeatedly toggle the server until the startup trace places the failure before spawn, during initialization, after a request, or during shutdown.
- Closes immediately after launch
- Run the configured command directlyPreserve its exit code and stderr. Import errors, missing modules, bad paths, and absent environment variables can all be hidden behind the same client message.
- Connects, then closes under use
- Correlate the last request with process and transport eventsRecord whether the child exited, stdout stopped, stderr blocked, or the client deliberately closed the connection.
- Closes when the client exits or disables the server
- Check the shutdown sequence firstA close can be normal teardown rather than a server startup defect.
Capture one reproducible startup trace
Copy the exact command, arguments, working directory, and non-secret environment names from the client's MCP configuration. Execute that command from the same working directory in a terminal, without piping protocol input at first. Record whether the executable is found, how quickly it exits, its numeric exit code, and the complete stderr text. Redact values of tokens and keys, but retain variable names and whether each was present.
If the process remains alive, reproduce with the smallest protocol exchange your SDK or inspector supports and timestamp the sequence: spawn, first stdout line, first stderr line, first request, last response, close callback, and child exit. The official TypeScript stdio transport exposes the spawned process ID and can expose stderr as a stream before startup, specifically so early diagnostics are not lost.
- Minimum launch record
- command, args, cwd, environment names, exit codeCompare these fields with the client configuration rather than with an interactive shell that may have a different PATH or environment.
- Minimum transport record
- first/last protocol line, close event, process exitThis separates failure to launch from a process that launched and later lost its stream.
- Model Context Protocol TypeScript SDK: StdioClientTransport API, MCP TypeScript SDK v2
- FlightClaw on GitHub: fix: cap mcp below 2.0 so the MCP server can start
- Hindsight on GitHub: fix(claude-code): pin mcp<2 so the MCP server can import FastMCP
- Genie on GitHub: fix(plugin): anchor Claude Code MCP launcher via CLAUDE_PLUGIN_ROOT
Keep stdout protocol-only and inspect stderr
For stdio MCP, the client writes newline-delimited JSON-RPC to the server's stdin and reads newline-delimited JSON-RPC from stdout. The current specification permits UTF-8 logging on stderr but forbids non-MCP output on stdout. A banner, debug print, dependency warning, or shell profile message on stdout can therefore corrupt the wire even when the server process itself remains healthy.
Temporarily remove or redirect every ordinary stdout write, including writes from startup wrappers and dependencies. Send diagnostics to stderr and make sure the client actually captures or inherits it. Do not treat every stderr line as fatal: the specification allows informational and debug logging there. The useful evidence is the last stderr message paired with the close time and exit code.
- Valid stdout
- One MCP JSON-RPC message per lineNo banners, progress text, pretty-printed multiline JSON, or debug output belongs on this channel.
- Diagnostic channel
- stderrCapture it from process start so an early import or launcher failure is visible.
Test executable, path, environment, and dependency hypotheses separately
A merged Genie fix reproduced -32000 when a relative launcher path resolved against the user's project instead of the plugin root; the spawn log exposed MODULE_NOT_FOUND. A current AltimateAI pull request reports a different launch failure: an IDE configuration required ELECTRON_RUN_AS_NODE, but a copied MCP entry dropped its environment block, launched the editor instead of Node, and closed the server transport. A July 2026 Cherry Studio issue reports the same wrapper when a built-in stdio installer package returned npm registry 404 on direct launch.
Dependency failures can look identical. Two July 2026 pull requests report fresh Python environments resolving MCP 2.0 and then exiting on imports expected by their server or FastMCP integration. In each case, direct execution exposed the import error that the client reduced to connection closed. These are project-specific reports, not a universal instruction to downgrade MCP. Compare the failing environment's lockfile and import trace with that project's supported versions before changing dependencies.
- Executable lookup
- Resolve the same binary the client resolvesAn absolute path or direct package invocation test can distinguish a missing PATH entry, a registry 404, or a server code failure.
- Working directory
- Resolve every relative script and config pathReproduce from the client's cwd; success from the repository root alone is not enough.
- Environment
- Compare required variable names and launch semanticsDo not print secret values. Confirm only presence, source, and whether the client forwards them.
- Dependencies
- Read the first import or module errorUse the owning project's declared compatibility range rather than applying another repository's pin blindly.
- FlightClaw on GitHub: fix: cap mcp below 2.0 so the MCP server can start
- Hindsight on GitHub: fix(claude-code): pin mcp<2 so the MCP server can import FastMCP
- Genie on GitHub: fix(plugin): anchor Claude Code MCP launcher via CLAUDE_PLUGIN_ROOT
- AltimateAI on GitHub: fix: carry the IDE entry's env when wiring the datamate stdio MCP server
- Cherry Studio on GitHub: [Bug]: mcp-auto-install cannot start - @cherry/mcp-auto-install npm package returns 404
Separate transport reset from deliberate client teardown
The current stdio binding defines shutdown through the underlying streams. A client should close the child's input, wait, and then force termination only if the process does not exit; a server should exit promptly on stdin EOF and may close its output and exit. The same visible close can therefore follow a user disabling a server, a client restart, an initialization failure, or an unexpected child exit.
Check the client's close callback and the child process exit event together. If the client initiated closure, investigate the preceding client decision or timeout. If the child exited first, return to its stderr and exit code. If neither side recorded an exit but communication stalls, inspect stream handling. One unmerged OpenCode pull request reports a Windows-specific reproduction in which piped stderr was not drained and the child blocked; treat that as an implementation anecdote to test only when logs are piped and the symptom appears under chatty startup or concurrent spawning. An August 2026 ClawMem issue initially framed after-first-call -32000 as a one-shot keep-alive bug; the maintainer could not reproduce a one-shot server and redirected diagnosis to host-side child death evidence such as SIGTERM lines, OOM score, and kernel kill logs.
- Client closed first
- Inspect disable, restart, timeout, and teardown pathsDo not diagnose a normal lifecycle close as a failed executable.
- Child exited first
- Use stderr and exit code as the causal traceA fresh restart may restore service, but it does not explain a repeatable startup exit. After-first-call closes still need a child-exit or host-kill record.
- Neither side exits
- Inspect pipe consumption and blocked writesTest the hypothesis under the same operating system and log volume; do not generalize an open pull request into an SDK-wide fact.
Choose the next guide from the first confirmed boundary
Return to the MCP troubleshooting directory when the trace points to a different HTTP, OAuth, scope, credit, or generation boundary. Use the JSON-RPC parse-error guide when the server stays running but stdout contains invalid protocol data. Use the missing-tools guide only after connection and discovery succeed; a tool registry problem is downstream of a process that cannot stay connected.
Editorial ownership boundary
This page owns only MCP error -32000 as a startup, stdio, transport-reset, or teardown symptom. It does not own JSON-RPC parse errors, authorization failures, missing tools after successful discovery, or product-generation failures. Consolidate it into the MCP troubleshooting directory if current reproducible startup and transport traces can no longer support a distinct decision path.