Skip to content

Commit 993dbf5

Browse files
authored
Merge pull request #352 from koic/document_initialize_protocol_version_authority
Document `initialize` body `protocolVersion` is authoritative on Streamable HTTP
2 parents d6b5392 + 711f064 commit 993dbf5

2 files changed

Lines changed: 55 additions & 0 deletions

File tree

lib/mcp/server/transports/streamable_http_transport.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,9 @@ def handle_post(request)
342342
body = parse_request_body(body_string)
343343
return body if parse_error_tuple?(body)
344344

345+
# The `MCP-Protocol-Version` header is only meaningful after negotiation, so on `initialize`
346+
# the JSON-RPC body `params.protocolVersion` is authoritative and the header (if any) is ignored.
347+
# This matches the TypeScript and Python SDKs.
345348
unless initialize_request?(body)
346349
return missing_session_id_response if !@stateless && !session_id
347350

test/mcp/server/transports/streamable_http_transport_test.rb

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1400,6 +1400,58 @@ def string
14001400
assert_equal 200, response[0]
14011401
end
14021402

1403+
test "POST initialize request negotiates body protocolVersion when header is an older supported version" do
1404+
older_version = "2025-06-18"
1405+
assert_includes Configuration::SUPPORTED_STABLE_PROTOCOL_VERSIONS, older_version
1406+
refute_equal Configuration::LATEST_STABLE_PROTOCOL_VERSION, older_version
1407+
1408+
request = create_rack_request(
1409+
"POST",
1410+
"/",
1411+
{
1412+
"CONTENT_TYPE" => "application/json",
1413+
"HTTP_MCP_PROTOCOL_VERSION" => older_version,
1414+
},
1415+
{
1416+
jsonrpc: "2.0",
1417+
method: "initialize",
1418+
id: "init",
1419+
params: { protocolVersion: Configuration::LATEST_STABLE_PROTOCOL_VERSION },
1420+
}.to_json,
1421+
)
1422+
1423+
response = @transport.handle_request(request)
1424+
assert_equal 200, response[0]
1425+
body = JSON.parse(response[2][0])
1426+
assert_equal Configuration::LATEST_STABLE_PROTOCOL_VERSION, body["result"]["protocolVersion"]
1427+
end
1428+
1429+
test "POST initialize request negotiates body protocolVersion when header is a newer supported version" do
1430+
older_version = "2025-06-18"
1431+
assert_includes Configuration::SUPPORTED_STABLE_PROTOCOL_VERSIONS, older_version
1432+
refute_equal Configuration::LATEST_STABLE_PROTOCOL_VERSION, older_version
1433+
1434+
request = create_rack_request(
1435+
"POST",
1436+
"/",
1437+
{
1438+
"CONTENT_TYPE" => "application/json",
1439+
"HTTP_MCP_PROTOCOL_VERSION" => Configuration::LATEST_STABLE_PROTOCOL_VERSION,
1440+
},
1441+
{
1442+
jsonrpc: "2.0",
1443+
method: "initialize",
1444+
id: "init",
1445+
params: { protocolVersion: older_version },
1446+
}.to_json,
1447+
)
1448+
1449+
response = @transport.handle_request(request)
1450+
assert_equal 200, response[0]
1451+
body = JSON.parse(response[2][0])
1452+
assert_equal older_version, body["result"]["protocolVersion"]
1453+
end
1454+
14031455
test "POST request with unsupported MCP-Protocol-Version returns 400" do
14041456
init_request = create_rack_request(
14051457
"POST",

0 commit comments

Comments
 (0)