-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Description
Description
There is a stability issue in the StdioServerTransport implementation of the TypeScript SDK. If an MCP client sends a request but abruptly closes the stdio pipes (stdin/stdout) before the server can write the response, the Node.js process throws an unhandled EPIPE exception and fatally crashes.
Because stdout.write() is not wrapped in a try/catch or lacking an 'error' event listener on the stream, standard client-side timeouts or abrupt disconnects lead to a complete server crash rather than a graceful shutdown. This acts as a Denial of Service (DoS) for local AI agents relying on the server.
Steps to Reproduce
Here is a minimal Python Proof of Concept (PoC) that reproduces the crash by initiating a valid handshake and instantly closing the pipe:
import subprocess
import time
import json
# 1. Start any MCP server using the TS SDK (e.g., server-everything)
process = subprocess.Popen(
["npx", "-y", "@modelcontextprotocol/server-everything"],
stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True
)
# 2. Send a valid JSON-RPC initialization request
req = {
"jsonrpc": "2.0", "id": 1, "method": "initialize",
"params": {
"protocolVersion": "2024-11-05",
"capabilities": {},
"clientInfo": {"name": "poc", "version": "1.0"}
}
}
process.stdin.write(json.dumps(req) + "\n")
process.stdin.flush()
# 3. Instantly close the pipes before Node can reply
process.stdin.close()
process.stdout.close()
# 4. Read the stderr crash log
time.sleep(1)
print(process.stderr.read())Actual Behavior (Stack Trace)
node:events:486
throw er; // Unhandled 'error' event
^
Error: EPIPE: broken pipe, write
at Socket._write (node:internal/net:75:18)
at writeOrBuffer (node:internal/streams/writable:570:12)
at _write (node:internal/streams/writable:499:10)
at Writable.write (node:internal/streams/writable:508:10)
at file:///.../node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js:66:30
at new Promise (<anonymous>)
at StdioServerTransport.send (file:///.../node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js:64:16)
Expected Behavior
The transport layer should catch the EPIPE error and handle it gracefully (e.g., emitting a close event and shutting down the session cleanly) rather than bubbling up as an unhandled exception that kills the host process.