fix(ingest): compose the MCP timeout with anyio's own cancel scope, not asyncio.wait_for (kø-z)
asyncio.wait_for cancelling stdio_call_tool's run() from outside the anyio task groups it awaits (stdio_client, ClientSession) never surfaced a TimeoutError: measured against a real hanging server, the mismatch produced an anyio.BrokenResourceError wrapped in a BaseExceptionGroup instead. Moving the deadline to anyio.fail_after, nested inside both task groups, lets anyio tear down its own structure cleanly and raise a plain TimeoutError, which is now translated into IngestError(code="mcp_timeout") alongside the mcp_tool_error/mcp_non_text_content family.
This commit is contained in:
parent
3748011d35
commit
5269b7ddd5
2 changed files with 49 additions and 12 deletions
|
|
@ -120,6 +120,28 @@ def test_tool_error_reaches_the_caller_as_ingest_error(
|
|||
assert excinfo.value.code == "mcp_tool_error"
|
||||
|
||||
|
||||
def test_tool_timeout_reaches_the_caller_as_ingest_error(
|
||||
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
"""A tool that outlives ``timeout_seconds`` must surface as a typed ``IngestError``.
|
||||
|
||||
``asyncio.wait_for`` wraps ``run()`` — itself two nested anyio task groups
|
||||
(``stdio_client``, ``ClientSession``). Only a REAL hanging server proves what the timeout
|
||||
cancellation actually surfaces as: a canned-tool test never enters a task group and cannot
|
||||
observe this at all (the same reason (x)'s ``mcp_tool_error`` unwrap needed a real subprocess).
|
||||
RED until the timeout is caught and re-raised as an owned ``IngestError``.
|
||||
"""
|
||||
script = _write_server(
|
||||
tmp_path,
|
||||
"import time\n@server.tool()\ndef cost_docs() -> str:\n time.sleep(5)\n return 'late'\n",
|
||||
)
|
||||
get = _transport(script, monkeypatch, timeout_seconds=0.2)
|
||||
|
||||
with pytest.raises(IngestError) as excinfo:
|
||||
get(f"mcp+stdio://{_SERVER_REF}/cost_docs", None)
|
||||
assert excinfo.value.code == "mcp_timeout"
|
||||
|
||||
|
||||
def test_missing_server_ref_fails_before_any_process_is_spawned(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue