From 51707c419222d11821aeed8eca07994804d6c060 Mon Sep 17 00:00:00 2001 From: lraveri Date: Mon, 22 Dec 2025 19:09:26 +0100 Subject: [PATCH] fix: return 404 for invalid MCP session IDs in examples --- examples/server/src/elicitationFormExample.ts | 38 +++++++++++++++---- examples/server/src/elicitationUrlExample.ts | 38 +++++++++++++++---- .../server/src/jsonResponseStreamableHttp.ts | 20 ++++++++-- examples/server/src/simpleStreamableHttp.ts | 38 +++++++++++++++---- examples/server/src/simpleTaskInteractive.ts | 27 ++++++++++--- .../sseAndStreamableHttpCompatibleServer.ts | 16 ++++++-- .../src/standaloneSseWithGetStreamableHttp.ts | 29 +++++++++++--- 7 files changed, 164 insertions(+), 42 deletions(-) diff --git a/examples/server/src/elicitationFormExample.ts b/examples/server/src/elicitationFormExample.ts index f8863c17b..1f1c0cc91 100644 --- a/examples/server/src/elicitationFormExample.ts +++ b/examples/server/src/elicitationFormExample.ts @@ -332,9 +332,21 @@ async function main() { try { let transport: StreamableHTTPServerTransport; - if (sessionId && transports[sessionId]) { - // Reuse existing transport for this session - transport = transports[sessionId]; + if (sessionId) { + if (transports[sessionId]) { + // Reuse existing transport for this session + transport = transports[sessionId]; + } else { + res.status(404).json({ + jsonrpc: '2.0', + error: { + code: -32000, + message: 'Not Found: Invalid session ID' + }, + id: null + }); + return; + } } else if (!sessionId && isInitializeRequest(req.body)) { // New initialization request - create new transport transport = new StreamableHTTPServerTransport({ @@ -366,7 +378,7 @@ async function main() { jsonrpc: '2.0', error: { code: -32000, - message: 'Bad Request: No valid session ID provided' + message: 'Bad Request: No session ID provided' }, id: null }); @@ -395,8 +407,13 @@ async function main() { // Handle GET requests for SSE streams const mcpGetHandler = async (req: Request, res: Response) => { const sessionId = req.headers['mcp-session-id'] as string | undefined; - if (!sessionId || !transports[sessionId]) { - res.status(400).send('Invalid or missing session ID'); + if (!sessionId) { + res.status(400).send('Missing session ID'); + return; + } + + if (!transports[sessionId]) { + res.status(404).send('Invalid session ID'); return; } @@ -410,8 +427,13 @@ async function main() { // Handle DELETE requests for session termination const mcpDeleteHandler = async (req: Request, res: Response) => { const sessionId = req.headers['mcp-session-id'] as string | undefined; - if (!sessionId || !transports[sessionId]) { - res.status(400).send('Invalid or missing session ID'); + if (!sessionId) { + res.status(400).send('Missing session ID'); + return; + } + + if (!transports[sessionId]) { + res.status(404).send('Invalid session ID'); return; } diff --git a/examples/server/src/elicitationUrlExample.ts b/examples/server/src/elicitationUrlExample.ts index 99f85d079..16934ab31 100644 --- a/examples/server/src/elicitationUrlExample.ts +++ b/examples/server/src/elicitationUrlExample.ts @@ -614,9 +614,21 @@ const mcpPostHandler = async (req: Request, res: Response) => { try { let transport: StreamableHTTPServerTransport; - if (sessionId && transports[sessionId]) { - // Reuse existing transport - transport = transports[sessionId]; + if (sessionId) { + if (transports[sessionId]) { + // Reuse existing transport + transport = transports[sessionId]; + } else { + res.status(404).json({ + jsonrpc: '2.0', + error: { + code: -32000, + message: 'Not Found: Invalid session ID' + }, + id: null + }); + return; + } } else if (!sessionId && isInitializeRequest(req.body)) { const server = getServer(); // New initialization request @@ -658,7 +670,7 @@ const mcpPostHandler = async (req: Request, res: Response) => { jsonrpc: '2.0', error: { code: -32000, - message: 'Bad Request: No valid session ID provided' + message: 'Bad Request: No session ID provided' }, id: null }); @@ -689,8 +701,13 @@ app.post('/mcp', authMiddleware, mcpPostHandler); // Handle GET requests for SSE streams (using built-in support from StreamableHTTP) const mcpGetHandler = async (req: Request, res: Response) => { const sessionId = req.headers['mcp-session-id'] as string | undefined; - if (!sessionId || !transports[sessionId]) { - res.status(400).send('Invalid or missing session ID'); + if (!sessionId) { + res.status(400).send('Missing session ID'); + return; + } + + if (!transports[sessionId]) { + res.status(404).send('Invalid session ID'); return; } @@ -728,8 +745,13 @@ app.get('/mcp', authMiddleware, mcpGetHandler); // Handle DELETE requests for session termination (according to MCP spec) const mcpDeleteHandler = async (req: Request, res: Response) => { const sessionId = req.headers['mcp-session-id'] as string | undefined; - if (!sessionId || !transports[sessionId]) { - res.status(400).send('Invalid or missing session ID'); + if (!sessionId) { + res.status(400).send('Missing session ID'); + return; + } + + if (!transports[sessionId]) { + res.status(404).send('Invalid session ID'); return; } diff --git a/examples/server/src/jsonResponseStreamableHttp.ts b/examples/server/src/jsonResponseStreamableHttp.ts index 2199ebfbe..870f6b5d8 100644 --- a/examples/server/src/jsonResponseStreamableHttp.ts +++ b/examples/server/src/jsonResponseStreamableHttp.ts @@ -105,9 +105,21 @@ app.post('/mcp', async (req: Request, res: Response) => { const sessionId = req.headers['mcp-session-id'] as string | undefined; let transport: StreamableHTTPServerTransport; - if (sessionId && transports[sessionId]) { - // Reuse existing transport - transport = transports[sessionId]; + if (sessionId) { + if (transports[sessionId]) { + // Reuse existing transport + transport = transports[sessionId]; + } else { + res.status(404).json({ + jsonrpc: '2.0', + error: { + code: -32000, + message: 'Not Found: Invalid session ID' + }, + id: null + }); + return; + } } else if (!sessionId && isInitializeRequest(req.body)) { // New initialization request - use JSON response mode transport = new StreamableHTTPServerTransport({ @@ -132,7 +144,7 @@ app.post('/mcp', async (req: Request, res: Response) => { jsonrpc: '2.0', error: { code: -32000, - message: 'Bad Request: No valid session ID provided' + message: 'Bad Request: No session ID provided' }, id: null }); diff --git a/examples/server/src/simpleStreamableHttp.ts b/examples/server/src/simpleStreamableHttp.ts index 7613e3786..7b9bd1f95 100644 --- a/examples/server/src/simpleStreamableHttp.ts +++ b/examples/server/src/simpleStreamableHttp.ts @@ -606,9 +606,21 @@ const mcpPostHandler = async (req: Request, res: Response) => { } try { let transport: StreamableHTTPServerTransport; - if (sessionId && transports[sessionId]) { - // Reuse existing transport - transport = transports[sessionId]; + if (sessionId) { + if (transports[sessionId]) { + // Reuse existing transport + transport = transports[sessionId]; + } else { + res.status(404).json({ + jsonrpc: '2.0', + error: { + code: -32000, + message: 'Not Found: Invalid session ID' + }, + id: null + }); + return; + } } else if (!sessionId && isInitializeRequest(req.body)) { // New initialization request const eventStore = new InMemoryEventStore(); @@ -645,7 +657,7 @@ const mcpPostHandler = async (req: Request, res: Response) => { jsonrpc: '2.0', error: { code: -32000, - message: 'Bad Request: No valid session ID provided' + message: 'Bad Request: No session ID provided' }, id: null }); @@ -680,8 +692,13 @@ if (useOAuth && authMiddleware) { // Handle GET requests for SSE streams (using built-in support from StreamableHTTP) const mcpGetHandler = async (req: Request, res: Response) => { const sessionId = req.headers['mcp-session-id'] as string | undefined; - if (!sessionId || !transports[sessionId]) { - res.status(400).send('Invalid or missing session ID'); + if (!sessionId) { + res.status(400).send('Missing session ID'); + return; + } + + if (!transports[sessionId]) { + res.status(404).send('Invalid session ID'); return; } @@ -711,8 +728,13 @@ if (useOAuth && authMiddleware) { // Handle DELETE requests for session termination (according to MCP spec) const mcpDeleteHandler = async (req: Request, res: Response) => { const sessionId = req.headers['mcp-session-id'] as string | undefined; - if (!sessionId || !transports[sessionId]) { - res.status(400).send('Invalid or missing session ID'); + if (!sessionId) { + res.status(400).send('Missing session ID'); + return; + } + + if (!transports[sessionId]) { + res.status(404).send('Invalid session ID'); return; } diff --git a/examples/server/src/simpleTaskInteractive.ts b/examples/server/src/simpleTaskInteractive.ts index 956c33f8e..7ecf7c0f7 100644 --- a/examples/server/src/simpleTaskInteractive.ts +++ b/examples/server/src/simpleTaskInteractive.ts @@ -679,10 +679,17 @@ app.post('/mcp', async (req: Request, res: Response) => { await server.connect(transport); await transport.handleRequest(req, res, req.body); return; + } else if (sessionId) { + res.status(404).json({ + jsonrpc: '2.0', + error: { code: -32000, message: 'Not Found: Invalid session ID' }, + id: null + }); + return; } else { res.status(400).json({ jsonrpc: '2.0', - error: { code: -32000, message: 'Bad Request: No valid session ID' }, + error: { code: -32000, message: 'Bad Request: No session ID' }, id: null }); return; @@ -704,8 +711,13 @@ app.post('/mcp', async (req: Request, res: Response) => { // Handle GET requests for SSE streams app.get('/mcp', async (req: Request, res: Response) => { const sessionId = req.headers['mcp-session-id'] as string | undefined; - if (!sessionId || !transports[sessionId]) { - res.status(400).send('Invalid or missing session ID'); + if (!sessionId) { + res.status(400).send('Missing session ID'); + return; + } + + if (!transports[sessionId]) { + res.status(404).send('Invalid session ID'); return; } @@ -716,8 +728,13 @@ app.get('/mcp', async (req: Request, res: Response) => { // Handle DELETE requests for session termination app.delete('/mcp', async (req: Request, res: Response) => { const sessionId = req.headers['mcp-session-id'] as string | undefined; - if (!sessionId || !transports[sessionId]) { - res.status(400).send('Invalid or missing session ID'); + if (!sessionId) { + res.status(400).send('Missing session ID'); + return; + } + + if (!transports[sessionId]) { + res.status(404).send('Invalid session ID'); return; } diff --git a/examples/server/src/sseAndStreamableHttpCompatibleServer.ts b/examples/server/src/sseAndStreamableHttpCompatibleServer.ts index 335802d0a..ab78364c2 100644 --- a/examples/server/src/sseAndStreamableHttpCompatibleServer.ts +++ b/examples/server/src/sseAndStreamableHttpCompatibleServer.ts @@ -96,13 +96,13 @@ app.all('/mcp', async (req: Request, res: Response) => { const sessionId = req.headers['mcp-session-id'] as string | undefined; let transport: StreamableHTTPServerTransport; - if (sessionId && transports[sessionId]) { + if (sessionId) { // Check if the transport is of the correct type const existingTransport = transports[sessionId]; if (existingTransport instanceof StreamableHTTPServerTransport) { // Reuse existing transport transport = existingTransport; - } else { + } else if (existingTransport) { // Transport exists but is not a StreamableHTTPServerTransport (could be SSEServerTransport) res.status(400).json({ jsonrpc: '2.0', @@ -113,6 +113,16 @@ app.all('/mcp', async (req: Request, res: Response) => { id: null }); return; + } else { + res.status(404).json({ + jsonrpc: '2.0', + error: { + code: -32000, + message: 'Not Found: Invalid session ID' + }, + id: null + }); + return; } } else if (!sessionId && req.method === 'POST' && isInitializeRequest(req.body)) { const eventStore = new InMemoryEventStore(); @@ -144,7 +154,7 @@ app.all('/mcp', async (req: Request, res: Response) => { jsonrpc: '2.0', error: { code: -32000, - message: 'Bad Request: No valid session ID provided' + message: 'Bad Request: No session ID provided' }, id: null }); diff --git a/examples/server/src/standaloneSseWithGetStreamableHttp.ts b/examples/server/src/standaloneSseWithGetStreamableHttp.ts index cceb24299..df384762a 100644 --- a/examples/server/src/standaloneSseWithGetStreamableHttp.ts +++ b/examples/server/src/standaloneSseWithGetStreamableHttp.ts @@ -43,9 +43,21 @@ app.post('/mcp', async (req: Request, res: Response) => { const sessionId = req.headers['mcp-session-id'] as string | undefined; let transport: StreamableHTTPServerTransport; - if (sessionId && transports[sessionId]) { - // Reuse existing transport - transport = transports[sessionId]; + if (sessionId) { + if (transports[sessionId]) { + // Reuse existing transport + transport = transports[sessionId]; + } else { + res.status(404).json({ + jsonrpc: '2.0', + error: { + code: -32000, + message: 'Not Found: Invalid session ID' + }, + id: null + }); + return; + } } else if (!sessionId && isInitializeRequest(req.body)) { // New initialization request transport = new StreamableHTTPServerTransport({ @@ -70,7 +82,7 @@ app.post('/mcp', async (req: Request, res: Response) => { jsonrpc: '2.0', error: { code: -32000, - message: 'Bad Request: No valid session ID provided' + message: 'Bad Request: No session ID provided' }, id: null }); @@ -97,8 +109,13 @@ app.post('/mcp', async (req: Request, res: Response) => { // Handle GET requests for SSE streams (now using built-in support from StreamableHTTP) app.get('/mcp', async (req: Request, res: Response) => { const sessionId = req.headers['mcp-session-id'] as string | undefined; - if (!sessionId || !transports[sessionId]) { - res.status(400).send('Invalid or missing session ID'); + if (!sessionId) { + res.status(400).send('Missing session ID'); + return; + } + + if (!transports[sessionId]) { + res.status(404).send('Invalid session ID'); return; }