Skip to content

Python FastMCP servers have no route either: @mcp.tool is the largest measured registration idiom #484

Closed

Description

@pengfei-threemoonslab

Python FastMCP servers have no route either: @mcp.tool is the largest measured registration idiom

Summary

#431 shipped a built-in registry of MCP tool-registration idioms covering TypeScript
and Go — the two languages its three vendor walks measured. The 30-server survey it
required before choosing that set is published at
docs/mcp-registration-idioms.md, and it
found one shape above the coverage line that #431 deliberately did not ship:

idiom repositories largest single repo
Python @mcp.tool (FastMCP decorator) 5 awslabs/mcp (488 call sites)
Go Tool{Name: "…"} 3 github/github-mcp-server (135)
TS .tool( / .registerTool("…" 3 cloudflare/mcp-server-cloudflare (85)

Python FastMCP is the largest single shape in the survey by both measures. redis/mcp-redis,
neo4j-contrib/mcp-neo4j, chroma-core/chroma-mcp and awslabs/mcp are all in the state the
MongoDB and Grafana servers were in before #431: detect returns is_agent_project: false.

Why it was deferred rather than skipped

It is a different extraction mechanism, and #393's lesson is that the mechanism is
reusable but each one needs its own adversarial probe list before it can claim anything.
Concretely, none of these hold for the lexical reader #431 shipped:

  • The name defaults to the decorated function's name and is only sometimes a literal
    (@mcp.tool(name="…")).
  • The input schema comes from the signature, so unlike TS/Go this route could carry
    real parameters — which changes what the SHIP-SCHEMA-* family sees.
  • Provenance is an import binding (from mcp.server.fastmcp import FastMCP,
    from fastmcp import FastMCP), not a declared dependency, and the binding is what stops
    @anything.tool from reading as a registration.
  • Python has a real AST in-tree, so a masking lexer would be the wrong tool: the existing
    inputs/_python_framework.py machinery is the right base.

The lexical reader had eight fail-open constructs in its first draft, all found by
writing the probe list. A Python idiom bolted onto #431's increment without its own list
would have shipped without that check.

Scope

  • One idiom, py_fastmcp_decorator, in the existing built-in registry — same registry,
    same medium ceiling, same per-file completeness rule, same exclusion-ledger accounting
    for a name this reader cannot resolve.
  • AST-based, following google_adk's binding-table approach rather than a text scan.
  • Its own adversarial probe list, at minimum: a decorator on an alias
    (t = mcp.tool), a name built at runtime, a decorator applied by a factory,
    functools.wraps, a conditional registration, a re-bound module symbol, and
    @app.tool where app is not a FastMCP instance.

Acceptance

Filed from #431's survey; the measurement is the evidence the
roadmap non-goal clause asks for.

Activity

  1. added
    P1Picked up inside the current milestone window; keep about 15 open
    on Sep 2, 2026
  2. added this to the v0.18.0 milestone on Sep 2, 2026
  3. pengfei-threemoonslab commented on Sep 2, 2026

    @pengfei-threemoonslab
    ContributorAuthor

    Priority: P1, v0.18.0. By the survey this issue cites, Python FastMCP @mcp.tool is the largest single registration idiom (5 repositories, 488 call sites in awslabs/mcp alone); without it the top-N MCP study excludes its biggest segment. Same registry, same measured-confidence discipline as #431; a runtime-built tool name stays unenumerated and lands in the exclusion ledger. Sequencing: land on main behind the v0.16.0 release candidate — it must not enter the wheel that #456's receipts bind to unless the candidate is re-cut deliberately.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1Picked up inside the current milestone window; keep about 15 openarea:adapterFramework input adapters and tool catalog constructionenhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions