v2.3.1 — Windows MCP hang hotfix (#46, #136)
Summary
Hotfix for the Windows long-running MCP tool hang. v2.2.4 shipped the event-loop policy fix, but @dev-limucc's test on #136 showed that was necessary but not sufficient — read-only tools worked, but build_or_update_graph_tool and embed_graph_tool still hung indefinitely on Windows 11 / Python 3.14.
uvx --reinstall code-review-graph
# or
pip install -U code-review-graphIf you were affected by either #46 or #136 on v2.2.4, this release should fix it.
What's fixed
FastMCP 2.x dispatches sync handlers inline on the only event-loop thread. When a handler runs for more than a few seconds — especially one that spawns subprocesses (full_build uses ProcessPoolExecutor) or does CPU-bound inference (sentence-transformers) — the loop stops pumping stdin/stdout, Claude Code's request never gets a response, and the MCP client shows "Synthesizing…" forever.
Fix: the five heavy tools are now async def and offload their blocking work with asyncio.to_thread. The event loop stays responsive and stdio keeps pumping.
Tools now async
build_or_update_graph_tool—full_build/incremental_updaterun_postprocess_tool— community detection can take 20s+ on large graphsembed_graph_tool— sentence-transformers / Gemini inferencedetect_changes_tool—git diffsubprocess + BFS traversalgenerate_wiki_tool— many SQLite reads + file writes
The other 19 tools are fast SQLite-read paths and stay sync.
Lock-in tests
Two new regression tests in tests/test_main.py::TestLongRunningToolsAreAsync:
test_heavy_tools_are_coroutines— asserts viamcp.get_tools()introspection that all 5 heavy tools register as coroutine functions.test_heavy_tool_source_uses_to_thread— greps each tool's source for a literalasyncio.to_threadcall, so we don't accidentally make a toolasync defwithout actually offloading the work.
These will fail at collection time if someone converts one of the 5 tools back to sync in a future refactor.
Verification
macOS / Python 3.11:
- All 24 tools register, 5 heavy ones as coroutines
- 737 tests pass (+2 new lock-in tests), coverage 74.63%
- ruff / mypy / bandit clean
- CI matrix 3.10 / 3.11 / 3.12 / 3.13 green
Windows: will be verified by @dev-limucc post-release against the original repro (build_or_update_graph_tool(full_rebuild=True) + embed_graph_tool).
Upgrade notes
- Nothing to do beyond upgrading. The async wrappers are transparent to MCP clients — they still call the tools the same way.
- If you're coming from v2.2.2 or earlier, the usual
code-review-graph installis still needed to pick up the v2.2.3 hook schema rewrite.