New in version 2.2.0Mounting lets you combine multiple FastMCP servers into one. When you mount a server, all its components become available through the parent. Under the hood, FastMCP uses FastMCPProvider (v3.0.0+) to source components from the mounted server.
Large applications benefit from modular organization. Rather than defining all components in one massive file, create focused servers for specific domains and combine them:
Modularity: Break down applications into smaller, focused servers
Reusability: Create utility servers and mount them wherever needed
Teamwork: Different teams can work on separate servers
Organization: Keep related functionality grouped together
Use mount() to add another server’s components to your server:
Copy
from fastmcp import FastMCP# Create focused subserversweather_server = FastMCP("Weather")@weather_server.tooldef get_forecast(city: str) -> str: """Get weather forecast for a city.""" return f"Sunny in {city}"@weather_server.resource("data://cities")def list_cities() -> list[str]: """List supported cities.""" return ["London", "Paris", "Tokyo"]# Create main server and mount the subservermain = FastMCP("MainApp")main.mount(weather_server)# Now main has access to get_forecast and data://cities
Mount remote HTTP servers or subprocess-based MCP servers using create_proxy():
Copy
from fastmcp import FastMCPfrom fastmcp.server import create_proxymcp = FastMCP("Orchestrator")# Mount a remote HTTP server (URLs work directly)mcp.mount(create_proxy("http://api.example.com/mcp"), namespace="api")# Mount local Python scripts (file paths work directly)mcp.mount(create_proxy("./my_server.py"), namespace="local")
With mount(), changes to the subserver are immediately reflected:
Copy
main = FastMCP("Main")main.mount(dynamic_server, namespace="dynamic")# Add a tool AFTER mounting - it's accessible through main@dynamic_server.tooldef added_later() -> str: return "Added after mounting!"# This works because mount() creates a live link
With import_server(), components are copied once at import time:
Copy
main = FastMCP("Main")async def setup(): await main.import_server(static_server, namespace="static")# Changes to static_server after this point are NOT reflected in main
The as_proxy parameter is deprecated. Mounted servers now always have their lifespan and middleware invoked. To create a proxy server explicitly, use create_proxy() from fastmcp.server.
Previously, the parent server could treat the mounted server as a separate entity with its own lifecycle. This behavior is now the default for all mounted servers:
New in version 3.0.0Parent server tag filters apply recursively to mounted servers:
Copy
api_server = FastMCP("API")@api_server.tool(tags={"production"})def prod_endpoint() -> str: return "Production data"@api_server.tool(tags={"development"})def dev_endpoint() -> str: return "Debug data"# Mount with production filterprod_app = FastMCP("Production")prod_app.mount(api_server, namespace="api")prod_app.enable(tags={"production"}, only=True)# Only prod_endpoint (namespaced as api_prod_endpoint) is visible
When using live mounting, operations like list_tools() on the parent server are affected by the performance of all mounted servers. This is particularly noticeable with:
HTTP-based mounted servers (300-400ms vs 1-2ms for local tools)
New in version 3.0.0When mounting multiple servers with the same namespace (or no namespace), the most recently mounted server takes precedence for conflicting component names: