From 9b89620257f1d185287f766466331e1404e09ee8 Mon Sep 17 00:00:00 2001 From: Koichi ITO Date: Sat, 23 May 2026 21:24:57 +0900 Subject: [PATCH] Fix case-sensitive Accept header comparison ## Motivation and Context RFC 9110 defines media type comparison as case-insensitive, but `parse_accept_header` compared types without normalizing case. This caused `Application/JSON` or `TEXT/Event-Stream` to be rejected with 406 Not Acceptable. ## How Has This Been Tested? Added tests for mixed-case Accept headers: - `Accept: Application/JSON, Text/Event-Stream` succeeds for POST - `Accept: TEXT/EVENT-STREAM` succeeds for GET SSE ## Breaking Changes None. This is a bug fix bringing behavior into conformance with RFC 9110. --- .../transports/streamable_http_transport.rb | 2 +- .../streamable_http_transport_test.rb | 39 +++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/lib/mcp/server/transports/streamable_http_transport.rb b/lib/mcp/server/transports/streamable_http_transport.rb index 3a642e2e..48d42868 100644 --- a/lib/mcp/server/transports/streamable_http_transport.rb +++ b/lib/mcp/server/transports/streamable_http_transport.rb @@ -504,7 +504,7 @@ def validate_accept_header(request, required_types) def parse_accept_header(header) header.split(",").map do |part| - part.split(";").first.strip + part.split(";").first.strip.downcase 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 facb5472..20d094a2 100644 --- a/test/mcp/server/transports/streamable_http_transport_test.rb +++ b/test/mcp/server/transports/streamable_http_transport_test.rb @@ -1465,6 +1465,45 @@ def string assert_equal 200, response[0] end + test "POST request with mixed-case Accept header succeeds" do + request = create_rack_request_without_accept( + "POST", + "/", + { + "CONTENT_TYPE" => "application/json", + "HTTP_ACCEPT" => "Application/JSON, Text/Event-Stream", + }, + { jsonrpc: "2.0", method: "initialize", id: "123" }.to_json, + ) + + response = @transport.handle_request(request) + assert_equal 200, response[0] + end + + test "GET request with upper-case Accept header succeeds" do + init_request = create_rack_request( + "POST", + "/", + { "CONTENT_TYPE" => "application/json" }, + { jsonrpc: "2.0", method: "initialize", id: "123" }.to_json, + ) + init_response = @transport.handle_request(init_request) + session_id = init_response[1]["Mcp-Session-Id"] + + request = create_rack_request_without_accept( + "GET", + "/", + { + "HTTP_ACCEPT" => "TEXT/EVENT-STREAM", + "HTTP_MCP_SESSION_ID" => session_id, + }, + ) + + response = @transport.handle_request(request) + assert_equal 200, response[0] + assert_equal "text/event-stream", response[1]["Content-Type"] + end + test "GET request without Accept header returns 406" do init_request = create_rack_request( "POST",