FastMCP (standalone)
The dominant Python framework for building MCP servers and clients. FastMCP 1.0 was incorporated into the official mcp package in 2024, but the standalone project continued evolving independently. Now maintained by Prefect (PrefectHQ/fastmcp), v3.0 shipped February 2026 as a major breaking rewrite. ~1M daily downloads. Powers ~70% of MCP servers across all languages. Critical: minor versions may contain breaking changes — pin aggressively.
Warnings
- breaking v3.0 (February 2026) is a major breaking rewrite from v2.x. Anyone not pinning fastmcp was auto-upgraded to v3.0 on pip install. Major changes: provider architecture replaces direct component registration, ctx.set_state()/ctx.get_state() are now async, StreamableHttpTransport replaces older HTTP transport classes, auth providers no longer auto-load config.
- breaking In v3, @mcp.tool decorator returns the original function unchanged (so decorated functions remain directly callable). In v2.x, @mcp.tool returned a FunctionTool object. Code accessing .name, .description, or other FunctionTool attributes on the decorated result will break.
- breaking Transport config (host, port) must be passed to mcp.run(), not the FastMCP() constructor. Passing them to the constructor raises TypeError.
- breaking fastmcp.server.auth module (introduced v2.12.0) is explicitly exempt from semantic versioning stability guarantees and has breaking changes on minor versions. Auth API changed significantly in v3.
- breaking GitHub repository moved from jlowin/fastmcp to PrefectHQ/fastmcp with v3.0. Old GitHub links forward automatically. PyPI package name, import paths, and CLI commands are unchanged.
- gotcha fastmcp includes the mcp package as a dependency — installing both separately can cause version conflicts if mcp is pinned independently. fastmcp pins its compatible mcp version internally.
- gotcha Minor versions may contain breaking changes (explicitly documented in release policy). 'Semantic versioning is pragmatic' — do not assume minor bumps are safe without checking release notes.
- gotcha fastmcp and the mcp SDK's bundled FastMCP 1.0 (from mcp.server.fastmcp) have the same class name but different behavior. Mixing imports in one project causes silent behavioral differences.
- gotcha CVE-2026-24486 (python-multipart) and CVE-2026-0994 (protobuf) were patched in fastmcp 3.0.2. Earlier 3.x and 2.x versions are vulnerable.
Install
-
pip install fastmcp -
pip install 'fastmcp<3' -
pip install 'fastmcp[openai]' -
pip install 'fastmcp[anthropic]'
Imports
- FastMCP (v2 and v3 — same import path)
from fastmcp import FastMCP mcp = FastMCP('My Server') @mcp.tool def add(a: int, b: int) -> int: """Add two numbers""" return a + b mcp.run() - Client
from fastmcp import Client async with Client('http://localhost:8000/mcp') as client: tools = await client.list_tools() result = await client.call_tool('add', {'a': 1, 'b': 2})
Quickstart
# Server
from fastmcp import FastMCP
mcp = FastMCP('Demo')
@mcp.tool
def add(a: int, b: int) -> int:
"""Add two numbers"""
return a + b
@mcp.resource('data://{name}')
def get_data(name: str) -> str:
"""Fetch named data"""
return f'Data for {name}'
@mcp.prompt
def review(code: str) -> str:
return f'Review this code:\n{code}'
if __name__ == '__main__':
mcp.run() # stdio by default
# mcp.run(transport='http', host='0.0.0.0', port=8000) # remote
# ---
# Client
import asyncio
from fastmcp import Client
async def main():
async with Client('http://localhost:8000/mcp') as client:
tools = await client.list_tools()
result = await client.call_tool('add', {'a': 1, 'b': 2})
print(result)
asyncio.run(main())
# ---
# CLI usage
# fastmcp list http://localhost:8000/mcp # list tools on any server
# fastmcp call http://localhost:8000/mcp add a=1 b=2 # call a tool
# fastmcp discover # find all locally configured servers