Skip to content

bug(server): connect() silently overwrites transport, breaking concurrent HTTP sessions #1405

@josh-fisher

Description

@josh-fisher

Describe the bug
When using StreamableHTTPServerTransport with multiple concurrent sessions, calling Server.connect(transport) for a second transport silently breaks the first transport's ability to receive responses. This is because connect() overwrites this._transport without any warning or error.

Related: #1400 describes a similar issue with reconnection ("Server already initialized"). Both stem from the same root cause: Server only supports one transport at a time. This issue documents a different failure mode—silent corruption of existing connections rather than an explicit error.

To Reproduce

  1. Create a single Server instance
  2. Create StreamableHTTPServerTransport for Session A and call server.connect(transportA)
  3. Session A makes requests successfully
  4. Create StreamableHTTPServerTransport for Session B and call server.connect(transportB)
  5. Session A now fails with AbortError: This operation was aborted
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';

const server = new Server({ name: 'test', version: '1.0.0' }, { capabilities: { tools: {} } });

// Session A connects
const transportA = new StreamableHTTPServerTransport({ sessionIdGenerator: () => 'session-a' });
await server.connect(transportA);  // Works

// Session B connects
const transportB = new StreamableHTTPServerTransport({ sessionIdGenerator: () => 'session-b' });
await server.connect(transportB);  // Also "works" - but silently breaks transportA

// Now any request through transportA will fail

Expected behavior
Either:

  1. Server.connect() should throw an error if already connected to a transport, OR
  2. Server should support multiple concurrent transports for HTTP scenarios, OR
  3. Documentation should clearly state that each HTTP session requires its own Server instance

Logs

[MCP] POST tools/call for session A...
[MCP] SSE socket.end for session A...
[MCP] SSE req.aborted for session A...
AbortError: This operation was aborted

Additional context

  • SDK Version: 1.25.2
  • The root cause is in Protocol.connect() which simply overwrites this._transport without checking for an existing connection
  • Workaround: Create a new Server instance for each session, as shown in the SDK's sseAndStreamableHttpCompatibleServer.js example
  • This is a significant footgun because: no error is thrown at connect() time, the first session works until the second connects, and error messages don't indicate the root cause

Suggested fix (fail fast):

async connect(transport) {
    if (this._transport) {
        throw new Error('Server is already connected to a transport. Create a new Server instance for each connection, or call close() first.');
    }
    this._transport = transport;
    // ...
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Moderate issues affecting some users, edge cases, potentially valuable featurebugSomething isn't workingready for workEnough information for someone to start working on

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions