|
7 | 7 | import pytest |
8 | 8 | from anyio import ClosedResourceError |
9 | 9 | from mcp import ClientSession, Tool as MCPTool |
10 | | -from mcp.types import CallToolResult, GetPromptResult, ListPromptsResult, ListToolsResult |
| 10 | +from mcp.shared.exceptions import McpError |
| 11 | +from mcp.types import CallToolResult, ErrorData, GetPromptResult, ListPromptsResult, ListToolsResult |
11 | 12 |
|
12 | 13 | from agents.exceptions import UserError |
13 | 14 | from agents.mcp.server import MCPServerStreamableHttp, _MCPServerWithClientSession |
@@ -228,6 +229,18 @@ async def call_tool(self, tool_name, arguments, meta=None): |
228 | 229 | raise ClosedResourceError() |
229 | 230 |
|
230 | 231 |
|
| 232 | +class McpRequestTimeoutSession: |
| 233 | + def __init__(self, message: str = "timed out"): |
| 234 | + self.call_tool_attempts = 0 |
| 235 | + self.message = message |
| 236 | + |
| 237 | + async def call_tool(self, tool_name, arguments, meta=None): |
| 238 | + self.call_tool_attempts += 1 |
| 239 | + raise McpError( |
| 240 | + ErrorData(code=httpx.codes.REQUEST_TIMEOUT, message=self.message), |
| 241 | + ) |
| 242 | + |
| 243 | + |
231 | 244 | class IsolatedRetrySession: |
232 | 245 | def __init__(self): |
233 | 246 | self.call_tool_attempts = 0 |
@@ -326,6 +339,21 @@ async def test_streamable_http_retries_closed_resource_on_isolated_session(): |
326 | 339 | assert isolated_session.call_tool_attempts == 1 |
327 | 340 |
|
328 | 341 |
|
| 342 | +@pytest.mark.asyncio |
| 343 | +async def test_streamable_http_retries_mcp_408_on_isolated_session(): |
| 344 | + isolated_session = IsolatedRetrySession() |
| 345 | + server = DummyStreamableHttpServer( |
| 346 | + McpRequestTimeoutSession("Timed out while waiting for response to ClientRequest."), |
| 347 | + isolated_session, |
| 348 | + ) |
| 349 | + server.max_retry_attempts = 1 |
| 350 | + |
| 351 | + result = await server.call_tool("tool", None) |
| 352 | + |
| 353 | + assert isinstance(result, CallToolResult) |
| 354 | + assert isolated_session.call_tool_attempts == 1 |
| 355 | + |
| 356 | + |
329 | 357 | @pytest.mark.asyncio |
330 | 358 | async def test_streamable_http_does_not_retry_4xx_on_isolated_session(): |
331 | 359 | isolated_session = IsolatedRetrySession() |
|
0 commit comments