Skip to content

Commit e750b28

Browse files
author
Charlie Tonneslan
committed
fix: prevent stack overflow on concurrent transport close
When multiple MCP transport sessions close simultaneously (server restart, network partition, mass disconnect), the onclose callbacks can trigger recursive close operations that overflow the call stack. The process stays alive but becomes completely unresponsive. Added a _closing guard flag that prevents re-entrant close() calls. Once close() is entered, subsequent calls return immediately. Fixes #1699
1 parent ccb78f2 commit e750b28

2 files changed

Lines changed: 14 additions & 0 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@modelcontextprotocol/server": patch
3+
---
4+
5+
Prevent stack overflow when multiple transports close simultaneously by guarding against re-entrant close() calls

packages/server/src/server/streamableHttp.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,7 @@ export class WebStandardStreamableHTTPServerTransport implements Transport {
238238
private _allowedOrigins?: string[];
239239
private _enableDnsRebindingProtection: boolean;
240240
private _retryInterval?: number;
241+
private _closing: boolean = false;
241242
private _supportedProtocolVersions: string[];
242243

243244
sessionId?: string;
@@ -887,6 +888,14 @@ export class WebStandardStreamableHTTPServerTransport implements Transport {
887888
}
888889

889890
async close(): Promise<void> {
891+
// Guard against re-entrant close to prevent recursive stack overflow
892+
// when multiple transports close simultaneously and onclose triggers
893+
// additional close operations.
894+
if (this._closing) {
895+
return;
896+
}
897+
this._closing = true;
898+
890899
// Close all SSE connections
891900
for (const { cleanup } of this._streamMapping.values()) {
892901
cleanup();

0 commit comments

Comments
 (0)