fix(server): stop stacking a tool profile's visibility on every session
Release / test (full, windows-latest, 3.11) (push) Canceled after 0s
Release / test (pdf, ubuntu-latest, 3.11) (push) Canceled after 0s
Release / test (pdf, ubuntu-latest, 3.12) (push) Canceled after 0s
Release / build (push) Canceled after 0s
Release / publish-pypi (push) Canceled after 0s
Release / github-release (push) Canceled after 0s
Release / test (full, windows-latest, 3.11) (push) Canceled after 0s
Release / test (pdf, ubuntu-latest, 3.11) (push) Canceled after 0s
Release / test (pdf, ubuntu-latest, 3.12) (push) Canceled after 0s
Release / build (push) Canceled after 0s
Release / publish-pypi (push) Canceled after 0s
Release / github-release (push) Canceled after 0s
What the first Linux CI run of the 1.6 tree found. - fastmcp 3's enable()/disable() append a Visibility transform per call, and a tool lookup walks the transform stack as nested calls. The lifespan re-applies the tool profile on every client connection, so an in-process server grew two layers per session until every tool call, system_status included, raised RecursionError (CPython 3.11 counts C frames against the limit). The profile's transforms now replace the previous ones, as _apply_discovery_mode already did; a test switches the profile 600 times and then calls a tool. The local suite runs in half the time it took with the stack growing. - 21 fake-ActiveX tests build a real pywin32 VARIANT; they now skip without pywin32, like the suite's other VARIANT-dependent COM tests, and the Windows lane keeps running them. - A test spelled a path through a directory it never created, which only Windows normalises away; it creates the directory. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FKFStjEFzpGyLq5bMpWxTd
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
17bf3a39ce
commit
cdb1063896
@@ -120,3 +120,25 @@ async def test_profile_switch_is_idempotent():
|
||||
assert set(info["disabled_tools"]) == set(server.SOLID_TOOL_NAMES)
|
||||
lean_again = await server._apply_tool_profile("lean")
|
||||
assert lean_again["enabled_count"] == len(server.LEAN_TOOL_NAMES)
|
||||
|
||||
|
||||
async def test_reapplying_a_profile_replaces_its_visibility_instead_of_stacking(monkeypatch):
|
||||
# fastmcp 3 appends a Visibility transform on every enable/disable call, and a
|
||||
# tool lookup walks the whole stack as nested calls. The lifespan re-applies
|
||||
# the profile on every client connection, so the stack grew by two per
|
||||
# session: after a few hundred in-process sessions every tool call raised
|
||||
# RecursionError (Linux CI, CPython 3.11, which counts C frames too).
|
||||
await server._apply_tool_profile("full")
|
||||
depth = len(server.mcp.transforms)
|
||||
for _ in range(300):
|
||||
await server._apply_tool_profile("lean")
|
||||
await server._apply_tool_profile("full")
|
||||
assert len(server.mcp.transforms) == depth
|
||||
|
||||
monkeypatch.setenv("AUTOCAD_MCP_BACKEND", "ezdxf")
|
||||
monkeypatch.setattr(config.settings, "tool_profile", "lean")
|
||||
async with Client(server.mcp) as client:
|
||||
visible = {tool.name for tool in await client.list_tools()}
|
||||
status = (await client.call_tool("system_status", {})).structured_content
|
||||
assert visible == set(server.LEAN_TOOL_NAMES)
|
||||
assert status["backend"] == "ezdxf"
|
||||
|
||||
Reference in New Issue
Block a user