A capabilities guide for the call — covering advanced MCP patterns beyond simple data source connections.
FastMCP is the standard Python framework for building MCP servers, clients, and applications. FastMCP 1.0 was incorporated into the official MCP Python SDK in 2024. Today it powers ~70% of MCP servers across all languages and downloads 1M times per day.
The core promise: declare a Python function, and FastMCP handles everything else — schema generation, validation, protocol lifecycle, transport negotiation, auth. You write business logic; the MCP layer "just works."
@mcp.tool, @mcp.resource, @mcp.prompt
PrefabApp and the host renders it.
Most MCP connectors are thin wrappers around an API. FastMCP goes far further — here are the features that turn a connector into a production service.
Long-running operations shouldn't block the conversation. FastMCP implements the MCP background task protocol (SEP-1686) — add task=True to any tool and it becomes async-capable.
@mcp.tool(task=True) async def process_large_report(files: list[str], progress: Progress = Progress()) -> str: """Generate report from 50+ files — runs in background.""" await progress.set_total(len(files)) for file in files: await progress.set_message(f"Processing {file}") # ... do work ... await progress.increment() return "Done" # Scale horizontally with additional workers # fastmcp tasks worker server.py
| Backend | Use For | Pickup Latency | Scaling |
|---|---|---|---|
| In-Memory | Dev / single-process | ~250ms | Single process only |
| Redis | Production | Single-digit ms | Horizontal — add workers |
Intercept, modify, or block every request and response flowing through your server. Add rate limiting, custom logging, input sanitisation, or request transformation — all in one place.
@mcp.middleware async def audit_logger(request, call_next): # Log every tool call with metadata logger.info(f"Tool call: {request.tool} | User: {request.context.user_id}") response = await call_next(request) logger.info(f"Tool result: {response.status}") return response
Your server can ask the user a question mid-execution — structured forms, confirmation dialogs, approvals. The conversation pauses, the user responds, your tool continues. Think "human in the loop" workflows.
@mcp.tool async def delete_campaign(campaign_id: str, ctx: Context): """Delete a campaign after confirmation.""" result = await ctx.elicit( message=f"Delete campaign {campaign_id}? This can't be undone.", response_type=ConfirmOrDeny, ) if result.action == "confirm": db.delete(campaign_id) return "Deleted."
A FastMCP server can make its own LLM calls back to the host model. This enables agentic tools that reason, classify, summarise, or chain LLM calls — entirely server-side, no separate API keys needed.
@mcp.tool async def classify_ticket(ticket_text: str, ctx: Context) -> str: result = await ctx.sample(f"Classify this support ticket: {ticket_text}") return result.text # LLM did the classification
Built-in auth for production deployments. Supports OAuth 2.0, Bearer tokens, API keys, and JWT. Integrates with Auth0, Clerk, Supabase, and custom providers.
Mount multiple FastMCP servers under namespaces to build federated tool registries. A master server can aggregate tools from five sub-servers, with automatic namespace collision handling.
master = FastMCP("Master") master.mount("/crm", crm_server) # tools exposed as crm_get_contact, etc. master.mount("/hr", hr_server) master.mount("/ops", ops_server)
Programmatically modify tool schemas or filter results before they reach the LLM. Strip sensitive fields, rename parameters for better AI understanding, add descriptions dynamically.
Run code on startup/shutdown — initialise database connections, load ML models, warm caches. Inject shared resources into tools via a typed dependency system (similar to FastAPI's Depends).
@asynccontextmanager async def lifespan(server: FastMCP): db = await connect_database() yield {"db": db} # injected into all tools await db.close() mcp = FastMCP("MyServer", lifespan=lifespan)
This is FastMCP's most distinctive capability. MCP tools normally return text. FastMCP Apps let tools return interactive UIs rendered directly inside the conversation window — charts the user can hover over, forms that submit data, sortable tables, dashboards with live state.
You write pure Python. The host renders the component library (Prefab UI). No frontend skills required.
app=True to any tool and return Prefab components — charts, tables, progress bars, metrics cards, forms, toggles. Python declarative syntax, interactive output. No JavaScript.# Prefab App — Revenue chart in ~10 lines of Python @mcp.tool(app=True) def revenue_dashboard(year: int) -> PrefabApp: """Show annual revenue as an interactive bar chart.""" data = db.get_revenue(year) with Column(gap=4, css_class="p-6") as view: Heading(f"{year} Revenue") BarChart(data=data, series=[ChartSeries(data_key="revenue")], x_axis="quarter") DataTable(data=data) return PrefabApp(view=view)
fastmcp dev apps server.py launches a browser preview at localhost:8080 with auto-reload, MCP inspector, and live JSON-RPC traffic view. No host client needed. Build and test UIs before connecting to Claude.
FastMCP's client layer lets you call any MCP server programmatically — from scripts, workflows, or other agents. Handles transports, auth, and protocol lifecycle automatically.
async with Client("https://gofastmcp.com/mcp") as client: result = await client.call_tool("search", {"query": "FastMCP deployment"}) resources = await client.list_resources() # Full protocol access — tools, resources, prompts
| Capability | Raw MCP | FastMCP |
|---|---|---|
| Setup | Manual schema, transport, lifecycle code | One decorator, done |
| Interactive UI | Not supported | ✅ Prefab Apps, Generative UI, Custom HTML |
| Long-running ops | Blocks the client | ✅ Background tasks with progress + Redis backend |
| Auth | Build from scratch | ✅ OAuth / Bearer / JWT built-in, Auth0/Clerk integrations |
| Middleware | Manual wrapping | ✅ Declarative intercept layer for all calls |
| Asking the user | Not supported | ✅ Elicitation — pause mid-tool for structured user input |
| LLM calls from server | Separate API key / complexity | ✅ Sampling — call the host LLM from within any tool |
| Multi-server | Manual routing | ✅ Composition — mount servers under namespaces |
| Deployment | DIY | ✅ Prefect Horizon (free), Docker, any cloud |
| Testing | Complex mock setup | ✅ Built-in testing utilities |