Description
Describe the bug
https://github.com/modelcontextprotocol/typescript-sdk/blob/main/src/server/streamableHttp.ts#L373-L389
private validateSession(req: IncomingMessage, res: ServerResponse): boolean {
if (!this._initialized) {
// If the server has not been initialized yet, reject all requests
res.writeHead(400).end(JSON.stringify({
jsonrpc: "2.0",
error: {
code: -32000,
message: "Bad Request: Server not initialized"
},
id: null
}));
return false;
}
if (this.sessionId === undefined) {
// If the session ID is not set, the session management is disabled
// and we don't need to validate the session ID
return true;
}
can never succeed in stateless mode because the server cannot re-use an existing transport when there is no session-id. Therefore this._initialized
is always false and validateSession
always fails.
Note that this.sessionId is also not set in such a case.
In a scenario where the MCP server is a Kubernetes deployment, it is also possible a request reaches another pod which does not have the transport in its cache.
To Reproduce
Create a streamableHttp server with sessionId disabled for example:
app.post('/mcp', async (req: Request, res: Response) => {
console.log('Received MCP request:', req.body);
try {
let transport: StreamableHTTPServerTransport;
if (isInitializeRequest(req.body)) {
// New initialization request - use JSON response mode
transport = new StreamableHTTPServerTransport({
sessionIdGenerator: () => undefined,
enableJsonResponse: true,
});
} else {
transport = new StreamableHTTPServerTransport({
sessionIdGenerator: () => undefined
});
}
// Handle the request with the transport
await server.connect(transport);
await transport.handleRequest(req, res, req.body);
} catch (error) {
console.error('Error handling MCP request:', error);
if (!res.headersSent) {
res.status(500).json({
jsonrpc: '2.0',
error: {
code: -32603,
message: 'Internal server error',
},
id: null,
});
}
}
});
and try to connect with a client
Expected behavior
client should be able to send the intialized message after initialisation even if there is no session-id to track sessions. i.E. stateless mode.
Logs
Error: Error POSTing to endpoint (HTTP 400): {"jsonrpc":"2.0","error":{"code":-32000,"message":"Bad Request: Server not initialized"},"id":null}
at StreamableHTTPClientTransport.send (file:///xxx/@modelcontextprotocol/sdk/dist/esm/client/streamableHttp.js:172:23)
One solution is likely to move the if (this.sessionId === undefined) {
block to the top of the function