From cf1d5784338206da629bef3950d650099581628c Mon Sep 17 00:00:00 2001 From: Koichi ITO Date: Tue, 17 Mar 2026 01:13:48 +0900 Subject: [PATCH] Return 404 for invalid session ID in `handle_regular_request` ## Motivation and Context The MCP specification requires that when a server receives a request containing a session ID that is no longer valid, it MUST respond with HTTP 404 Not Found. The `handle_get` path already returned 404 correctly, but `handle_regular_request` (the POST path) was returning 400 "Invalid session ID" instead. Ref: https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#session-management > The server MAY terminate the session at any time, after which it MUST respond > to requests containing that session ID with HTTP 404 Not Found. ## How Has This Been Tested? Added a test for POST requests with an invalid session ID, verifying that the response is 404 with "Session not found" error message. All existing tests pass. ## Breaking Change POST requests with an invalid session ID now return HTTP 404 "Session not found" instead of HTTP 400 "Invalid session ID". Clients that match on the 400 status code or the old error message will need to be updated. However, this change is considered a bug fix because it brings the behavior into compliance with the MCP specification. --- .../transports/streamable_http_transport.rb | 2 +- .../streamable_http_transport_test.rb | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/lib/mcp/server/transports/streamable_http_transport.rb b/lib/mcp/server/transports/streamable_http_transport.rb index 2d921bf..ca640c6 100644 --- a/lib/mcp/server/transports/streamable_http_transport.rb +++ b/lib/mcp/server/transports/streamable_http_transport.rb @@ -261,7 +261,7 @@ def handle_regular_request(body_string, session_id) unless @stateless # If session ID is provided, but not in the sessions hash, return an error if session_id && !@sessions.key?(session_id) - return [400, { "Content-Type" => "application/json" }, [{ error: "Invalid session ID" }.to_json]] + return session_not_found_response end end diff --git a/test/mcp/server/transports/streamable_http_transport_test.rb b/test/mcp/server/transports/streamable_http_transport_test.rb index 7066e4d..1f6310b 100644 --- a/test/mcp/server/transports/streamable_http_transport_test.rb +++ b/test/mcp/server/transports/streamable_http_transport_test.rb @@ -287,6 +287,25 @@ class StreamableHTTPTransportTest < ActiveSupport::TestCase assert_equal "Session not found", body["error"] end + test "handles POST request with invalid session ID" do + request = create_rack_request( + "POST", + "/", + { + "CONTENT_TYPE" => "application/json", + "HTTP_MCP_SESSION_ID" => "invalid_id", + }, + { jsonrpc: "2.0", method: "ping", id: "456" }.to_json, + ) + + response = @transport.handle_request(request) + assert_equal 404, response[0] + assert_equal({ "Content-Type" => "application/json" }, response[1]) + + body = JSON.parse(response[2][0]) + assert_equal "Session not found", body["error"] + end + test "handles DELETE request with valid session ID" do # First create a session with initialize init_request = create_rack_request(