@@ -960,6 +960,72 @@ async def test_streamablehttp_client_session_termination(
960
960
await session .list_tools ()
961
961
962
962
963
+ @pytest .mark .anyio
964
+ async def test_streamablehttp_client_session_termination_204 (
965
+ basic_server , basic_server_url , monkeypatch
966
+ ):
967
+ """Test client session termination functionality with a 204 response.
968
+
969
+ This test patches the httpx client to return a 204 response for DELETEs.
970
+ """
971
+
972
+ # Save the original delete method to restore later
973
+ original_delete = httpx .AsyncClient .delete
974
+
975
+ # Mock the client's delete method to return a 204
976
+ async def mock_delete (self , * args , ** kwargs ):
977
+ # Call the original method to get the real response
978
+ response = await original_delete (self , * args , ** kwargs )
979
+
980
+ # Create a new response with 204 status code but same headers
981
+ mocked_response = httpx .Response (
982
+ 204 ,
983
+ headers = response .headers ,
984
+ content = response .content ,
985
+ request = response .request ,
986
+ )
987
+ return mocked_response
988
+
989
+ # Apply the patch to the httpx client
990
+ monkeypatch .setattr (httpx .AsyncClient , "delete" , mock_delete )
991
+
992
+ captured_session_id = None
993
+
994
+ # Create the streamablehttp_client with a custom httpx client to capture headers
995
+ async with streamablehttp_client (f"{ basic_server_url } /mcp" ) as (
996
+ read_stream ,
997
+ write_stream ,
998
+ get_session_id ,
999
+ ):
1000
+ async with ClientSession (read_stream , write_stream ) as session :
1001
+ # Initialize the session
1002
+ result = await session .initialize ()
1003
+ assert isinstance (result , InitializeResult )
1004
+ captured_session_id = get_session_id ()
1005
+ assert captured_session_id is not None
1006
+
1007
+ # Make a request to confirm session is working
1008
+ tools = await session .list_tools ()
1009
+ assert len (tools .tools ) == 4
1010
+
1011
+ headers = {}
1012
+ if captured_session_id :
1013
+ headers [MCP_SESSION_ID_HEADER ] = captured_session_id
1014
+
1015
+ async with streamablehttp_client (f"{ basic_server_url } /mcp" , headers = headers ) as (
1016
+ read_stream ,
1017
+ write_stream ,
1018
+ _ ,
1019
+ ):
1020
+ async with ClientSession (read_stream , write_stream ) as session :
1021
+ # Attempt to make a request after termination
1022
+ with pytest .raises (
1023
+ McpError ,
1024
+ match = "Session terminated" ,
1025
+ ):
1026
+ await session .list_tools ()
1027
+
1028
+
963
1029
@pytest .mark .anyio
964
1030
async def test_streamablehttp_client_resumption (event_server ):
965
1031
"""Test client session to resume a long running tool."""
0 commit comments