The @platformatic/mcp package only generates and returns Mcp-Session-Id headers when enableSSE: true is configured. This breaks compatibility with MCP clients that use the Streamable HTTP transport without SSE, as session ID negotiation is a core requirement of the MCP Streamable HTTP specification independent of SSE streaming.
Reproduction
// Register the plugin with enableSSE: false:
await app.register(mcpPlugin, {
enableSSE: false,
serverInfo: { name: 'test-server', version: '1.0.0' },
capabilities: { tools: {}, resources: {}, prompts: {} }
})
Send an initialize request:
curl -X POST http://localhost:3000/mcp \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2024-11-05",
"capabilities": {},
"clientInfo": { "name": "test", "version": "1.0" }
}
}'
Expected: Response includes Mcp-Session-Id header per MCP Streamable HTTP spec.
Actual: No Mcp-Session-Id header is returned.
Root Cause
In src/routes/mcp.js, session creation is entirely gated behind the enableSSE flag:
// Line 108-125
if (enableSSE) {
let session;
if (sessionId) {
const existingSession = await sessionStore.get(sessionId);
if (existingSession) {
session = existingSession;
} else {
session = await createSSESession();
reply.header('Mcp-Session-Id', session.id);
}
} else {
session = await createSSESession();
reply.header('Mcp-Session-Id', session.id);
}
sessionId = session.id;
}
When enableSSE: false, the entire session lifecycle is skipped; no sessions are created, no Mcp-Session-Id headers are returned, and subsequent requests cannot include session context.
Impact
This breaks compatibility with MCP clients that implement the full Streamable HTTP transport specification, including:
- ElevenLabs MCP client (uses Python MCP SDK); throws ExceptionGroup errors when session ID is missing
- Any client using StreamableHttpTransport from the official MCP SDKs that expects session negotiation
- Clients that require session persistence without needing SSE streaming
The MCP specification treats Streamable HTTP session management and SSE streaming as separate concerns. A server should be able to support session ID negotiation without implementing SSE.
Proposed Fix
Decouple session lifecycle from SSE support. The enableSSE flag should only control the GET /mcp SSE endpoint, not the session management on POST /mcp:
- Always create sessions and return Mcp-Session-Id on initialize requests to POST /mcp
- Only enable the GET /mcp SSE stream endpoint when
enableSSE: true
- Optionally, add a separate config flag like
enableSessionManagement: true (default) for fine-grained control
Workaround
Currently requires implementing a custom route wrapper that handles session ID generation and validation before delegating to the plugin, which defeats the purpose of using a managed MCP adapter.
Environment
- @platformatic/mcp version: 1.2.2
- Node.js version: 18+
- Affected clients: ElevenLabs, Python MCP SDK StreamableHttpTransport, any client expecting MCP Streamable HTTP session negotiation
The @platformatic/mcp package only generates and returns
Mcp-Session-Idheaders whenenableSSE: trueis configured. This breaks compatibility with MCP clients that use the Streamable HTTP transport without SSE, as session ID negotiation is a core requirement of the MCP Streamable HTTP specification independent of SSE streaming.Reproduction
Expected: Response includes Mcp-Session-Id header per MCP Streamable HTTP spec.
Actual: No Mcp-Session-Id header is returned.
Root Cause
In src/routes/mcp.js, session creation is entirely gated behind the enableSSE flag:
When enableSSE: false, the entire session lifecycle is skipped; no sessions are created, no Mcp-Session-Id headers are returned, and subsequent requests cannot include session context.
Impact
This breaks compatibility with MCP clients that implement the full Streamable HTTP transport specification, including:
The MCP specification treats Streamable HTTP session management and SSE streaming as separate concerns. A server should be able to support session ID negotiation without implementing SSE.
Proposed Fix
Decouple session lifecycle from SSE support. The
enableSSEflag should only control the GET /mcp SSE endpoint, not the session management on POST /mcp:enableSSE: trueenableSessionManagement: true(default) for fine-grained controlWorkaround
Currently requires implementing a custom route wrapper that handles session ID generation and validation before delegating to the plugin, which defeats the purpose of using a managed MCP adapter.
Environment