@@ -960,6 +960,72 @@ async def test_streamablehttp_client_session_termination(
960960 await session .list_tools ()
961961
962962
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+
9631029@pytest .mark .anyio
9641030async def test_streamablehttp_client_resumption (event_server ):
9651031 """Test client session to resume a long running tool."""
0 commit comments