fix(mcp): cancel timed-out coroutines, check session inside async callback - #6665
Open
aaronlab wants to merge 1 commit into
Open
Conversation
…lback - _run_on_mcp_loop: cancel the in-flight Future when result() raises TimeoutError — without cancellation the coroutine lingers on the MCP event loop holding session resources, and a backlog of zombie coroutines can effectively deadlock per-server sessions - _make_tool_handler: move the session-is-None check from the caller thread into the async _call() coroutine to eliminate a TOCTOU race where the session can disconnect between the check and the actual call_tool RPC, causing AttributeError on NoneType Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
This was referenced May 12, 2026
Contributor
|
Thanks for identifying two real MCP lifecycle concerns. Problems
Suggested changes
Automated hermes-sweeper review. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Futurewhen_run_on_mcp_looptimes out, preventing zombie coroutines from accumulating on the MCP event loop_call()to eliminate TOCTOU race during reconnectionDetails
Coroutine leak on timeout (HIGH)
_run_on_mcp_loopsubmits a coroutine to the MCP event loop viaasyncio.run_coroutine_threadsafeand waits withfuture.result(timeout=...). On timeout, theTimeoutErrorpropagates but the coroutine continues running on the event loop. Since MCP sessions are per-server (one session handles all tool calls), a backlog of zombie coroutines can congest the transport — no new calls complete because the session is processing replies for timed-out calls.Fix:
future.cancel()in except handler before re-raising.Session TOCTOU race (MEDIUM)
_make_tool_handlerchecksserver.sessionon the caller thread, then the actualcall_toolruns later on the MCP event loop thread. If the server reconnects between these (settingsession = Nonein thefinallyblock of the reconnection loop),server.sessionisNoneandcall_toolraisesAttributeError. Same pattern in all 5 handler factories.Fix: move the
session is Nonecheck inside the async_call()coroutine.Test plan
pytest tests/ -q🤖 Generated with Claude Code