2626from mcp .client .streamable_http import streamablehttp_client
2727from mcp .server import Server
2828from mcp .server .streamable_http import (
29+ MCP_PROTOCOL_VERSION_HEADER ,
2930 MCP_SESSION_ID_HEADER ,
3031 SESSION_ID_PATTERN ,
3132 EventCallback ,
@@ -576,11 +577,24 @@ def test_session_termination(basic_server, basic_server_url):
576577 )
577578 assert response .status_code == 200
578579
580+ # Extract negotiated protocol version from SSE response
581+ init_data = None
582+ assert response .headers .get ("Content-Type" ) == "text/event-stream"
583+ for line in response .text .splitlines ():
584+ if line .startswith ("data: " ):
585+ init_data = json .loads (line [6 :])
586+ break
587+ assert init_data is not None
588+ negotiated_version = init_data ["result" ]["protocolVersion" ]
589+
579590 # Now terminate the session
580591 session_id = response .headers .get (MCP_SESSION_ID_HEADER )
581592 response = requests .delete (
582593 f"{ basic_server_url } /mcp" ,
583- headers = {MCP_SESSION_ID_HEADER : session_id },
594+ headers = {
595+ MCP_SESSION_ID_HEADER : session_id ,
596+ MCP_PROTOCOL_VERSION_HEADER : negotiated_version ,
597+ },
584598 )
585599 assert response .status_code == 200
586600
@@ -611,16 +625,27 @@ def test_response(basic_server, basic_server_url):
611625 )
612626 assert response .status_code == 200
613627
614- # Now terminate the session
628+ # Extract negotiated protocol version from SSE response
629+ init_data = None
630+ assert response .headers .get ("Content-Type" ) == "text/event-stream"
631+ for line in response .text .splitlines ():
632+ if line .startswith ("data: " ):
633+ init_data = json .loads (line [6 :])
634+ break
635+ assert init_data is not None
636+ negotiated_version = init_data ["result" ]["protocolVersion" ]
637+
638+ # Now get the session ID
615639 session_id = response .headers .get (MCP_SESSION_ID_HEADER )
616640
617- # Try to use the terminated session
641+ # Try to use the session with proper headers
618642 tools_response = requests .post (
619643 mcp_url ,
620644 headers = {
621645 "Accept" : "application/json, text/event-stream" ,
622646 "Content-Type" : "application/json" ,
623647 MCP_SESSION_ID_HEADER : session_id , # Use the session ID we got earlier
648+ MCP_PROTOCOL_VERSION_HEADER : negotiated_version ,
624649 },
625650 json = {"jsonrpc" : "2.0" , "method" : "tools/list" , "id" : "tools-1" },
626651 stream = True ,
@@ -662,12 +687,23 @@ def test_get_sse_stream(basic_server, basic_server_url):
662687 session_id = init_response .headers .get (MCP_SESSION_ID_HEADER )
663688 assert session_id is not None
664689
690+ # Extract negotiated protocol version from SSE response
691+ init_data = None
692+ assert init_response .headers .get ("Content-Type" ) == "text/event-stream"
693+ for line in init_response .text .splitlines ():
694+ if line .startswith ("data: " ):
695+ init_data = json .loads (line [6 :])
696+ break
697+ assert init_data is not None
698+ negotiated_version = init_data ["result" ]["protocolVersion" ]
699+
665700 # Now attempt to establish an SSE stream via GET
666701 get_response = requests .get (
667702 mcp_url ,
668703 headers = {
669704 "Accept" : "text/event-stream" ,
670705 MCP_SESSION_ID_HEADER : session_id ,
706+ MCP_PROTOCOL_VERSION_HEADER : negotiated_version ,
671707 },
672708 stream = True ,
673709 )
@@ -682,6 +718,7 @@ def test_get_sse_stream(basic_server, basic_server_url):
682718 headers = {
683719 "Accept" : "text/event-stream" ,
684720 MCP_SESSION_ID_HEADER : session_id ,
721+ MCP_PROTOCOL_VERSION_HEADER : negotiated_version ,
685722 },
686723 stream = True ,
687724 )
@@ -710,11 +747,22 @@ def test_get_validation(basic_server, basic_server_url):
710747 session_id = init_response .headers .get (MCP_SESSION_ID_HEADER )
711748 assert session_id is not None
712749
750+ # Extract negotiated protocol version from SSE response
751+ init_data = None
752+ assert init_response .headers .get ("Content-Type" ) == "text/event-stream"
753+ for line in init_response .text .splitlines ():
754+ if line .startswith ("data: " ):
755+ init_data = json .loads (line [6 :])
756+ break
757+ assert init_data is not None
758+ negotiated_version = init_data ["result" ]["protocolVersion" ]
759+
713760 # Test without Accept header
714761 response = requests .get (
715762 mcp_url ,
716763 headers = {
717764 MCP_SESSION_ID_HEADER : session_id ,
765+ MCP_PROTOCOL_VERSION_HEADER : negotiated_version ,
718766 },
719767 stream = True ,
720768 )
@@ -727,6 +775,7 @@ def test_get_validation(basic_server, basic_server_url):
727775 headers = {
728776 "Accept" : "application/json" ,
729777 MCP_SESSION_ID_HEADER : session_id ,
778+ MCP_PROTOCOL_VERSION_HEADER : negotiated_version ,
730779 },
731780 )
732781 assert response .status_code == 406
@@ -1038,6 +1087,7 @@ async def test_streamablehttp_client_resumption(event_server):
10381087 captured_resumption_token = None
10391088 captured_notifications = []
10401089 tool_started = False
1090+ captured_protocol_version = None
10411091
10421092 async def message_handler (
10431093 message : RequestResponder [types .ServerRequest , types .ClientResult ]
@@ -1070,6 +1120,8 @@ async def on_resumption_token_update(token: str) -> None:
10701120 assert isinstance (result , InitializeResult )
10711121 captured_session_id = get_session_id ()
10721122 assert captured_session_id is not None
1123+ # Capture the negotiated protocol version
1124+ captured_protocol_version = result .protocolVersion
10731125
10741126 # Start a long-running tool in a task
10751127 async with anyio .create_task_group () as tg :
@@ -1104,10 +1156,12 @@ async def run_tool():
11041156 captured_notifications_pre = captured_notifications .copy ()
11051157 captured_notifications = []
11061158
1107- # Now resume the session with the same mcp-session-id
1159+ # Now resume the session with the same mcp-session-id and protocol version
11081160 headers = {}
11091161 if captured_session_id :
11101162 headers [MCP_SESSION_ID_HEADER ] = captured_session_id
1163+ if captured_protocol_version :
1164+ headers [MCP_PROTOCOL_VERSION_HEADER ] = captured_protocol_version
11111165
11121166 async with streamablehttp_client (f"{ server_url } /mcp" , headers = headers ) as (
11131167 read_stream ,
@@ -1480,7 +1534,7 @@ def test_server_validates_protocol_version_header(basic_server, basic_server_url
14801534 )
14811535 assert response .status_code == 400
14821536 assert (
1483- "MCP-Protocol-Version" in response .text
1537+ MCP_PROTOCOL_VERSION_HEADER in response .text
14841538 or "protocol version" in response .text .lower ()
14851539 )
14861540
@@ -1491,13 +1545,13 @@ def test_server_validates_protocol_version_header(basic_server, basic_server_url
14911545 "Accept" : "application/json, text/event-stream" ,
14921546 "Content-Type" : "application/json" ,
14931547 MCP_SESSION_ID_HEADER : session_id ,
1494- "MCP-Protocol-Version" : "invalid-version" ,
1548+ MCP_PROTOCOL_VERSION_HEADER : "invalid-version" ,
14951549 },
14961550 json = {"jsonrpc" : "2.0" , "method" : "tools/list" , "id" : "test-2" },
14971551 )
14981552 assert response .status_code == 400
14991553 assert (
1500- "MCP-Protocol-Version" in response .text
1554+ MCP_PROTOCOL_VERSION_HEADER in response .text
15011555 or "protocol version" in response .text .lower ()
15021556 )
15031557
@@ -1508,13 +1562,13 @@ def test_server_validates_protocol_version_header(basic_server, basic_server_url
15081562 "Accept" : "application/json, text/event-stream" ,
15091563 "Content-Type" : "application/json" ,
15101564 MCP_SESSION_ID_HEADER : session_id ,
1511- "MCP-Protocol-Version" : "1999-01-01" , # Very old unsupported version
1565+ MCP_PROTOCOL_VERSION_HEADER : "1999-01-01" , # Very old unsupported version
15121566 },
15131567 json = {"jsonrpc" : "2.0" , "method" : "tools/list" , "id" : "test-3" },
15141568 )
15151569 assert response .status_code == 400
15161570 assert (
1517- "MCP-Protocol-Version" in response .text
1571+ MCP_PROTOCOL_VERSION_HEADER in response .text
15181572 or "protocol version" in response .text .lower ()
15191573 )
15201574
@@ -1535,7 +1589,7 @@ def test_server_validates_protocol_version_header(basic_server, basic_server_url
15351589 "Accept" : "application/json, text/event-stream" ,
15361590 "Content-Type" : "application/json" ,
15371591 MCP_SESSION_ID_HEADER : session_id ,
1538- "MCP-Protocol-Version" : negotiated_version ,
1592+ MCP_PROTOCOL_VERSION_HEADER : negotiated_version ,
15391593 },
15401594 json = {"jsonrpc" : "2.0" , "method" : "tools/list" , "id" : "test-4" },
15411595 )
0 commit comments