v2.0.1 — support FastMCP Code Mode (nested tool calls and listings) - #43
Merged
Conversation
The community adapter now distinguishes agent-facing traffic from calls a server makes to itself — a Code Mode sandbox chaining tools through call_tool, a catalog meta-tool fetching the hidden catalog, one tool composing another: - A nested tools/list is served verbatim. Previously it rebuilt the injection registries from the raw backend catalog, after which the strip no longer removed the injected session_id/context arguments — so an agent echoing the handle it was just issued failed FastMCP validation with "Unexpected keyword argument" on its next call, and the outer call's structured mint-back mirror was silently dropped. - A nested tools/call still publishes its event, but joins the enclosing call's session (one logical call, one session, instead of a fresh mint per inner call), carries the new presence-gated agentcat_nested tag, and is never decorated — mint-back blocks no longer leak into sandbox-visible results where generated code trips over them. The re-entrancy marker rides FastMCP's request-scoped context state, which nested contexts share by reference; frames are scoped by server identity so mounted and multi-server setups stay isolated. Regression tests reproduce the Code Mode mechanism without pydantic-monty via a CatalogTransform factory, on both the fastmcp 3.x and 4.x legs.
naji247
force-pushed
the
code-mode-support
branch
from
August 6, 2026 13:27
4e7c6ff to
1059d5f
Compare
…ases Two hardening changes surfaced by reviewing the nested-call test plan: - The frame now rides a module ContextVar tuple-stack (the _open_seams pattern) instead of FastMCP's Context._request_state. The state dict is only shared by reference with nested contexts from mid-3.x — on earlier releases the frame silently never propagated, so nested calls kept minting their own sessions there. A ContextVar has the same reach on every release, and concurrent inner calls each get their own context copy instead of racing restores in a shared dict. - The test module's version gate was too coarse: everything skipped without CatalogTransform, quietly dropping nested-call coverage from the daily version sweep on pre-transform releases. Only the hidden-catalog tests carry that guard now; new composing-server tests (a listed tool calling a sibling via ctx.fastmcp.call_tool) run on every community fastmcp release — which is exactly how the carrier bug above was caught, on fastmcp 3.0.0. New coverage: plain composing-tool nesting, per-call identify resolution on nested events, and concurrent inner calls via asyncio.gather all joining the outer session with a clean follow-up call.
kashishhora
approved these changes
Aug 6, 2026
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.
What
Patch release making AgentCat's community adapter fully compatible with FastMCP Code Mode and, more generally, with any server that calls itself mid-request (catalog meta-tools, tools composing sibling tools).
The bug
Code Mode's meta-tools fetch the real catalog mid-call via
CatalogTransform.get_tool_catalog, which lists withrun_middleware=True. That transform-bypassed backend listing re-enteredon_list_tools, which rebuilt the injection registries from it — replacing the agent-facing registry wholesale. Two visible consequences on any Code Mode server:executecall, the strip no longer removed the injectedsession_id/contextarguments, so an agent echoing the handle it was just issued (as the mint-back instructs) failed FastMCP validation withUnexpected keyword argument 'session_id'on every subsequent call._mcp_instructionsmirror was silently dropped.Independently, inner sandbox calls each minted their own session (one logical
executefragmented across 2+ sessions) and their results carried mint-back decoration into the sandbox, where generated code trips over the extra key.The fix
The adapter now installs a re-entrancy frame for the duration of each
on_call_tool, carried in FastMCP's request-scoped context state (shared by reference with every nested context; frames are scoped by server identity so mounted/multi-server setups stay isolated). While a frame is open on the same server:tools/list→ served verbatim: no injection, no registry writes. Agent-facing registries survive; sandbox-facing catalogs stay clean.tools/call→ still publishes its event (inner-call visibility inside Code Mode is a feature), but joins the enclosing call's session, carries a new presence-gatedagentcat_nested: "true"tag (same pattern asagentcat_mrtr;agentcat_session_id_sourcekeeps the outer call's value), and is never decorated.Tests
tests/test_utils/community_catalog_server.pyreproduces the Code Mode mechanism withoutpydantic-monty(aCatalogTransformmeta-tool that fetches the catalog and drives hidden tools). 10 regression tests on the fastmcp 3.x leg + a 4.x sibling; 9 of them fail against the pre-fix adapter, reproducing the exact production symptom. Full suites green on all three dependency legs (mcp 1.x + fastmcp 3.4.5: 878; mcp 2.x + fastmcp 4.0.0b1: 740; no-fastmcp: 760), and verified end to end over streamable HTTP against a live Code Mode server with events confirmed in the dashboard.Notes
AGENTCAT_TAG_NESTEDshould be mirrored into the TypeScript SDK at the next cross-SDK sync.uv.lockis stale (predates the 2.0.0 metadata) and is deliberately left for a separate housekeeping PR.