Skip to content

Commit 5ebcaef

Browse files
njbrakegrll
andauthored
Prevent MCP ClientSession hang (grll#35)
* Prevent MCP ClientSession hang Per https://modelcontextprotocol.io/specification/draft/basic/lifecycle#timeouts "Implementations SHOULD establish timeouts for all sent requests, to prevent hung connections and resource exhaustion. When the request has not received a success or error response within the timeout period, the sender SHOULD issue a cancellation notification for that request and stop waiting for a response. SDKs and other middleware SHOULD allow these timeouts to be configured on a per-request basis." * Update core.py * Update core.py * Update core.py * Update based on PR comments * Update core.py Co-authored-by: Guillaume Raille <guillaume.raille@gmail.com> --------- Co-authored-by: Guillaume Raille <guillaume.raille@gmail.com>
1 parent 757e221 commit 5ebcaef

1 file changed

Lines changed: 14 additions & 1 deletion

File tree

src/mcpadapt/core.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import threading
99
from abc import ABC, abstractmethod
1010
from contextlib import AsyncExitStack, asynccontextmanager
11+
from datetime import timedelta
1112
from functools import partial
1213
from typing import Any, AsyncGenerator, Callable, Coroutine
1314

@@ -71,6 +72,7 @@ def async_adapt(
7172
@asynccontextmanager
7273
async def mcptools(
7374
serverparams: StdioServerParameters | dict[str, Any],
75+
client_session_timeout_seconds: float | timedelta | None = 5,
7476
) -> AsyncGenerator[tuple[ClientSession, list[mcp.types.Tool]], None]:
7577
"""Async context manager that yields tools from an MCP server.
7678
@@ -81,6 +83,7 @@ async def mcptools(
8183
serverparams: Parameters passed to either the stdio client or sse client.
8284
* if StdioServerParameters, run the MCP server using the stdio protocol.
8385
* if dict, assume the dict corresponds to parameters to an sse MCP server.
86+
client_session_timeout_seconds: Timeout for MCP ClientSession calls
8487
8588
Yields:
8689
A tuple of (MCP Client Session, list of MCP tools) available on the MCP server.
@@ -98,8 +101,18 @@ async def mcptools(
98101
f"Invalid serverparams, expected StdioServerParameters or dict found `{type(serverparams)}`"
99102
)
100103

104+
timeout = None
105+
if isinstance(client_session_timeout_seconds, float):
106+
timeout = timedelta(seconds=client_session_timeout_seconds)
107+
elif isinstance(client_session_timeout_seconds, timedelta):
108+
timeout = client_session_timeout_seconds
109+
101110
async with client as (read, write):
102-
async with ClientSession(read, write) as session:
111+
async with ClientSession(
112+
read,
113+
write,
114+
timeout,
115+
) as session:
103116
# Initialize the connection and get the tools from the mcp server
104117
await session.initialize()
105118
tools = await session.list_tools()

0 commit comments

Comments
 (0)