Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions tests/tools/test_mcp_stdio_children_dead.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,36 @@ async def _run():
)

asyncio.run(_run())


def test_watch_ok_probe_does_not_create_unawaited_coroutine():
"""The fast-fail gate must inspect the watcher, not call it (#96044).

The old probe — inspect.isawaitable(_watch_children()) — created a
fresh coroutine per stdio tool call and never awaited it, emitting
'coroutine ... was never awaited' RuntimeWarnings under -W error and
churning the GC. Pin that the shipped source no longer calls the
watcher during the probe.
"""
import inspect as _inspect

import tools.mcp_tool as mcp_mod

src = _inspect.getsource(mcp_mod)
assert "isawaitable(_watch_children())" not in src
assert "iscoroutinefunction(_watch_children)" in src


def test_watch_ok_semantics_mock_vs_real():
"""MagicMock watchers stay on the plain-await path; real async defs
(and AsyncMock) qualify for the fast-fail race — same split the old
isawaitable(call) probe produced, without the coroutine leak."""
import inspect as _inspect
from unittest.mock import AsyncMock, MagicMock

async def _real_watcher(): # what the real method looks like
pass

assert _inspect.iscoroutinefunction(_real_watcher) is True
assert _inspect.iscoroutinefunction(AsyncMock()) is True
assert _inspect.iscoroutinefunction(MagicMock()) is False
2 changes: 1 addition & 1 deletion tools/mcp_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -6174,7 +6174,7 @@ async def _call():
_watch_children = getattr(server, "_watch_stdio_children", None)
_watch_ok = (
_watch_children is not None
and inspect.isawaitable(_watch_children())
and inspect.iscoroutinefunction(_watch_children)
and asyncio.iscoroutine(_call_coro)
)
if not _watch_ok:
Expand Down
Loading