Skip to content

Stateless HTTP mode reuses one MCP server across requests -> "Already connected to a transport" (breaks multi-request clients) #117

Description

@Defilan

Summary

In HTTP mode (src/http.ts / dist/http.js), createHttpApp creates a single McpServer at construction time and calls mcpServer.connect(transport) on every /mcp request:

const mcpServer = createPerplexityServer();          // one shared server
app.all("/mcp", async (req, res) => {
  const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined, ... });
  await mcpServer.connect(transport);                // 2nd concurrent connect throws
  ...
});

Because the streamable-HTTP transport is stateless (sessionIdGenerator: undefined), there is no session to reuse. Once one request's transport is connected, any request that arrives before it closes calls connect() on the already-connected server and throws:

Error: Already connected to a transport. Call close() before connecting to a new transport, or use a separate Protocol instance per connection.

and the handler returns HTTP 500.

Impact

This breaks real MCP clients over HTTP. A standards-compliant client sends initialize, then tools/list (and typically holds a stream open), so its second request 500s and no tools ever register. A strictly-sequential caller happens to dodge it, because res.on("close") closes the transport and frees the shared server between requests — which is why a single one-shot curl "works" while an actual client does not.

Reproduce

Run the HTTP server and point any real MCP client (or two overlapping requests) at it:

PERPLEXITY_API_KEY=... npm run start:http

initialize succeeds; the follow-up request returns 500 and the server logs:

ERROR: Error handling MCP request {"error":"Error: Already connected to a transport. ..."}

Fix

Create the McpServer (and transport) per request — the SDK's documented stateless pattern — and close it on response close. PR attached.

Environment

  • @perplexity-ai/mcp-server 0.9.0, streamable-HTTP transport (start:http), stateless mode.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions