@@ -1385,6 +1385,258 @@ def string
13851385 assert_equal "text/event-stream" , response [ 1 ] [ "Content-Type" ]
13861386 end
13871387
1388+ test "POST initialize request ignores MCP-Protocol-Version header" do
1389+ request = create_rack_request (
1390+ "POST" ,
1391+ "/" ,
1392+ {
1393+ "CONTENT_TYPE" => "application/json" ,
1394+ "HTTP_MCP_PROTOCOL_VERSION" => "1900-01-01" ,
1395+ } ,
1396+ { jsonrpc : "2.0" , method : "initialize" , id : "init" } . to_json ,
1397+ )
1398+
1399+ response = @transport . handle_request ( request )
1400+ assert_equal 200 , response [ 0 ]
1401+ end
1402+
1403+ test "POST request with unsupported MCP-Protocol-Version returns 400" do
1404+ init_request = create_rack_request (
1405+ "POST" ,
1406+ "/" ,
1407+ { "CONTENT_TYPE" => "application/json" } ,
1408+ { jsonrpc : "2.0" , method : "initialize" , id : "init" } . to_json ,
1409+ )
1410+ init_response = @transport . handle_request ( init_request )
1411+ session_id = init_response [ 1 ] [ "Mcp-Session-Id" ]
1412+
1413+ request = create_rack_request (
1414+ "POST" ,
1415+ "/" ,
1416+ {
1417+ "CONTENT_TYPE" => "application/json" ,
1418+ "HTTP_MCP_SESSION_ID" => session_id ,
1419+ "HTTP_MCP_PROTOCOL_VERSION" => "1999-01-01" ,
1420+ } ,
1421+ { jsonrpc : "2.0" , method : "tools/list" , id : "list" } . to_json ,
1422+ )
1423+
1424+ response = @transport . handle_request ( request )
1425+ assert_equal 400 , response [ 0 ]
1426+ assert_equal ( { "Content-Type" => "application/json" } , response [ 1 ] )
1427+
1428+ body = JSON . parse ( response [ 2 ] [ 0 ] )
1429+ assert_equal "2.0" , body [ "jsonrpc" ]
1430+ assert_nil body [ "id" ]
1431+ assert_equal JsonRpcHandler ::ErrorCode ::INVALID_REQUEST , body [ "error" ] [ "code" ]
1432+ assert_includes body [ "error" ] [ "message" ] , "1999-01-01"
1433+ assert_includes body [ "error" ] [ "message" ] , Configuration ::LATEST_STABLE_PROTOCOL_VERSION
1434+ end
1435+
1436+ test "POST request with malformed MCP-Protocol-Version returns 400" do
1437+ init_request = create_rack_request (
1438+ "POST" ,
1439+ "/" ,
1440+ { "CONTENT_TYPE" => "application/json" } ,
1441+ { jsonrpc : "2.0" , method : "initialize" , id : "init" } . to_json ,
1442+ )
1443+ init_response = @transport . handle_request ( init_request )
1444+ session_id = init_response [ 1 ] [ "Mcp-Session-Id" ]
1445+
1446+ request = create_rack_request (
1447+ "POST" ,
1448+ "/" ,
1449+ {
1450+ "CONTENT_TYPE" => "application/json" ,
1451+ "HTTP_MCP_SESSION_ID" => session_id ,
1452+ "HTTP_MCP_PROTOCOL_VERSION" => "not-a-version" ,
1453+ } ,
1454+ { jsonrpc : "2.0" , method : "tools/list" , id : "list" } . to_json ,
1455+ )
1456+
1457+ response = @transport . handle_request ( request )
1458+ assert_equal 400 , response [ 0 ]
1459+
1460+ body = JSON . parse ( response [ 2 ] [ 0 ] )
1461+ assert_includes body [ "error" ] [ "message" ] , "not-a-version"
1462+ end
1463+
1464+ test "POST request with supported MCP-Protocol-Version succeeds" do
1465+ init_request = create_rack_request (
1466+ "POST" ,
1467+ "/" ,
1468+ { "CONTENT_TYPE" => "application/json" } ,
1469+ { jsonrpc : "2.0" , method : "initialize" , id : "init" } . to_json ,
1470+ )
1471+ init_response = @transport . handle_request ( init_request )
1472+ session_id = init_response [ 1 ] [ "Mcp-Session-Id" ]
1473+
1474+ request = create_rack_request (
1475+ "POST" ,
1476+ "/" ,
1477+ {
1478+ "CONTENT_TYPE" => "application/json" ,
1479+ "HTTP_MCP_SESSION_ID" => session_id ,
1480+ "HTTP_MCP_PROTOCOL_VERSION" => Configuration ::LATEST_STABLE_PROTOCOL_VERSION ,
1481+ } ,
1482+ { jsonrpc : "2.0" , method : "tools/list" , id : "list" } . to_json ,
1483+ )
1484+
1485+ response = @transport . handle_request ( request )
1486+ assert_equal 200 , response [ 0 ]
1487+ end
1488+
1489+ test "POST request without MCP-Protocol-Version header succeeds" do
1490+ init_request = create_rack_request (
1491+ "POST" ,
1492+ "/" ,
1493+ { "CONTENT_TYPE" => "application/json" } ,
1494+ { jsonrpc : "2.0" , method : "initialize" , id : "init" } . to_json ,
1495+ )
1496+ init_response = @transport . handle_request ( init_request )
1497+ session_id = init_response [ 1 ] [ "Mcp-Session-Id" ]
1498+
1499+ request = create_rack_request (
1500+ "POST" ,
1501+ "/" ,
1502+ {
1503+ "CONTENT_TYPE" => "application/json" ,
1504+ "HTTP_MCP_SESSION_ID" => session_id ,
1505+ } ,
1506+ { jsonrpc : "2.0" , method : "tools/list" , id : "list" } . to_json ,
1507+ )
1508+
1509+ response = @transport . handle_request ( request )
1510+ assert_equal 200 , response [ 0 ]
1511+ end
1512+
1513+ test "POST request with array body and unsupported MCP-Protocol-Version returns 400" do
1514+ init_request = create_rack_request (
1515+ "POST" ,
1516+ "/" ,
1517+ { "CONTENT_TYPE" => "application/json" } ,
1518+ { jsonrpc : "2.0" , method : "initialize" , id : "init" } . to_json ,
1519+ )
1520+ init_response = @transport . handle_request ( init_request )
1521+ session_id = init_response [ 1 ] [ "Mcp-Session-Id" ]
1522+
1523+ request = create_rack_request (
1524+ "POST" ,
1525+ "/" ,
1526+ {
1527+ "CONTENT_TYPE" => "application/json" ,
1528+ "HTTP_MCP_SESSION_ID" => session_id ,
1529+ "HTTP_MCP_PROTOCOL_VERSION" => "1999-01-01" ,
1530+ } ,
1531+ [ { jsonrpc : "2.0" , method : "tools/list" , id : "list" } ] . to_json ,
1532+ )
1533+
1534+ response = @transport . handle_request ( request )
1535+ assert_equal 400 , response [ 0 ]
1536+
1537+ body = JSON . parse ( response [ 2 ] [ 0 ] )
1538+ assert_equal JsonRpcHandler ::ErrorCode ::INVALID_REQUEST , body [ "error" ] [ "code" ]
1539+ end
1540+
1541+ test "GET request with unsupported MCP-Protocol-Version returns 400" do
1542+ init_request = create_rack_request (
1543+ "POST" ,
1544+ "/" ,
1545+ { "CONTENT_TYPE" => "application/json" } ,
1546+ { jsonrpc : "2.0" , method : "initialize" , id : "init" } . to_json ,
1547+ )
1548+ init_response = @transport . handle_request ( init_request )
1549+ session_id = init_response [ 1 ] [ "Mcp-Session-Id" ]
1550+
1551+ request = create_rack_request (
1552+ "GET" ,
1553+ "/" ,
1554+ {
1555+ "HTTP_MCP_SESSION_ID" => session_id ,
1556+ "HTTP_MCP_PROTOCOL_VERSION" => "1999-01-01" ,
1557+ } ,
1558+ )
1559+
1560+ response = @transport . handle_request ( request )
1561+ assert_equal 400 , response [ 0 ]
1562+
1563+ body = JSON . parse ( response [ 2 ] [ 0 ] )
1564+ assert_equal JsonRpcHandler ::ErrorCode ::INVALID_REQUEST , body [ "error" ] [ "code" ]
1565+ end
1566+
1567+ test "GET request without MCP-Protocol-Version header succeeds" do
1568+ init_request = create_rack_request (
1569+ "POST" ,
1570+ "/" ,
1571+ { "CONTENT_TYPE" => "application/json" } ,
1572+ { jsonrpc : "2.0" , method : "initialize" , id : "init" } . to_json ,
1573+ )
1574+ init_response = @transport . handle_request ( init_request )
1575+ session_id = init_response [ 1 ] [ "Mcp-Session-Id" ]
1576+
1577+ request = create_rack_request (
1578+ "GET" ,
1579+ "/" ,
1580+ { "HTTP_MCP_SESSION_ID" => session_id } ,
1581+ )
1582+
1583+ response = @transport . handle_request ( request )
1584+ assert_equal 200 , response [ 0 ]
1585+ end
1586+
1587+ test "DELETE request with unsupported MCP-Protocol-Version returns 400" do
1588+ init_request = create_rack_request (
1589+ "POST" ,
1590+ "/" ,
1591+ { "CONTENT_TYPE" => "application/json" } ,
1592+ { jsonrpc : "2.0" , method : "initialize" , id : "init" } . to_json ,
1593+ )
1594+ init_response = @transport . handle_request ( init_request )
1595+ session_id = init_response [ 1 ] [ "Mcp-Session-Id" ]
1596+
1597+ request = create_rack_request (
1598+ "DELETE" ,
1599+ "/" ,
1600+ {
1601+ "HTTP_MCP_SESSION_ID" => session_id ,
1602+ "HTTP_MCP_PROTOCOL_VERSION" => "1999-01-01" ,
1603+ } ,
1604+ )
1605+
1606+ response = @transport . handle_request ( request )
1607+ assert_equal 400 , response [ 0 ]
1608+
1609+ body = JSON . parse ( response [ 2 ] [ 0 ] )
1610+ assert_equal JsonRpcHandler ::ErrorCode ::INVALID_REQUEST , body [ "error" ] [ "code" ]
1611+ end
1612+
1613+ test "DELETE request with unsupported MCP-Protocol-Version returns 400 in stateless mode" do
1614+ stateless_transport = StreamableHTTPTransport . new ( @server , stateless : true )
1615+
1616+ request = create_rack_request (
1617+ "DELETE" ,
1618+ "/" ,
1619+ { "HTTP_MCP_PROTOCOL_VERSION" => "1999-01-01" } ,
1620+ )
1621+
1622+ response = stateless_transport . handle_request ( request )
1623+ assert_equal 400 , response [ 0 ]
1624+ end
1625+
1626+ test "DELETE request validates session before MCP-Protocol-Version" do
1627+ request = create_rack_request (
1628+ "DELETE" ,
1629+ "/" ,
1630+ {
1631+ "HTTP_MCP_SESSION_ID" => "unknown-session-id" ,
1632+ "HTTP_MCP_PROTOCOL_VERSION" => "1999-01-01" ,
1633+ } ,
1634+ )
1635+
1636+ response = @transport . handle_request ( request )
1637+ assert_equal 404 , response [ 0 ]
1638+ end
1639+
13881640 test "stateless mode allows requests without session IDs, responding with no session ID" do
13891641 stateless_transport = StreamableHTTPTransport . new ( @server , stateless : true )
13901642
0 commit comments