Skip to content

fix: handle EPIPE and ERR_STREAM_DESTROYED in StdioServerTransport#1679

Open
kai-agent-free wants to merge 2 commits intomodelcontextprotocol:mainfrom
kai-agent-free:fix/stdio-epipe-handling
Open

fix: handle EPIPE and ERR_STREAM_DESTROYED in StdioServerTransport#1679
kai-agent-free wants to merge 2 commits intomodelcontextprotocol:mainfrom
kai-agent-free:fix/stdio-epipe-handling

Conversation

@kai-agent-free
Copy link

Problem

When an MCP client disconnects abruptly (closes stdin/stdout pipes), StdioServerTransport.send() throws an unhandled EPIPE error that fatally crashes the Node.js process. This is a DoS vector for any MCP server using stdio transport.

Solution

Minimal change to StdioServerTransport:

  1. Added _onstdouterror listener — registered on stdout in start(), catches EPIPE and ERR_STREAM_DESTROYED errors and calls close() gracefully instead of letting them propagate as unhandled exceptions. Other errors are forwarded to onerror.

  2. Added error handling in send() — checks stdout.writable before writing, and wraps write() in try/catch for synchronous throw protection.

  3. Cleanup in close() — removes the stdout error listener to prevent leaks.

Tests

Added 5 new tests:

  • EPIPE on stdout triggers graceful close
  • ERR_STREAM_DESTROYED on stdout triggers graceful close
  • Non-EPIPE stdout errors forwarded to onerror
  • send() rejects when stdout is not writable
  • stdout error listener removed on close

All existing tests continue to pass.

Fixes #1564

When a client disconnects abruptly, stdout.write() can emit an EPIPE
or ERR_STREAM_DESTROYED error that crashes the server process. This
adds:

- An error listener on stdout that catches EPIPE/ERR_STREAM_DESTROYED
  and triggers graceful close() instead of crashing
- try/catch in send() for synchronous write errors
- A writable check before writing
- Cleanup of the stdout error listener in close()

Fixes modelcontextprotocol#1564
@kai-agent-free kai-agent-free requested a review from a team as a code owner March 13, 2026 11:35
@changeset-bot
Copy link

changeset-bot bot commented Mar 13, 2026

🦋 Changeset detected

Latest commit: 9a96b23

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 4 packages
Name Type
@modelcontextprotocol/server Patch
@modelcontextprotocol/express Patch
@modelcontextprotocol/hono Patch
@modelcontextprotocol/node Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@pkg-pr-new
Copy link

pkg-pr-new bot commented Mar 13, 2026

Open in StackBlitz

@modelcontextprotocol/client

npm i https://pkg.pr.new/modelcontextprotocol/typescript-sdk/@modelcontextprotocol/client@1679

@modelcontextprotocol/server

npm i https://pkg.pr.new/modelcontextprotocol/typescript-sdk/@modelcontextprotocol/server@1679

@modelcontextprotocol/express

npm i https://pkg.pr.new/modelcontextprotocol/typescript-sdk/@modelcontextprotocol/express@1679

@modelcontextprotocol/hono

npm i https://pkg.pr.new/modelcontextprotocol/typescript-sdk/@modelcontextprotocol/hono@1679

@modelcontextprotocol/node

npm i https://pkg.pr.new/modelcontextprotocol/typescript-sdk/@modelcontextprotocol/node@1679

commit: 6808f97

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Unhandled 'EPIPE' in 'StdioServerTransport' causes fatal process crash on client disconnect

1 participant