fix(mcp): validate tool call timeout config

This commit is contained in:
Junyan Qin
2026-07-23 18:20:30 +08:00
parent 0dfae76e39
commit 283c6949f4
2 changed files with 10 additions and 4 deletions
@@ -315,8 +315,12 @@ class RuntimeMCPSession:
def _parse_tool_call_timeout(self, value: typing.Any) -> float:
"""Return a safe tool-call timeout; zero explicitly disables it."""
try:
timeout = float(value)
except (TypeError, ValueError):
timeout = -1 if isinstance(value, bool) else float(value)
if timeout > 0:
# Validate the exact conversion used for each call here, so a
# finite-but-enormous manual config cannot fail at invocation.
timedelta(seconds=timeout)
except (TypeError, ValueError, OverflowError):
timeout = -1
if not math.isfinite(timeout) or timeout < 0:
@@ -1035,7 +1039,9 @@ class RuntimeMCPSession:
def _is_tool_call_timeout(exc: BaseException) -> bool:
"""Recognize the MCP SDK's per-request timeout without retrying it."""
return any(
isinstance(leaf, McpError) and leaf.error.code == httpx.codes.REQUEST_TIMEOUT
isinstance(leaf, McpError)
and leaf.error.code == httpx.codes.REQUEST_TIMEOUT
and leaf.error.message.startswith('Timed out while waiting for response')
for leaf in RuntimeMCPSession._iter_exception_leaves(exc)
)
@@ -153,7 +153,7 @@ async def test_invoke_mcp_tool_timeout_is_not_retried_and_session_remains_usable
assert call_tool.await_count == 2
@pytest.mark.parametrize('invalid_timeout', [-1, float('inf'), 'not-a-number'])
@pytest.mark.parametrize('invalid_timeout', [-1, float('inf'), 1e300, True, 'not-a-number'])
def test_invalid_tool_call_timeout_falls_back_to_default(invalid_timeout):
ap = _app()
session = RuntimeMCPSession(