Skip to content
This repository was archived by the owner on May 16, 2026. It is now read-only.

fix: emit connection error asynchronously to avoid unhandled rejection crashes#1

Open
AmSach wants to merge 1 commit into
mainfrom
fix/issue-1049-stdio-unexpected-exit-crash
Open

fix: emit connection error asynchronously to avoid unhandled rejection crashes#1
AmSach wants to merge 1 commit into
mainfrom
fix/issue-1049-stdio-unexpected-exit-crash

Conversation

@AmSach

@AmSach AmSach commented May 11, 2026

Copy link
Copy Markdown
Owner

Summary

When a spawned server exits unexpectedly in stdio mode, the method synchronously calls on all pending request promises via . If no handler has been attached to those promises (or to ), the rejection fires before the caller's try/catch is active, and Node.js v15+ treats it as an unhandled rejection that calls , killing the entire process.

This was reported in issue modelcontextprotocol#1049 where using with a server that exits immediately causes to crash the Node.js process.

Root Cause

In , calls synchronously in a block:

When the stdio child process exits unexpectedly:

  1. emits its event
  2. is called
  3. It rejects all pending request promises synchronously
  4. If the caller hasn't attached yet, Node.js fires

Fix

Added a new registration API on the class:

  1. ** Set** — stores registered error handlers
  2. **** — registers a handler, returns a cleanup function
  3. **** — emits the error **asynchronously via **, giving callers a chance to attach before the rejection fires

The defer means:

  • Caller can do and the catch will fire
  • Or caller can register to handle disconnections gracefully

API Usage

Files Changed

  • : Added Set, method, method, and call to in

Closes modelcontextprotocol#1049

…n crashes

When a spawned server exits unexpectedly in stdio mode, the Protocol
synchronously calls reject() on all pending request promises via
_responseHandlers. If no .catch() handler has been attached to those
promises (or to client.connect()), the rejection fires synchronously
before the caller's try/catch is active, and Node.js v15+ treats it as
an unhandled rejection that calls triggerUncaughtException, killing
the entire process.

The fix adds a new onConnectionError(handler) registration API on the
Protocol class. When the transport closes unexpectedly, the error is
emitted asynchronously via setImmediate(), giving callers a chance
to attach .catch() to the connect() promise before the error fires.

The onConnectionError callback receives the SdkError with code
ConnectionClosed, allowing callers to handle unexpected disconnections
gracefully without the process crashing.

Fixes: modelcontextprotocol#1049
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[MCP-SDK] stdio client crashes with "MCP error -32000: Connection closed" when spawned server exits unexpectedly

1 participant