Skip to content

Commit 44bbcfe

Browse files
fix: Retry ClosedResourceError on isolated session (#2711)
1 parent 5c9fb2c commit 44bbcfe

File tree

2 files changed

+32
-1
lines changed

2 files changed

+32
-1
lines changed

src/agents/mcp/server.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
if sys.version_info < (3, 11):
1616
from exceptiongroup import BaseExceptionGroup # pyright: ignore[reportMissingImports]
17+
from anyio import ClosedResourceError
1718
from anyio.streams.memory import MemoryObjectReceiveStream, MemoryObjectSendStream
1819
from mcp import ClientSession, StdioServerParameters, Tool as MCPTool, stdio_client
1920
from mcp.client.session import MessageHandlerFnT
@@ -1165,7 +1166,15 @@ async def _call_tool_with_session(
11651166
return await session.call_tool(tool_name, arguments, meta=meta)
11661167

11671168
def _should_retry_in_isolated_session(self, exc: BaseException) -> bool:
1168-
if isinstance(exc, (asyncio.CancelledError, httpx.ConnectError, httpx.TimeoutException)):
1169+
if isinstance(
1170+
exc,
1171+
(
1172+
asyncio.CancelledError,
1173+
ClosedResourceError,
1174+
httpx.ConnectError,
1175+
httpx.TimeoutException,
1176+
),
1177+
):
11691178
return True
11701179
if isinstance(exc, httpx.HTTPStatusError):
11711180
return exc.response.status_code >= 500

tests/mcp/test_client_session_retries.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import httpx
77
import pytest
8+
from anyio import ClosedResourceError
89
from mcp import ClientSession, Tool as MCPTool
910
from mcp.types import CallToolResult, GetPromptResult, ListPromptsResult, ListToolsResult
1011

@@ -218,6 +219,15 @@ async def call_tool(self, tool_name, arguments, meta=None):
218219
raise httpx.TimeoutException(self.message)
219220

220221

222+
class ClosedResourceSession:
223+
def __init__(self):
224+
self.call_tool_attempts = 0
225+
226+
async def call_tool(self, tool_name, arguments, meta=None):
227+
self.call_tool_attempts += 1
228+
raise ClosedResourceError()
229+
230+
221231
class IsolatedRetrySession:
222232
def __init__(self):
223233
self.call_tool_attempts = 0
@@ -304,6 +314,18 @@ async def test_streamable_http_retries_5xx_on_isolated_session():
304314
assert isolated_session.call_tool_attempts == 1
305315

306316

317+
@pytest.mark.asyncio
318+
async def test_streamable_http_retries_closed_resource_on_isolated_session():
319+
isolated_session = IsolatedRetrySession()
320+
server = DummyStreamableHttpServer(ClosedResourceSession(), isolated_session)
321+
server.max_retry_attempts = 1
322+
323+
result = await server.call_tool("tool", None)
324+
325+
assert isinstance(result, CallToolResult)
326+
assert isolated_session.call_tool_attempts == 1
327+
328+
307329
@pytest.mark.asyncio
308330
async def test_streamable_http_does_not_retry_4xx_on_isolated_session():
309331
isolated_session = IsolatedRetrySession()

0 commit comments

Comments
 (0)