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 ,
@@ -1481,7 +1535,7 @@ async def test_server_validates_protocol_version_header(basic_server, basic_serv
14811535 )
14821536 assert response .status_code == 400
14831537 assert (
1484- "MCP-Protocol-Version" in response .text
1538+ MCP_PROTOCOL_VERSION_HEADER in response .text
14851539 or "protocol version" in response .text .lower ()
14861540 )
14871541
@@ -1492,13 +1546,13 @@ async def test_server_validates_protocol_version_header(basic_server, basic_serv
14921546 "Accept" : "application/json, text/event-stream" ,
14931547 "Content-Type" : "application/json" ,
14941548 MCP_SESSION_ID_HEADER : session_id ,
1495- "MCP-Protocol-Version" : "invalid-version" ,
1549+ MCP_PROTOCOL_VERSION_HEADER : "invalid-version" ,
14961550 },
14971551 json = {"jsonrpc" : "2.0" , "method" : "tools/list" , "id" : "test-2" },
14981552 )
14991553 assert response .status_code == 400
15001554 assert (
1501- "MCP-Protocol-Version" in response .text
1555+ MCP_PROTOCOL_VERSION_HEADER in response .text
15021556 or "protocol version" in response .text .lower ()
15031557 )
15041558
@@ -1509,13 +1563,13 @@ async def test_server_validates_protocol_version_header(basic_server, basic_serv
15091563 "Accept" : "application/json, text/event-stream" ,
15101564 "Content-Type" : "application/json" ,
15111565 MCP_SESSION_ID_HEADER : session_id ,
1512- "MCP-Protocol-Version" : "1999-01-01" , # Very old unsupported version
1566+ MCP_PROTOCOL_VERSION_HEADER : "1999-01-01" , # Very old unsupported version
15131567 },
15141568 json = {"jsonrpc" : "2.0" , "method" : "tools/list" , "id" : "test-3" },
15151569 )
15161570 assert response .status_code == 400
15171571 assert (
1518- "MCP-Protocol-Version" in response .text
1572+ MCP_PROTOCOL_VERSION_HEADER in response .text
15191573 or "protocol version" in response .text .lower ()
15201574 )
15211575
@@ -1536,7 +1590,7 @@ async def test_server_validates_protocol_version_header(basic_server, basic_serv
15361590 "Accept" : "application/json, text/event-stream" ,
15371591 "Content-Type" : "application/json" ,
15381592 MCP_SESSION_ID_HEADER : session_id ,
1539- "MCP-Protocol-Version" : negotiated_version ,
1593+ MCP_PROTOCOL_VERSION_HEADER : negotiated_version ,
15401594 },
15411595 json = {"jsonrpc" : "2.0" , "method" : "tools/list" , "id" : "test-4" },
15421596 )
0 commit comments