fastmcp icon indicating copy to clipboard operation
fastmcp copied to clipboard

Documentation: Server composition pattern incompatible with fastmcp dev

Open nick-youngblut opened this issue 2 months ago • 3 comments

Enhancement

The server composition documentation shows a pattern that only works when running servers directly, but fails silently when using fastmcp dev.

Current Documentation Pattern

The docs show:

from fastmcp import FastMCP
import asyncio

# Define subservers
weather_mcp = FastMCP(name="WeatherService")

@weather_mcp.tool
def get_forecast(city: str) -> dict:
    """Get weather forecast."""
    return {"city": city, "forecast": "Sunny"}

# Define main server
main_mcp = FastMCP(name="MainApp")

# Import subserver
async def setup():
    await main_mcp.import_server(weather_mcp, prefix="weather")

if __name__ == "__main__":
    asyncio.run(setup())
    main_mcp.run()

The Problem

This pattern does not work with fastmcp dev:

fastmcp dev server.py
# Result: No tools listed - setup() never runs

Why: fastmcp dev imports the module but doesn't execute the if __name__ == "__main__" block, so setup() is never called and subservers are never imported.

What Works

The pattern works fine when running directly:

python server.py
# or
npx @modelcontextprotocol/inspector uv run python server.py

Suggested Documentation Fix

The composition docs should include a warning and show the correct pattern for fastmcp dev compatibility:

Option 1: Event Loop Compatible Setup (Recommended)

async def setup():
    await main_mcp.import_server(weather_mcp, prefix="weather")

# Run setup at module level - compatible with both fastmcp dev and direct execution
try:
    loop = asyncio.get_running_loop()
    loop.create_task(setup())
except RuntimeError:
    asyncio.run(setup())

if __name__ == "__main__":
    main_mcp.run()

Option 2: Use MCP Inspector Instead

Add a note that for development/testing composed servers, the MCP Inspector is recommended:

npx @modelcontextprotocol/inspector uv run python server.py

nick-youngblut avatar Oct 21 '25 18:10 nick-youngblut

edit: listen to jeremiah not to me

importing requires a live server, mounting does not, can you use a mounted server?

the live server requirement precludes doing this with fastmcp dev

You may be able to import the server via a lifespan as starting in 2.13 lifespan is server lifetime-bound

strawgate avatar Oct 21 '25 19:10 strawgate

Actually I'd say neither of those is the best pattern. fastmcp run and fastmcp dev have the same semantics, including the use of a factory_function entrypoint for exactly this use case.

However I see that fastmcp run has a warning about __main__ but fastmcp dev only documents its entrypoints without that warning, so we should add it

Image

jlowin avatar Oct 21 '25 22:10 jlowin

Running fastmcp dev on the code shown in server composition documentation doesn't fail, but no tools are listed. This is quite confusing... at least at first.

nick-youngblut avatar Oct 22 '25 03:10 nick-youngblut