Skip to content

qmd mcp --http fails on second request: "Stateless transport cannot be reused" #163

@BIG-TATHEP

Description

@BIG-TATHEP

Description

qmd mcp --http (and qmd mcp --http --daemon) crashes on the second MCP request with:

Stateless transport cannot be reused across requests. Create a new transport per request.

The first request (e.g. initialize) succeeds, but any subsequent request returns a 500 error with a Bun fallback HTML page containing the error in base64.

Steps to Reproduce

qmd mcp --http --daemon

# First request — works
curl -s -X POST http://localhost:8181/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}},"id":1}'
# → Returns valid JSON-RPC response

# Second request — fails
curl -s -X POST http://localhost:8181/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","method":"tools/list","params":{},"id":2}'
# → Returns 500 with HTML error page

Root Cause

In src/mcp.ts, startMcpHttpServer() creates a single WebStandardStreamableHTTPServerTransport instance and reuses it for all incoming requests:

const transport = new WebStandardStreamableHTTPServerTransport({
  enableJsonResponse: true,
});
await mcpServer.connect(transport);
// ...
const res = await transport.handleRequest(req, { parsedBody: body });

The MCP SDK's WebStandardStreamableHTTPServerTransport in stateless mode (no sessionIdGenerator) requires a fresh transport per request. Reusing it triggers the guard in the SDK:

if (!this.sessionIdGenerator && this._hasHandledRequest) {
  throw new Error('Stateless transport cannot be reused...');
}

Suggested Fix

Add sessionIdGenerator to enable stateful mode (sessions managed by transport):

const transport = new WebStandardStreamableHTTPServerTransport({
  enableJsonResponse: true,
  sessionIdGenerator: () => crypto.randomUUID(),
});

Or alternatively, create a new transport instance per request (true stateless mode).

Environment

  • OS: macOS 15.3 (Darwin 25.3.0, Apple Silicon)
  • Bun: 1.3.9
  • qmd: v1.0.0 (commit 96634da, 2026-02-13)
  • @modelcontextprotocol/sdk: ^1.25.1
  • Client: Claude Code / Claude Desktop

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions