Skip to content

Commit 2396a34

Browse files
QuantGeekDevclaude
andcommitted
fix: refactor SSE transport to use per-session SDK server instances
The SSE transport previously multiplexed all client connections through a single SDK Server + custom transport, causing session collisions when clients like n8n reconnect frequently. Responses were broadcast to ALL connected clients instead of being routed to the correct session. This refactor creates a separate SDK SSEServerTransport and SDK Server instance per SSE connection, matching the SDK's intended usage pattern (as shown in its own examples) and the HTTP stream transport's architecture. Key changes: - Each GET /sse creates a new SDK SSEServerTransport + SDK Server pair - POST /messages routes to the correct per-session transport - MCPServer provides a server factory via createSDKServerForSession() - Session cleanup avoids circular close between server and transport - Removed manual SSE stream management, keep-alive, and broadcast logic Fixes #90 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent a385629 commit 2396a34

4 files changed

Lines changed: 320 additions & 265 deletions

File tree

src/core/MCPServer.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,23 @@ export class MCPServer {
195195
return process.cwd();
196196
}
197197

198+
/**
199+
* Creates a new SDK Server instance configured with all registered handlers.
200+
* Used by SSE transport to create isolated per-session servers.
201+
*/
202+
private createSDKServerForSession(): Server {
203+
const serverOptions: Record<string, unknown> = { capabilities: this.capabilities };
204+
if (this._hasApps) {
205+
serverOptions.extensions = { [MCP_APP_EXTENSION_ID]: {} };
206+
}
207+
const sessionServer = new Server(
208+
{ name: this.serverName, version: this.serverVersion },
209+
serverOptions as any,
210+
);
211+
this.setupHandlers(sessionServer);
212+
return sessionServer;
213+
}
214+
198215
private createTransport(): BaseTransport {
199216
logger.debug(`Creating transport: ${this.transportConfig.type}`);
200217

@@ -977,6 +994,18 @@ export class MCPServer {
977994
this.transport = this.createTransport();
978995

979996
logger.info(`Connecting transport (${this.transport.type}) to SDK Server...`);
997+
998+
// For SSE transport, set up per-session SDK Server instances for proper
999+
// session isolation. Each SSE connection gets its own SDK Server with all
1000+
// handlers registered, connected to its own SDK SSEServerTransport.
1001+
// This matches the SDK's expected usage pattern and fixes session
1002+
// collision issues (e.g., n8n opening a new connection per execution).
1003+
if (this.transport.type === 'sse') {
1004+
const sseTransport = this.transport as SSEServerTransport;
1005+
sseTransport.setServerFactory(() => this.createSDKServerForSession());
1006+
}
1007+
1008+
// connect() calls transport.start() internally
9801009
await this.server.connect(this.transport);
9811010

9821011
logger.info(

0 commit comments

Comments
 (0)