|
57 | 57 | CallToolRequestParams, |
58 | 58 | CallToolResult, |
59 | 59 | InitializeResult, |
| 60 | + JSONRPCError, |
60 | 61 | JSONRPCRequest, |
| 62 | + JSONRPCResponse, |
61 | 63 | ListToolsResult, |
62 | 64 | PaginatedRequestParams, |
63 | 65 | ReadResourceRequestParams, |
@@ -1105,6 +1107,42 @@ async def test_streamable_http_client_error_handling(initialized_client_session: |
1105 | 1107 | assert "Unknown resource: unknown://test-error" in exc_info.value.error.message |
1106 | 1108 |
|
1107 | 1109 |
|
| 1110 | +@pytest.mark.anyio |
| 1111 | +async def test_streamable_http_request_error_does_not_close_writer(): |
| 1112 | + async def handler(request: httpx.Request) -> httpx.Response: |
| 1113 | + body = json.loads(request.content) |
| 1114 | + if body["method"] == "tools/list": |
| 1115 | + raise httpx.ConnectError("boom", request=request) |
| 1116 | + |
| 1117 | + return httpx.Response( |
| 1118 | + 200, |
| 1119 | + headers={"content-type": "application/json"}, |
| 1120 | + json={"jsonrpc": "2.0", "id": body["id"], "result": {}}, |
| 1121 | + request=request, |
| 1122 | + ) |
| 1123 | + |
| 1124 | + async with httpx.AsyncClient(transport=httpx.MockTransport(handler)) as client: |
| 1125 | + async with streamable_http_client("http://testserver/mcp", http_client=client) as (read_stream, write_stream): |
| 1126 | + await write_stream.send(SessionMessage(JSONRPCRequest(jsonrpc="2.0", id="bad", method="tools/list"))) |
| 1127 | + |
| 1128 | + with anyio.fail_after(1): |
| 1129 | + error_message = await read_stream.receive() |
| 1130 | + |
| 1131 | + assert isinstance(error_message, SessionMessage) |
| 1132 | + assert isinstance(error_message.message, JSONRPCError) |
| 1133 | + assert error_message.message.id == "bad" |
| 1134 | + assert error_message.message.error.code == types.INTERNAL_ERROR |
| 1135 | + |
| 1136 | + await write_stream.send(SessionMessage(JSONRPCRequest(jsonrpc="2.0", id="ok", method="ping"))) |
| 1137 | + |
| 1138 | + with anyio.fail_after(1): |
| 1139 | + response_message = await read_stream.receive() |
| 1140 | + |
| 1141 | + assert isinstance(response_message, SessionMessage) |
| 1142 | + assert isinstance(response_message.message, JSONRPCResponse) |
| 1143 | + assert response_message.message.id == "ok" |
| 1144 | + |
| 1145 | + |
1108 | 1146 | @pytest.mark.anyio |
1109 | 1147 | async def test_streamable_http_client_session_persistence(basic_server: None, basic_server_url: str): |
1110 | 1148 | """Test that session ID persists across requests.""" |
|
0 commit comments