fix(examples): return 404 for unknown session IDs, 400 for missing (#1770)
This commit is contained in:
parent
d6a02c85c0
commit
8822c96315
9 changed files with 147 additions and 60 deletions
5
.changeset/fix-session-status-codes.md
Normal file
5
.changeset/fix-session-status-codes.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
'@modelcontextprotocol/examples-server': patch
|
||||
---
|
||||
|
||||
Example servers now return HTTP 404 (not 400) when a request includes an unknown session ID, so clients can correctly detect they need to start a new session. Requests missing a session ID entirely still return 400.
|
||||
|
|
@ -364,14 +364,17 @@ async function main() {
|
|||
|
||||
await transport.handleRequest(req, res, req.body);
|
||||
return;
|
||||
} else if (sessionId) {
|
||||
res.status(404).json({
|
||||
jsonrpc: '2.0',
|
||||
error: { code: -32_001, message: 'Session not found' },
|
||||
id: null
|
||||
});
|
||||
return;
|
||||
} else {
|
||||
// Invalid request - no session ID or not initialization request
|
||||
res.status(400).json({
|
||||
jsonrpc: '2.0',
|
||||
error: {
|
||||
code: -32_000,
|
||||
message: 'Bad Request: No valid session ID provided'
|
||||
},
|
||||
error: { code: -32_000, message: 'Bad Request: Session ID required' },
|
||||
id: null
|
||||
});
|
||||
return;
|
||||
|
|
@ -399,8 +402,12 @@ 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('Session not found');
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -414,8 +421,12 @@ 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('Session not found');
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -606,14 +606,17 @@ const mcpPostHandler = async (req: Request, res: Response) => {
|
|||
|
||||
await transport.handleRequest(req, res, req.body);
|
||||
return; // Already handled
|
||||
} else if (sessionId) {
|
||||
res.status(404).json({
|
||||
jsonrpc: '2.0',
|
||||
error: { code: -32_001, message: 'Session not found' },
|
||||
id: null
|
||||
});
|
||||
return;
|
||||
} else {
|
||||
// Invalid request - no session ID or not initialization request
|
||||
res.status(400).json({
|
||||
jsonrpc: '2.0',
|
||||
error: {
|
||||
code: -32_000,
|
||||
message: 'Bad Request: No valid session ID provided'
|
||||
},
|
||||
error: { code: -32_000, message: 'Bad Request: Session ID required' },
|
||||
id: null
|
||||
});
|
||||
return;
|
||||
|
|
@ -643,8 +646,12 @@ 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('Session not found');
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -682,8 +689,12 @@ 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('Session not found');
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -110,14 +110,17 @@ app.post('/mcp', async (req: Request, res: Response) => {
|
|||
await server.connect(transport);
|
||||
await transport.handleRequest(req, res, req.body);
|
||||
return; // Already handled
|
||||
} else if (sessionId) {
|
||||
res.status(404).json({
|
||||
jsonrpc: '2.0',
|
||||
error: { code: -32_001, message: 'Session not found' },
|
||||
id: null
|
||||
});
|
||||
return;
|
||||
} else {
|
||||
// Invalid request - no session ID or not initialization request
|
||||
res.status(400).json({
|
||||
jsonrpc: '2.0',
|
||||
error: {
|
||||
code: -32_000,
|
||||
message: 'Bad Request: No valid session ID provided'
|
||||
},
|
||||
error: { code: -32_000, message: 'Bad Request: Session ID required' },
|
||||
id: null
|
||||
});
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -689,14 +689,17 @@ const mcpPostHandler = async (req: Request, res: Response) => {
|
|||
|
||||
await transport.handleRequest(req, res, req.body);
|
||||
return; // Already handled
|
||||
} else if (sessionId) {
|
||||
res.status(404).json({
|
||||
jsonrpc: '2.0',
|
||||
error: { code: -32_001, message: 'Session not found' },
|
||||
id: null
|
||||
});
|
||||
return;
|
||||
} else {
|
||||
// Invalid request - no session ID or not initialization request
|
||||
res.status(400).json({
|
||||
jsonrpc: '2.0',
|
||||
error: {
|
||||
code: -32_000,
|
||||
message: 'Bad Request: No valid session ID provided'
|
||||
},
|
||||
error: { code: -32_000, message: 'Bad Request: Session ID required' },
|
||||
id: null
|
||||
});
|
||||
return;
|
||||
|
|
@ -730,8 +733,12 @@ 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('Session not found');
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -761,8 +768,12 @@ 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('Session not found');
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -670,10 +670,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: -32_001, message: 'Session not found' },
|
||||
id: null
|
||||
});
|
||||
return;
|
||||
} else {
|
||||
res.status(400).json({
|
||||
jsonrpc: '2.0',
|
||||
error: { code: -32_000, message: 'Bad Request: No valid session ID' },
|
||||
error: { code: -32_000, message: 'Bad Request: Session ID required' },
|
||||
id: null
|
||||
});
|
||||
return;
|
||||
|
|
@ -695,8 +702,12 @@ 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('Session not found');
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -707,8 +718,12 @@ 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('Session not found');
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -86,14 +86,17 @@ app.post('/mcp', async (req: Request, res: Response) => {
|
|||
// Handle the request - the onsessioninitialized callback will store the transport
|
||||
await transport.handleRequest(req, res, req.body);
|
||||
return; // Already handled
|
||||
} else if (sessionId) {
|
||||
res.status(404).json({
|
||||
jsonrpc: '2.0',
|
||||
error: { code: -32_001, message: 'Session not found' },
|
||||
id: null
|
||||
});
|
||||
return;
|
||||
} else {
|
||||
// Invalid request - no session ID or not initialization request
|
||||
res.status(400).json({
|
||||
jsonrpc: '2.0',
|
||||
error: {
|
||||
code: -32_000,
|
||||
message: 'Bad Request: No valid session ID provided'
|
||||
},
|
||||
error: { code: -32_000, message: 'Bad Request: Session ID required' },
|
||||
id: null
|
||||
});
|
||||
return;
|
||||
|
|
@ -119,8 +122,12 @@ 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('Session not found');
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -327,13 +327,17 @@ async function startServer() {
|
|||
await mcpServer.connect(transport);
|
||||
await transport.handleRequest(req, res, req.body);
|
||||
return;
|
||||
} else if (sessionId) {
|
||||
res.status(404).json({
|
||||
jsonrpc: '2.0',
|
||||
error: { code: -32_001, message: 'Session not found' },
|
||||
id: null
|
||||
});
|
||||
return;
|
||||
} else {
|
||||
res.status(400).json({
|
||||
jsonrpc: '2.0',
|
||||
error: {
|
||||
code: -32_000,
|
||||
message: 'Invalid or missing session ID'
|
||||
},
|
||||
error: { code: -32_000, message: 'Bad Request: Session ID required' },
|
||||
id: null
|
||||
});
|
||||
return;
|
||||
|
|
@ -359,8 +363,12 @@ async function startServer() {
|
|||
app.get('/mcp', bearerAuth, 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('Session not found');
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -381,8 +389,12 @@ async function startServer() {
|
|||
app.delete('/mcp', bearerAuth, 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('Session not found');
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -929,13 +929,17 @@ app.post('/mcp', async (req: Request, res: Response) => {
|
|||
await mcpServer.connect(transport);
|
||||
await transport.handleRequest(req, res, req.body);
|
||||
return;
|
||||
} else if (sessionId) {
|
||||
res.status(404).json({
|
||||
jsonrpc: '2.0',
|
||||
error: { code: -32_001, message: 'Session not found' },
|
||||
id: null
|
||||
});
|
||||
return;
|
||||
} else {
|
||||
res.status(400).json({
|
||||
jsonrpc: '2.0',
|
||||
error: {
|
||||
code: -32_000,
|
||||
message: 'Invalid or missing session ID'
|
||||
},
|
||||
error: { code: -32_000, message: 'Bad Request: Session ID required' },
|
||||
id: null
|
||||
});
|
||||
return;
|
||||
|
|
@ -961,8 +965,12 @@ app.post('/mcp', async (req: Request, res: Response) => {
|
|||
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('Session not found');
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -988,8 +996,12 @@ app.get('/mcp', async (req: Request, res: Response) => {
|
|||
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('Session not found');
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue