fastmcp

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

FastMCP - Build MCP Servers in Python

FastMCP - 在Python中构建MCP服务器

FastMCP is a Python framework for building Model Context Protocol (MCP) servers that expose tools, resources, and prompts to Large Language Models like Claude. This skill provides production-tested patterns, error prevention, and deployment strategies for building robust MCP servers.
FastMCP是一个Python框架,用于构建模型上下文协议(MCP)服务器,向Claude等大语言模型(LLM)暴露工具、资源和提示词。本技能提供经过生产验证的模式、错误预防方案以及部署策略,帮助你构建稳健的MCP服务器。

Quick Start

快速开始

Installation

安装

bash
pip install fastmcp
bash
pip install fastmcp

or

uv pip install fastmcp
undefined
uv pip install fastmcp
undefined

Minimal Server

最简服务器示例

python
from fastmcp import FastMCP
python
from fastmcp import FastMCP

MUST be at module level for FastMCP Cloud

必须在模块级别定义,以支持FastMCP Cloud

mcp = FastMCP("My Server")
@mcp.tool() async def hello(name: str) -> str: """Say hello to someone.""" return f"Hello, {name}!"
if name == "main": mcp.run()

**Run it:**
```bash
mcp = FastMCP("My Server")
@mcp.tool() async def hello(name: str) -> str: """向某人打招呼。""" return f"Hello, {name}!"
if name == "main": mcp.run()

**运行方式:**
```bash

Local development

本地开发

python server.py
python server.py

With FastMCP CLI

使用FastMCP CLI

fastmcp dev server.py
fastmcp dev server.py

HTTP mode

HTTP模式

python server.py --transport http --port 8000
undefined
python server.py --transport http --port 8000
undefined

What's New in v2.14.x (December 2025)

v2.14.x版本新特性(2025年12月)

v2.14.2 (December 31, 2024)

v2.14.2(2024年12月31日)

  • MCP SDK pinned to <2.x for compatibility
  • Supabase provider gains
    auth_route
    parameter
  • Bug fixes: outputSchema
    $ref
    resolution, OAuth Proxy validation, OpenAPI 3.1 support
  • MCP SDK固定为<2.x版本以保证兼容性
  • Supabase提供新增
    auth_route
    参数
  • 修复问题:outputSchema的
    $ref
    解析、OAuth代理验证、OpenAPI 3.1支持

v2.14.1: Sampling with Tools (SEP-1577)

v2.14.1:工具调用采样(SEP-1577)

  • ctx.sample()
    now accepts tools
    for agentic workflows
  • AnthropicSamplingHandler
    promoted from experimental
  • ctx.sample_step()
    for single LLM call returning
    SampleStep
  • Python 3.13 support added
  • ctx.sample()
    现在支持传入工具
    ,适用于智能体工作流
  • AnthropicSamplingHandler
    从实验特性转为正式特性
  • ctx.sample_step()
    用于单次LLM调用,返回
    SampleStep
    对象
  • 新增Python 3.13支持

v2.14.0: Background Tasks (SEP-1686)

v2.14.0:后台任务(SEP-1686)

  • Protocol-native background tasks for long-running operations
  • Add
    task=True
    to async decorators; progress tracking without blocking
  • MCP 2025-11-25 specification support
  • SEP-1699: SSE polling and event resumability
  • SEP-1330: Multi-select enum elicitation schemas
  • SEP-1034: Default values for elicitation schemas
⚠️ Breaking Changes (v2.14.0):
  • BearerAuthProvider
    module removed (use
    JWTVerifier
    or
    OAuthProxy
    )
  • Context.get_http_request()
    method removed
  • fastmcp.Image
    top-level import removed (use
    from fastmcp.utilities import Image
    )
  • enable_docket
    ,
    enable_tasks
    settings removed (always enabled)
  • run_streamable_http_async()
    ,
    sse_app()
    ,
    streamable_http_app()
    ,
    run_sse_async()
    methods removed
  • dependencies
    parameter removed from decorators
  • output_schema=False
    support eliminated
  • FASTMCP_SERVER_
    environment variable prefix deprecated
Known Compatibility:
  • MCP SDK pinned to <2.x (v2.14.2+)
  • 协议原生后台任务,支持长时间运行的操作
  • 异步装饰器添加
    task=True
    参数;支持进度追踪且不阻塞主线程
  • 支持MCP 2025-11-25规范
  • SEP-1699:SSE轮询和事件可恢复性
  • SEP-1330:多选枚举启发式模式
  • SEP-1034:启发式模式默认值
⚠️ v2.14.0破坏性变更:
  • 移除
    BearerAuthProvider
    模块(使用
    JWTVerifier
    OAuthProxy
    替代)
  • 移除
    Context.get_http_request()
    方法
  • 移除
    fastmcp.Image
    顶层导入(使用
    from fastmcp.utilities import Image
    替代)
  • 移除
    enable_docket
    enable_tasks
    配置项(默认始终启用)
  • 移除
    run_streamable_http_async()
    sse_app()
    streamable_http_app()
    run_sse_async()
    方法
  • 移除装饰器中的
    dependencies
    参数
  • 取消对
    output_schema=False
    的支持
  • 弃用
    FASTMCP_SERVER_
    环境变量前缀
已知兼容性:
  • MCP SDK固定为<2.x版本(v2.14.2及以上)

What's New in v3.0.0 (Beta - January 2026)

v3.0.0版本新特性(测试版 - 2026年1月)

⚠️ MAJOR BREAKING CHANGES - FastMCP 3.0 is a complete architectural refactor.
⚠️ 重大破坏性变更 - FastMCP 3.0是一次完整的架构重构。

Provider Architecture

提供器架构

All components now sourced via Providers:
  • FileSystemProvider
    - Discover decorated functions from directories with hot-reload
  • SkillsProvider
    - Expose agent skill files as MCP resources
  • OpenAPIProvider
    - Auto-generate from OpenAPI specs
  • ProxyProvider
    - Proxy to remote MCP servers
python
from fastmcp import FastMCP
from fastmcp.providers import FileSystemProvider

mcp = FastMCP("server")
mcp.add_provider(FileSystemProvider(path="./tools", reload=True))
所有组件现在通过提供器获取:
  • FileSystemProvider
    - 从目录中发现装饰函数,支持热重载
  • SkillsProvider
    - 将智能体技能文件暴露为MCP资源
  • OpenAPIProvider
    - 从OpenAPI规范自动生成
  • ProxyProvider
    - 代理到远程MCP服务器
python
from fastmcp import FastMCP
from fastmcp.providers import FileSystemProvider

mcp = FastMCP("server")
mcp.add_provider(FileSystemProvider(path="./tools", reload=True))

Transforms (Component Middleware)

转换(组件中间件)

Modify components without changing source code:
  • Namespace, rename, filter by version
  • ResourcesAsTools
    - Expose resources as tools
  • PromptsAsTools
    - Expose prompts as tools
python
from fastmcp.transforms import Namespace, VersionFilter

mcp.add_transform(Namespace(prefix="api"))
mcp.add_transform(VersionFilter(min_version="2.0"))
无需修改源代码即可修改组件:
  • 命名空间、重命名、按版本过滤
  • ResourcesAsTools
    - 将资源暴露为工具
  • PromptsAsTools
    - 将提示词暴露为工具
python
from fastmcp.transforms import Namespace, VersionFilter

mcp.add_transform(Namespace(prefix="api"))
mcp.add_transform(VersionFilter(min_version="2.0"))

Component Versioning

组件版本控制

python
@mcp.tool(version="2.0")
async def fetch_data(query: str) -> dict:
    # Clients see highest version by default
    # Can request specific version
    return {"data": [...]}
python
@mcp.tool(version="2.0")
async def fetch_data(query: str) -> dict:
    # 客户端默认使用最高版本
    # 也可以请求特定版本
    return {"data": [...]}

Session-Scoped State

会话级状态

python
@mcp.tool()
async def set_preference(key: str, value: str, ctx: Context) -> dict:
    await ctx.set_state(key, value)  # Persists across session
    return {"saved": True}

@mcp.tool()
async def get_preference(key: str, ctx: Context) -> dict:
    value = await ctx.get_state(key, default=None)
    return {"value": value}
python
@mcp.tool()
async def set_preference(key: str, value: str, ctx: Context) -> dict:
    await ctx.set_state(key, value)  # 在会话中持久化
    return {"saved": True}

@mcp.tool()
async def get_preference(key: str, ctx: Context) -> dict:
    value = await ctx.get_state(key, default=None)
    return {"value": value}

Other Features

其他特性

  • --reload
    flag for auto-restart during development
  • Automatic threadpool dispatch for sync functions
  • Tool timeouts
  • OpenTelemetry tracing
  • Component authorization:
    @tool(auth=require_scopes("admin"))
  • --reload
    标志,开发时自动重启服务器
  • 自动为同步函数分配线程池
  • 工具超时机制
  • OpenTelemetry追踪
  • 组件授权:
    @tool(auth=require_scopes("admin"))

Migration Guide

迁移指南

Pin to v2 if not ready:
undefined
若未准备好升级,固定到v2版本:
undefined

requirements.txt

requirements.txt

fastmcp<3

**For most servers**, updating the import is all you need:
```python
fastmcp<3

**对于大多数服务器**,只需更新导入语句即可兼容:
```python

v2.x and v3.0 compatible

兼容v2.x和v3.0版本

from fastmcp import FastMCP
mcp = FastMCP("server")
from fastmcp import FastMCP
mcp = FastMCP("server")

... rest of code works the same

... 其余代码保持不变


**See**: [Official Migration Guide](https://github.com/jlowin/fastmcp/blob/main/docs/development/upgrade-guide.mdx)

---

**参考**: [官方迁移指南](https://github.com/jlowin/fastmcp/blob/main/docs/development/upgrade-guide.mdx)

---

Core Concepts

核心概念

Tools

工具

Functions LLMs can call. Best practices: Clear names, comprehensive docstrings (LLMs read these!), strong type hints (Pydantic validates), structured returns, error handling.
python
@mcp.tool()
async def async_tool(url: str) -> dict:  # Use async for I/O
    async with httpx.AsyncClient() as client:
        return (await client.get(url)).json()
LLM可以调用的函数。最佳实践:清晰的命名、全面的文档字符串(LLM会读取这些内容!)、强类型提示(Pydantic会验证)、结构化返回、错误处理。
python
@mcp.tool()
async def async_tool(url: str) -> dict:  # I/O操作使用async
    async with httpx.AsyncClient() as client:
        return (await client.get(url)).json()

Resources

资源

Expose data to LLMs. URI schemes:
data://
,
file://
,
resource://
,
info://
,
api://
, or custom.
python
@mcp.resource("user://{user_id}/profile")  # Template with parameters
async def get_user(user_id: str) -> dict:  # CRITICAL: param names must match
    return await fetch_user_from_db(user_id)
向LLM暴露数据。URI方案:
data://
file://
resource://
info://
api://
或自定义方案。
python
@mcp.resource("user://{user_id}/profile")  # 带参数的模板
async def get_user(user_id: str) -> dict:  # 关键:参数名称必须与模板匹配
    return await fetch_user_from_db(user_id)

Prompts

提示词

Pre-configured prompts with parameters.
python
@mcp.prompt("analyze")
def analyze_prompt(topic: str) -> str:
    return f"Analyze {topic} considering: state, challenges, opportunities, recommendations."
带参数的预配置提示词。
python
@mcp.prompt("analyze")
def analyze_prompt(topic: str) -> str:
    return f"分析{topic},需涵盖:现状、挑战、机遇、建议。"

Context Features

上下文特性

Inject
Context
parameter (with type hint!) for advanced features:
Elicitation (User Input):
python
from fastmcp import Context

@mcp.tool()
async def confirm_action(action: str, context: Context) -> dict:
    confirmed = await context.request_elicitation(prompt=f"Confirm {action}?", response_type=str)
    return {"status": "completed" if confirmed.lower() == "yes" else "cancelled"}
Progress Tracking:
python
@mcp.tool()
async def batch_import(file_path: str, context: Context) -> dict:
    data = await read_file(file_path)
    for i, item in enumerate(data):
        await context.report_progress(i + 1, len(data), f"Importing {i + 1}/{len(data)}")
        await import_item(item)
    return {"imported": len(data)}
Sampling (LLM calls from tools):
python
@mcp.tool()
async def enhance_text(text: str, context: Context) -> str:
    response = await context.request_sampling(
        messages=[{"role": "user", "content": f"Enhance: {text}"}],
        temperature=0.7
    )
    return response["content"]
注入
Context
参数(必须带类型提示!)以使用高级特性:
启发式交互(用户输入):
python
from fastmcp import Context

@mcp.tool()
async def confirm_action(action: str, context: Context) -> dict:
    confirmed = await context.request_elicitation(prompt=f"确认执行{action}?", response_type=str)
    return {"status": "已完成" if confirmed.lower() == "yes" else "已取消"}
进度追踪:
python
@mcp.tool()
async def batch_import(file_path: str, context: Context) -> dict:
    data = await read_file(file_path)
    for i, item in enumerate(data):
        await context.report_progress(i + 1, len(data), f"正在导入第{i + 1}/{len(data)}项")
        await import_item(item)
    return {"已导入": len(data)}
采样(从工具中调用LLM):
python
@mcp.tool()
async def enhance_text(text: str, context: Context) -> str:
    response = await context.request_sampling(
        messages=[{"role": "user", "content": f"优化以下文本:{text}"}],
        temperature=0.7
    )
    return response["content"]

Background Tasks (v2.14.0+)

后台任务(v2.14.0+)

Long-running operations that report progress without blocking clients. Uses Docket task scheduler (always enabled in v2.14.0+).
Basic Usage:
python
@mcp.tool(task=True)  # Enable background task mode
async def analyze_large_dataset(dataset_id: str, context: Context) -> dict:
    """Analyze large dataset with progress tracking."""
    data = await fetch_dataset(dataset_id)

    for i, chunk in enumerate(data.chunks):
        # Report progress to client
        await context.report_progress(
            current=i + 1,
            total=len(data.chunks),
            message=f"Processing chunk {i + 1}/{len(data.chunks)}"
        )
        await process_chunk(chunk)

    return {"status": "complete", "records_processed": len(data)}
Task States:
pending
running
completed
/
failed
/
cancelled
When to Use:
  • Operations taking >30 seconds (LLM timeout risk)
  • Batch processing with per-item status updates
  • Operations that may need user input mid-execution
  • Long-running API calls or data processing
Known Limitation (v2.14.x):
  • statusMessage
    from
    ctx.report_progress()
    is not forwarded to clients during background task polling (GitHub Issue #2904)
  • Progress messages appear in server logs but not in client UI
  • Workaround: Use official MCP SDK (
    mcp>=1.10.0
    ) instead of FastMCP for now
  • Status: Fix pending in PR #2906
Important: Tasks execute through Docket scheduler. Cannot execute tasks through proxies (will raise error).
支持长时间运行的操作,可报告进度且不阻塞客户端。使用Docket任务调度器(v2.14.0+默认始终启用)。
基本用法:
python
@mcp.tool(task=True)  # 启用后台任务模式
async def analyze_large_dataset(dataset_id: str, context: Context) -> dict:
    """分析大型数据集并追踪进度。"""
    data = await fetch_dataset(dataset_id)

    for i, chunk in enumerate(data.chunks):
        # 向客户端报告进度
        await context.report_progress(
            current=i + 1,
            total=len(data.chunks),
            message=f"正在处理第{i + 1}/{len(data.chunks)}个数据块"
        )
        await process_chunk(chunk)

    return {"状态": "完成", "已处理记录数": len(data)}
任务状态:
pending
(待处理)→
running
(运行中)→
completed
(已完成)/
failed
(失败)/
cancelled
(已取消)
适用场景:
  • 耗时超过30秒的操作(存在LLM超时风险)
  • 带逐项状态更新的批量处理
  • 执行过程中可能需要用户输入的操作
  • 长时间运行的API调用或数据处理
已知限制(v2.14.x):
  • ctx.report_progress()
    中的
    statusMessage
    在后台任务轮询时不会转发给客户端(GitHub Issue #2904
  • 进度消息会出现在服务器日志中,但不会显示在客户端UI
  • 临时解决方案:暂时使用官方MCP SDK(
    mcp>=1.10.0
    )替代FastMCP
  • 状态:修复方案正在PR #2906中处理
重要提示:任务通过Docket调度器执行。无法通过代理执行任务(会触发错误)。

Sampling with Tools (v2.14.1+)

工具调用采样(v2.14.1+)

Servers can pass tools to
ctx.sample()
for agentic workflows where the LLM can call tools during sampling.
Agentic Sampling:
python
from fastmcp import Context
from fastmcp.sampling import AnthropicSamplingHandler
服务器可以将工具传递给
ctx.sample()
,实现智能体工作流,让LLM在采样过程中调用工具。
智能体采样示例:
python
from fastmcp import Context
from fastmcp.sampling import AnthropicSamplingHandler

Configure sampling handler

配置采样处理器

mcp = FastMCP("Agent Server") mcp.add_sampling_handler(AnthropicSamplingHandler(api_key=os.getenv("ANTHROPIC_API_KEY")))
@mcp.tool() async def research_topic(topic: str, context: Context) -> dict: """Research a topic using agentic sampling with tools."""
# Define tools available during sampling
research_tools = [
    {
        "name": "search_web",
        "description": "Search the web for information",
        "inputSchema": {"type": "object", "properties": {"query": {"type": "string"}}}
    },
    {
        "name": "fetch_url",
        "description": "Fetch content from a URL",
        "inputSchema": {"type": "object", "properties": {"url": {"type": "string"}}}
    }
]

# Sample with tools - LLM can call these tools during reasoning
result = await context.sample(
    messages=[{"role": "user", "content": f"Research: {topic}"}],
    tools=research_tools,
    max_tokens=4096
)

return {"research": result.content, "tools_used": result.tool_calls}

**Single-Step Sampling:**
```python
@mcp.tool()
async def get_single_response(prompt: str, context: Context) -> dict:
    """Get a single LLM response without tool loop."""

    # sample_step() returns SampleStep for inspection
    step = await context.sample_step(
        messages=[{"role": "user", "content": prompt}],
        temperature=0.7
    )

    return {
        "content": step.content,
        "model": step.model,
        "stop_reason": step.stop_reason
    }
Sampling Handlers:
  • AnthropicSamplingHandler
    - For Claude models (v2.14.1+)
  • OpenAISamplingHandler
    - For GPT models
Known Limitation:
ctx.sample()
works when client connects to a single server but fails with "Sampling not supported" error when multiple servers are configured in client. Tools without sampling work fine. (Community-sourced finding)
mcp = FastMCP("Agent Server") mcp.add_sampling_handler(AnthropicSamplingHandler(api_key=os.getenv("ANTHROPIC_API_KEY")))
@mcp.tool() async def research_topic(topic: str, context: Context) -> dict: """使用带工具的智能体采样研究主题。"""
# 定义采样过程中可用的工具
research_tools = [
    {
        "name": "search_web",
        "description": "在网络上搜索信息",
        "inputSchema": {"type": "object", "properties": {"query": {"type": "string"}}}
    },
    {
        "name": "fetch_url",
        "description": "获取URL中的内容",
        "inputSchema": {"type": "object", "properties": {"url": {"type": "string"}}}
    }
]

# 带工具的采样 - LLM可以在推理过程中调用这些工具
result = await context.sample(
    messages=[{"role": "user", "content": f"研究主题:{topic}"}],
    tools=research_tools,
    max_tokens=4096
)

return {"研究结果": result.content, "使用的工具": result.tool_calls}

**单步采样:**
```python
@mcp.tool()
async def get_single_response(prompt: str, context: Context) -> dict:
    """获取单次LLM响应,无工具循环。"""

    # sample_step()返回SampleStep对象供检查
    step = await context.sample_step(
        messages=[{"role": "user", "content": prompt}],
        temperature=0.7
    )

    return {
        "内容": step.content,
        "模型": step.model,
        "停止原因": step.stop_reason
    }
采样处理器:
  • AnthropicSamplingHandler
    - 用于Claude模型(v2.14.1+)
  • OpenAISamplingHandler
    - 用于GPT模型
已知限制: 当客户端连接到单个服务器时
ctx.sample()
可以正常工作,但当客户端配置了多个服务器时会抛出“采样不支持”错误。不带采样的工具可以正常工作。(社区发现问题

Storage Backends

存储后端

Built on
py-key-value-aio
for OAuth tokens, response caching, persistent state.
Available Backends:
  • Memory (default): Ephemeral, fast, dev-only
  • Disk: Persistent, encrypted with
    FernetEncryptionWrapper
    , platform-aware (Mac/Windows default)
  • Redis: Distributed, production, multi-instance
  • Others: DynamoDB, MongoDB, Elasticsearch, Memcached, RocksDB, Valkey
Basic Usage:
python
from key_value.stores import DiskStore, RedisStore
from key_value.encryption import FernetEncryptionWrapper
from cryptography.fernet import Fernet
基于
py-key-value-aio
构建,用于存储OAuth令牌、响应缓存、持久化状态。
可用后端:
  • 内存存储(默认):临时存储,速度快,仅适用于开发环境
  • 磁盘存储:持久化存储,使用
    FernetEncryptionWrapper
    加密,适配不同平台(Mac/Windows默认使用)
  • Redis存储:分布式存储,适用于生产环境、多实例部署
  • 其他存储:DynamoDB、MongoDB、Elasticsearch、Memcached、RocksDB、Valkey
基本用法:
python
from key_value.stores import DiskStore, RedisStore
from key_value.encryption import FernetEncryptionWrapper
from cryptography.fernet import Fernet

Disk (persistent, single instance)

磁盘存储(持久化,单实例)

mcp = FastMCP("Server", storage=DiskStore(path="/app/data/storage"))
mcp = FastMCP("Server", storage=DiskStore(path="/app/data/storage"))

Redis (distributed, production)

Redis存储(分布式,生产环境)

mcp = FastMCP("Server", storage=RedisStore( host=os.getenv("REDIS_HOST"), password=os.getenv("REDIS_PASSWORD") ))
mcp = FastMCP("Server", storage=RedisStore( host=os.getenv("REDIS_HOST"), password=os.getenv("REDIS_PASSWORD") ))

Encrypted storage (recommended)

加密存储(推荐)

mcp = FastMCP("Server", storage=FernetEncryptionWrapper( key_value=DiskStore(path="/app/data"), fernet=Fernet(os.getenv("STORAGE_ENCRYPTION_KEY")) ))

**Platform Defaults:** Mac/Windows use Disk, Linux uses Memory. Override with `storage` parameter.
mcp = FastMCP("Server", storage=FernetEncryptionWrapper( key_value=DiskStore(path="/app/data"), fernet=Fernet(os.getenv("STORAGE_ENCRYPTION_KEY")) ))

**平台默认值:** Mac/Windows使用磁盘存储,Linux使用内存存储。可通过`storage`参数覆盖默认设置。

Server Lifespans

服务器生命周期

⚠️ Breaking Change in v2.13.0: Lifespan behavior changed from per-session to per-server-instance.
Initialize/cleanup resources once per server (NOT per session) - critical for DB connections, API clients.
python
from contextlib import asynccontextmanager
from dataclasses import dataclass

@dataclass
class AppContext:
    db: Database
    api_client: httpx.AsyncClient

@asynccontextmanager
async def app_lifespan(server: FastMCP):
    """Runs ONCE per server instance."""
    db = await Database.connect(os.getenv("DATABASE_URL"))
    api_client = httpx.AsyncClient(base_url=os.getenv("API_BASE_URL"), timeout=30.0)

    try:
        yield AppContext(db=db, api_client=api_client)
    finally:
        await db.disconnect()
        await api_client.aclose()

mcp = FastMCP("Server", lifespan=app_lifespan)
⚠️ v2.13.0中的破坏性变更:生命周期行为从每个会话执行一次改为每个服务器实例执行一次。
在服务器启动时初始化资源,关闭时清理资源(而非每个会话执行一次)- 这对于数据库连接、API客户端等资源至关重要。
python
from contextlib import asynccontextmanager
from dataclasses import dataclass

@dataclass
class AppContext:
    db: Database
    api_client: httpx.AsyncClient

@asynccontextmanager
async def app_lifespan(server: FastMCP):
    """每个服务器实例仅执行一次。"""
    db = await Database.connect(os.getenv("DATABASE_URL"))
    api_client = httpx.AsyncClient(base_url=os.getenv("API_BASE_URL"), timeout=30.0)

    try:
        yield AppContext(db=db, api_client=api_client)
    finally:
        await db.disconnect()
        await api_client.aclose()

mcp = FastMCP("Server", lifespan=app_lifespan)

Access in tools

在工具中访问

@mcp.tool() async def query_db(sql: str, context: Context) -> list: app_ctx = context.fastmcp_context.lifespan_context return await app_ctx.db.query(sql)

**ASGI Integration (FastAPI/Starlette):**
```python
mcp = FastMCP("Server", lifespan=mcp_lifespan)
app = FastAPI(lifespan=mcp.lifespan)  # ✅ MUST pass lifespan!
State Management:
python
context.fastmcp_context.set_state(key, value)  # Store
context.fastmcp_context.get_state(key, default=None)  # Retrieve
@mcp.tool() async def query_db(sql: str, context: Context) -> list: app_ctx = context.fastmcp_context.lifespan_context return await app_ctx.db.query(sql)

**ASGI集成(FastAPI/Starlette):**
```python
mcp = FastMCP("Server", lifespan=mcp_lifespan)
app = FastAPI(lifespan=mcp.lifespan)  # ✅ 必须传递lifespan!
状态管理:
python
context.fastmcp_context.set_state(key, value)  # 存储
context.fastmcp_context.get_state(key, default=None)  # 检索

Middleware System

中间件系统

8 Built-in Types: TimingMiddleware, ResponseCachingMiddleware, LoggingMiddleware, RateLimitingMiddleware, ErrorHandlingMiddleware, ToolInjectionMiddleware, PromptToolMiddleware, ResourceToolMiddleware
Execution Order (order matters!):
Request Flow:
  → ErrorHandlingMiddleware (catches errors)
    → TimingMiddleware (starts timer)
      → LoggingMiddleware (logs request)
        → RateLimitingMiddleware (checks rate limit)
          → ResponseCachingMiddleware (checks cache)
            → Tool/Resource Handler
Basic Usage:
python
from fastmcp.middleware import ErrorHandlingMiddleware, TimingMiddleware, LoggingMiddleware

mcp.add_middleware(ErrorHandlingMiddleware())  # First: catch errors
mcp.add_middleware(TimingMiddleware())         # Second: time requests
mcp.add_middleware(LoggingMiddleware(level="INFO"))
mcp.add_middleware(RateLimitingMiddleware(max_requests=100, window_seconds=60))
mcp.add_middleware(ResponseCachingMiddleware(ttl_seconds=300, storage=RedisStore()))
Custom Middleware:
python
from fastmcp.middleware import BaseMiddleware

class AccessControlMiddleware(BaseMiddleware):
    async def on_call_tool(self, tool_name, arguments, context):
        user = context.fastmcp_context.get_state("user_id")
        if user not in self.allowed_users:
            raise PermissionError(f"User not authorized")
        return await self.next(tool_name, arguments, context)
Hook Hierarchy:
on_message
(all) →
on_request
/
on_notification
on_call_tool
/
on_read_resource
/
on_get_prompt
on_list_*
(list operations)
8种内置中间件类型: TimingMiddleware(计时中间件)、ResponseCachingMiddleware(响应缓存中间件)、LoggingMiddleware(日志中间件)、RateLimitingMiddleware(限流中间件)、ErrorHandlingMiddleware(错误处理中间件)、ToolInjectionMiddleware(工具注入中间件)、PromptToolMiddleware(提示词工具中间件)、ResourceToolMiddleware(资源工具中间件)
执行顺序(顺序至关重要!):
请求流程:
  → ErrorHandlingMiddleware(捕获错误)
    → TimingMiddleware(启动计时)
      → LoggingMiddleware(记录请求)
        → RateLimitingMiddleware(检查限流)
          → ResponseCachingMiddleware(检查缓存)
            → 工具/资源处理器
基本用法:
python
from fastmcp.middleware import ErrorHandlingMiddleware, TimingMiddleware, LoggingMiddleware

mcp.add_middleware(ErrorHandlingMiddleware())  # 第一个:捕获错误
mcp.add_middleware(TimingMiddleware())         # 第二个:计时请求
mcp.add_middleware(LoggingMiddleware(level="INFO"))
mcp.add_middleware(RateLimitingMiddleware(max_requests=100, window_seconds=60))
mcp.add_middleware(ResponseCachingMiddleware(ttl_seconds=300, storage=RedisStore()))
自定义中间件:
python
from fastmcp.middleware import BaseMiddleware

class AccessControlMiddleware(BaseMiddleware):
    async def on_call_tool(self, tool_name, arguments, context):
        user = context.fastmcp_context.get_state("user_id")
        if user not in self.allowed_users:
            raise PermissionError(f"用户未授权")
        return await self.next(tool_name, arguments, context)
钩子层级:
on_message
(所有请求)→
on_request
/
on_notification
on_call_tool
/
on_read_resource
/
on_get_prompt
on_list_*
(列表操作)

Server Composition

服务器组合

Two Strategies:
  1. import_server()
    - Static snapshot: One-time copy at import, changes don't propagate, fast (no runtime delegation). Use for: Finalized component bundles.
  2. mount()
    - Dynamic link: Live runtime link, changes immediately visible, runtime delegation (slower). Use for: Modular runtime composition.
Basic Usage:
python
undefined
两种策略:
  1. import_server()
    - 静态快照:导入时一次性复制,后续变更不会同步,速度快(无运行时委托)。适用场景:已定型的组件包。
  2. mount()
    - 动态链接:运行时实时链接,变更立即生效,运行时委托(速度较慢)。适用场景:模块化运行时组合。
基本用法:
python
undefined

Import (static)

导入(静态)

main_server.import_server(api_server) # One-time copy
main_server.import_server(api_server) # 一次性复制

Mount (dynamic)

挂载(动态)

main_server.mount(api_server, prefix="api") # Tools: api.fetch_data main_server.mount(db_server, prefix="db") # Resources: resource://db/path

**Tag Filtering:**
```python
@api_server.tool(tags=["public"])
def public_api(): pass

main_server.import_server(api_server, include_tags=["public"])  # Only public
main_server.mount(api_server, prefix="api", exclude_tags=["admin"])  # No admin
Resource Prefix Formats:
  • Path (default since v2.4.0):
    resource://prefix/path
  • Protocol (legacy):
    prefix+resource://path
python
main_server.mount(subserver, prefix="api", resource_prefix_format="path")
main_server.mount(api_server, prefix="api") # 工具路径:api.fetch_data main_server.mount(db_server, prefix="db") # 资源路径:resource://db/path

**标签过滤:**
```python
@api_server.tool(tags=["public"])
def public_api(): pass

main_server.import_server(api_server, include_tags=["public"])  # 仅导入公共工具
main_server.mount(api_server, prefix="api", exclude_tags=["admin"])  # 排除管理员工具
资源前缀格式:
  • 路径格式(v2.4.0起默认):
    resource://prefix/path
  • 协议格式(旧版):
    prefix+resource://path
python
main_server.mount(subserver, prefix="api", resource_prefix_format="path")

OAuth & Authentication

OAuth与身份认证

4 Authentication Patterns:
  1. Token Validation (
    JWTVerifier
    ): Validate external tokens
  2. External Identity Providers (
    RemoteAuthProvider
    ): OAuth 2.0/OIDC with DCR
  3. OAuth Proxy (
    OAuthProxy
    ): Bridge to providers without DCR (GitHub, Google, Azure, AWS, Discord, Facebook)
  4. Full OAuth (
    OAuthProvider
    ): Complete authorization server
Pattern 1: Token Validation
python
from fastmcp.auth import JWTVerifier

auth = JWTVerifier(issuer="https://auth.example.com", audience="my-server",
                   public_key=os.getenv("JWT_PUBLIC_KEY"))
mcp = FastMCP("Server", auth=auth)
Pattern 3: OAuth Proxy (Production)
python
from fastmcp.auth import OAuthProxy
from key_value.stores import RedisStore
from key_value.encryption import FernetEncryptionWrapper
from cryptography.fernet import Fernet

auth = OAuthProxy(
    jwt_signing_key=os.environ["JWT_SIGNING_KEY"],
    client_storage=FernetEncryptionWrapper(
        key_value=RedisStore(host=os.getenv("REDIS_HOST"), password=os.getenv("REDIS_PASSWORD")),
        fernet=Fernet(os.environ["STORAGE_ENCRYPTION_KEY"])
    ),
    upstream_authorization_endpoint="https://github.com/login/oauth/authorize",
    upstream_token_endpoint="https://github.com/login/oauth/access_token",
    upstream_client_id=os.getenv("GITHUB_CLIENT_ID"),
    upstream_client_secret=os.getenv("GITHUB_CLIENT_SECRET"),
    enable_consent_screen=True  # CRITICAL: Prevents confused deputy attacks
)
mcp = FastMCP("GitHub Auth", auth=auth)
OAuth Proxy Features: Token factory pattern (issues own JWTs), consent screens (prevents bypass), PKCE support, RFC 7662 token introspection
Supported Providers: GitHub, Google, Azure, AWS Cognito, Discord, Facebook, WorkOS, AuthKit, Descope, Scalekit, OCI (v2.13.1)
Supabase Provider (v2.14.2+):
python
from fastmcp.auth import SupabaseProvider

auth = SupabaseProvider(
    auth_route="/custom-auth",  # Custom auth route (new in v2.14.2)
    # ... other config
)
4种认证模式:
  1. 令牌验证
    JWTVerifier
    ):验证外部令牌
  2. 外部身份提供商
    RemoteAuthProvider
    ):支持DCR的OAuth 2.0/OIDC
  3. OAuth代理
    OAuthProxy
    ):桥接到不支持DCR的提供商(GitHub、Google、Azure、AWS、Discord、Facebook)
  4. 完整OAuth
    OAuthProvider
    ):完整的授权服务器
模式1:令牌验证
python
from fastmcp.auth import JWTVerifier

auth = JWTVerifier(issuer="https://auth.example.com", audience="my-server",
                   public_key=os.getenv("JWT_PUBLIC_KEY"))
mcp = FastMCP("Server", auth=auth)
模式3:OAuth代理(生产环境推荐)
python
from fastmcp.auth import OAuthProxy
from key_value.stores import RedisStore
from key_value.encryption import FernetEncryptionWrapper
from cryptography.fernet import Fernet

auth = OAuthProxy(
    jwt_signing_key=os.environ["JWT_SIGNING_KEY"],
    client_storage=FernetEncryptionWrapper(
        key_value=RedisStore(host=os.getenv("REDIS_HOST"), password=os.getenv("REDIS_PASSWORD")),
        fernet=Fernet(os.environ["STORAGE_ENCRYPTION_KEY"])
    ),
    upstream_authorization_endpoint="https://github.com/login/oauth/authorize",
    upstream_token_endpoint="https://github.com/login/oauth/access_token",
    upstream_client_id=os.getenv("GITHUB_CLIENT_ID"),
    upstream_client_secret=os.getenv("GITHUB_CLIENT_SECRET"),
    enable_consent_screen=True  # 关键:防止混淆代理攻击
)
mcp = FastMCP("GitHub Auth", auth=auth)
OAuth代理特性: 令牌工厂模式(签发自有JWT)、同意屏幕(防止绕过)、PKCE支持、RFC 7662令牌 introspection
支持的提供商: GitHub、Google、Azure、AWS Cognito、Discord、Facebook、WorkOS、AuthKit、Descope、Scalekit、OCI(v2.13.1)
Supabase提供商(v2.14.2+):
python
from fastmcp.auth import SupabaseProvider

auth = SupabaseProvider(
    auth_route="/custom-auth",  # 自定义认证路由(v2.14.2新增)
    # ... 其他配置
)

Icons, API Integration, Cloud Deployment

图标、API集成、云部署

Icons: Add to servers, tools, resources, prompts. Use
Icon(url, size)
, data URIs via
Icon.from_file()
or
Image.to_data_uri()
(v2.13.1).
API Integration (3 Patterns):
  1. Manual:
    httpx.AsyncClient
    with base_url/headers/timeout
  2. OpenAPI Auto-Gen:
    FastMCP.from_openapi(spec, client, route_maps)
    - GET→Resources/Templates, POST/PUT/DELETE→Tools
  3. FastAPI Conversion:
    FastMCP.from_fastapi(app, httpx_client_kwargs)
Cloud Deployment Critical Requirements:
  1. Module-level server named
    mcp
    ,
    server
    , or
    app
  2. PyPI dependencies only in requirements.txt
  3. Public GitHub repo (or accessible)
  4. Environment variables for config
python
undefined
图标: 可为服务器、工具、资源、提示词添加图标。使用
Icon(url, size)
,或通过
Icon.from_file()
Image.to_data_uri()
生成数据URI(v2.13.1)。
API集成(3种模式):
  1. 手动集成:使用
    httpx.AsyncClient
    配置base_url/headers/timeout
  2. OpenAPI自动生成
    FastMCP.from_openapi(spec, client, route_maps)
    - GET→资源/模板,POST/PUT/DELETE→工具
  3. FastAPI转换
    FastMCP.from_fastapi(app, httpx_client_kwargs)
云部署关键要求:
  1. 模块级服务器,命名为
    mcp
    server
    app
  2. requirements.txt中仅包含PyPI依赖
  3. 公开的GitHub仓库(或可访问的仓库)
  4. 使用环境变量配置
python
undefined

✅ CORRECT: Module-level export

✅ 正确方式:模块级导出

mcp = FastMCP("server") # At module level!
mcp = FastMCP("server") # 必须在模块级别定义!

❌ WRONG: Function-wrapped

❌ 错误方式:函数包裹

def create_server(): return FastMCP("server") # Too late for cloud!

**Deployment:** https://fastmcp.cloud → Sign in → Create Project → Select repo → Deploy

**Client Config (Claude Desktop):**
```json
{"mcpServers": {"my-server": {"url": "https://project.fastmcp.app/mcp", "transport": "http"}}}
def create_server(): return FastMCP("server") # 云部署无法识别!

**部署流程:** https://fastmcp.cloud → 登录 → 创建项目 → 选择仓库 → 部署

**客户端配置(Claude桌面端):**
```json
{"mcpServers": {"my-server": {"url": "https://project.fastmcp.app/mcp", "transport": "http"}}}

30 Common Errors (With Solutions)

30种常见错误及解决方案

Error 1: Missing Server Object

错误1:缺少服务器对象

Error:
RuntimeError: No server object found at module level
Cause: Server not exported at module level (FastMCP Cloud requirement) Solution:
mcp = FastMCP("server")
at module level, not inside functions
错误信息:
RuntimeError: No server object found at module level
原因: 服务器未在模块级别导出(FastMCP Cloud要求) 解决方案: 在模块级别定义
mcp = FastMCP("server")
,不要放在函数内部

Error 2: Async/Await Confusion

错误2:Async/Await混淆

Error:
RuntimeError: no running event loop
,
TypeError: object coroutine can't be used in 'await'
Cause: Mixing sync/async incorrectly Solution: Use
async def
for tools with
await
, sync
def
for non-async code
错误信息:
RuntimeError: no running event loop
,
TypeError: object coroutine can't be used in 'await'
原因: 错误地混合同步/异步代码 解决方案:
await
的工具使用
async def
,非异步代码使用同步
def

Error 3: Context Not Injected

错误3:上下文未注入

Error:
TypeError: missing 1 required positional argument: 'context'
Cause: Missing
Context
type annotation Solution:
async def tool(context: Context)
- type hint required!
错误信息:
TypeError: missing 1 required positional argument: 'context'
原因: 缺少
Context
类型注解 解决方案: 定义工具时使用
async def tool(context: Context)
- 必须添加类型提示!

Error 4: Resource URI Syntax

错误4:资源URI语法错误

Error:
ValueError: Invalid resource URI: missing scheme
Cause: Resource URI missing scheme prefix Solution: Use
@mcp.resource("data://config")
not
@mcp.resource("config")
错误信息:
ValueError: Invalid resource URI: missing scheme
原因: 资源URI缺少协议前缀 解决方案: 使用
@mcp.resource("data://config")
而非
@mcp.resource("config")

Error 5: Resource Template Parameter Mismatch

错误5:资源模板参数不匹配

Error:
TypeError: get_user() missing 1 required positional argument
Cause: Function parameter names don't match URI template Solution:
@mcp.resource("user://{user_id}/profile")
def get_user(user_id: str)
- names must match exactly

错误信息:
TypeError: get_user() missing 1 required positional argument
原因: 函数参数名称与URI模板不匹配 解决方案:
@mcp.resource("user://{user_id}/profile")
def get_user(user_id: str)
- 名称必须完全匹配

Error 6: Pydantic Validation Error

错误6:Pydantic验证错误

Error:
ValidationError: value is not a valid integer
Cause: Type hints don't match provided data Solution: Use Pydantic models:
class Params(BaseModel): query: str = Field(min_length=1)
错误信息:
ValidationError: value is not a valid integer
原因: 类型提示与提供的数据不匹配 解决方案: 使用Pydantic模型:
class Params(BaseModel): query: str = Field(min_length=1)

Error 7: Transport/Protocol Mismatch

错误7:传输/协议不匹配

Error:
ConnectionError: Server using different transport
Cause: Client and server using incompatible transports Solution: Match transports - stdio:
mcp.run()
+
{"command": "python", "args": ["server.py"]}
, HTTP:
mcp.run(transport="http", port=8000)
+
{"url": "http://localhost:8000/mcp", "transport": "http"}
HTTP Timeout Issue (Fixed in v2.14.3):
  • HTTP transport was defaulting to 5-second timeout instead of MCP's 30-second default (GitHub Issue #2845)
  • Tools taking >5 seconds would fail silently in v2.14.2 and earlier
  • Solution: Upgrade to fastmcp>=2.14.3 (timeout now respects MCP's 30s default)
错误信息:
ConnectionError: Server using different transport
原因: 客户端与服务器使用不兼容的传输方式 解决方案: 保持传输方式一致 - stdio:
mcp.run()
+
{"command": "python", "args": ["server.py"]}
,HTTP:
mcp.run(transport="http", port=8000)
+
{"url": "http://localhost:8000/mcp", "transport": "http"}
HTTP超时问题(v2.14.3已修复):
  • HTTP传输默认超时为5秒,而非MCP标准的30秒(GitHub Issue #2845
  • v2.14.2及更早版本中,耗时超过5秒的工具会静默失败
  • 解决方案:升级到fastmcp>=2.14.3(现在超时时间遵循MCP的30秒默认值)

Error 8: Import Errors (Editable Package)

错误8:导入错误(可编辑包)

Error:
ModuleNotFoundError: No module named 'my_package'
Cause: Package not properly installed Solution:
pip install -e .
or use absolute imports or
export PYTHONPATH="/path/to/project"
错误信息:
ModuleNotFoundError: No module named 'my_package'
原因: 包未正确安装 解决方案: 使用
pip install -e .
,或使用绝对导入,或设置
export PYTHONPATH="/path/to/project"

Error 9: Deprecation Warnings

错误9:弃用警告

Error:
DeprecationWarning: 'mcp.settings' is deprecated
Cause: Using old FastMCP v1 API Solution: Use
os.getenv("API_KEY")
instead of
mcp.settings.get("API_KEY")
错误信息:
DeprecationWarning: 'mcp.settings' is deprecated
原因: 使用旧版FastMCP v1 API 解决方案: 使用
os.getenv("API_KEY")
替代
mcp.settings.get("API_KEY")

Error 10: Port Already in Use

错误10:端口已被占用

Error:
OSError: [Errno 48] Address already in use
Cause: Port 8000 already occupied Solution: Use different port
--port 8001
or kill process
lsof -ti:8000 | xargs kill -9
错误信息:
OSError: [Errno 48] Address already in use
原因: 端口8000已被占用 解决方案: 使用其他端口
--port 8001
,或杀死占用进程
lsof -ti:8000 | xargs kill -9

Error 11: Schema Generation Failures

错误11:模式生成失败

Error:
TypeError: Object of type 'ndarray' is not JSON serializable
Cause: Unsupported type hints (NumPy arrays, custom classes) Solution: Return JSON-compatible types:
list[float]
or convert:
{"values": np_array.tolist()}
Custom Classes Not Supported (Community-sourced): FastMCP supports all Pydantic-compatible types, but custom classes must be converted to dictionaries or Pydantic models for tool returns:
python
undefined
错误信息:
TypeError: Object of type 'ndarray' is not JSON serializable
原因: 使用了不支持的类型提示(NumPy数组、自定义类) 解决方案: 返回JSON兼容类型:
list[float]
,或转换为
{"values": np_array.tolist()}
自定义类不支持(社区发现): FastMCP支持所有Pydantic兼容类型,但自定义类必须转换为字典或Pydantic模型才能作为工具返回值:
python
undefined

❌ NOT SUPPORTED

❌ 不支持

class MyCustomClass: def init(self, value: str): self.value = value
@mcp.tool() async def get_custom() -> MyCustomClass: return MyCustomClass("test") # Serialization error
class MyCustomClass: def init(self, value: str): self.value = value
@mcp.tool() async def get_custom() -> MyCustomClass: return MyCustomClass("test") # 序列化错误

✅ SUPPORTED - Use dict or Pydantic

✅ 支持 - 使用dict或Pydantic

@mcp.tool() async def get_custom() -> dict[str, str]: obj = MyCustomClass("test") return {"value": obj.value}
@mcp.tool() async def get_custom() -> dict[str, str]: obj = MyCustomClass("test") return {"value": obj.value}

OR use Pydantic BaseModel

或使用Pydantic BaseModel

from pydantic import BaseModel class MyModel(BaseModel): value: str
@mcp.tool() async def get_model() -> MyModel: return MyModel(value="test") # Works!

**OutputSchema $ref Resolution (Fixed in v2.14.2)**:
- Root-level `$ref` in `outputSchema` wasn't being dereferenced ([GitHub Issue #2720](https://github.com/jlowin/fastmcp/issues/2720))
- Caused MCP spec non-compliance and client compatibility issues
- **Solution**: Upgrade to fastmcp>=2.14.2 (auto-dereferences $ref)
from pydantic import BaseModel class MyModel(BaseModel): value: str
@mcp.tool() async def get_model() -> MyModel: return MyModel(value="test") # 正常工作!

**OutputSchema $ref解析(v2.14.2已修复):**
- `outputSchema`中的根级别`$ref`未被正确解析([GitHub Issue #2720](https://github.com/jlowin/fastmcp/issues/2720))
- 导致MCP规范不兼容和客户端兼容性问题
- **解决方案**:升级到fastmcp>=2.14.2(自动解析$ref)

Error 12: JSON Serialization

错误12:JSON序列化错误

Error:
TypeError: Object of type 'datetime' is not JSON serializable
Cause: Returning non-JSON-serializable objects Solution: Convert:
datetime.now().isoformat()
, bytes:
.decode('utf-8')
错误信息:
TypeError: Object of type 'datetime' is not JSON serializable
原因: 返回了非JSON可序列化的对象 解决方案: 转换为兼容格式:
datetime.now().isoformat()
,字节数据:
.decode('utf-8')

Error 13: Circular Import Errors

错误13:循环导入错误

Error:
ImportError: cannot import name 'X' from partially initialized module
Cause: Circular dependency (common in cloud deployment) Solution: Use direct imports in
__init__.py
:
from .api_client import APIClient
or lazy imports in functions
错误信息:
ImportError: cannot import name 'X' from partially initialized module
原因: 循环依赖(云部署中常见) 解决方案:
__init__.py
中使用直接导入:
from .api_client import APIClient
,或在函数中使用延迟导入

Error 14: Python Version Compatibility

错误14:Python版本兼容性

Error:
DeprecationWarning: datetime.utcnow() is deprecated
Cause: Using deprecated Python 3.12+ methods Solution: Use
datetime.now(timezone.utc)
instead of
datetime.utcnow()
错误信息:
DeprecationWarning: datetime.utcnow() is deprecated
原因: 使用了Python 3.12+中已弃用的方法 解决方案: 使用
datetime.now(timezone.utc)
替代
datetime.utcnow()

Error 15: Import-Time Execution

错误15:导入时执行异步代码

Error:
RuntimeError: Event loop is closed
Cause: Creating async resources at module import time Solution: Use lazy initialization - create connection class with async
connect()
method, call when needed in tools

错误信息:
RuntimeError: Event loop is closed
原因: 在模块导入时创建异步资源 解决方案: 使用延迟初始化 - 创建带异步
connect()
方法的连接类,在工具中需要时调用

Error 16: Storage Backend Not Configured

错误16:未配置存储后端

Error:
RuntimeError: OAuth tokens lost on restart
,
ValueError: Cache not persisting
Cause: Using default memory storage in production without persistence Solution: Use encrypted DiskStore (single instance) or RedisStore (multi-instance) with
FernetEncryptionWrapper
错误信息:
RuntimeError: OAuth tokens lost on restart
,
ValueError: Cache not persisting
原因: 生产环境中使用默认内存存储,无持久化 解决方案: 使用加密的DiskStore(单实例)或RedisStore(多实例),搭配
FernetEncryptionWrapper

Error 17: Lifespan Not Passed to ASGI App

错误17:未将生命周期传递给ASGI应用

Error:
RuntimeError: Database connection never initialized
,
Warning: MCP lifespan hooks not running
Cause: FastMCP with FastAPI/Starlette without passing lifespan (v2.13.0 requirement) Solution:
app = FastAPI(lifespan=mcp.lifespan)
- MUST pass lifespan!
错误信息:
RuntimeError: Database connection never initialized
,
Warning: MCP lifespan hooks not running
原因: FastMCP与FastAPI/Starlette集成时未传递生命周期(v2.13.0要求) 解决方案:
app = FastAPI(lifespan=mcp.lifespan)
- 必须传递lifespan!

Error 18: Middleware Execution Order Error

错误18:中间件执行顺序错误

Error:
RuntimeError: Rate limit not checked before caching
Cause: Incorrect middleware ordering (order matters!) Solution: ErrorHandling → Timing → Logging → RateLimiting → ResponseCaching (this order)
错误信息:
RuntimeError: Rate limit not checked before caching
原因: 中间件顺序错误(顺序至关重要!) 解决方案: 错误处理→计时→日志→限流→响应缓存(此顺序)

Error 19: Circular Middleware Dependencies

错误19:中间件循环依赖

Error:
RecursionError: maximum recursion depth exceeded
Cause: Middleware not calling
self.next()
or calling incorrectly Solution: Always call
result = await self.next(tool_name, arguments, context)
in middleware hooks
错误信息:
RecursionError: maximum recursion depth exceeded
原因: 中间件未调用
self.next()
或调用方式错误 解决方案: 在中间件钩子中始终调用
result = await self.next(tool_name, arguments, context)

Error 20: Import vs Mount Confusion

错误20:导入与挂载混淆

Error:
RuntimeError: Subserver changes not reflected
,
ValueError: Unexpected tool namespacing
Cause: Using
import_server()
when
mount()
was needed (or vice versa) Solution:
import_server()
for static bundles (one-time copy),
mount()
for dynamic composition (live link)
错误信息:
RuntimeError: Subserver changes not reflected
,
ValueError: Unexpected tool namespacing
原因: 应该使用
mount()
时使用了
import_server()
(反之亦然) 解决方案:
import_server()
用于静态包(一次性复制),
mount()
用于动态组合(实时链接)

Error 21: Resource Prefix Format Mismatch

错误21:资源前缀格式不匹配

Error:
ValueError: Resource not found: resource://api/users
Cause: Using wrong resource prefix format Solution: Path format (default v2.4.0+):
resource://prefix/path
, Protocol (legacy):
prefix+resource://path
- set with
resource_prefix_format="path"
错误信息:
ValueError: Resource not found: resource://api/users
原因: 使用了错误的资源前缀格式 解决方案: 路径格式(v2.4.0+默认):
resource://prefix/path
,协议格式(旧版):
prefix+resource://path
- 可通过
resource_prefix_format="path"
设置

Error 22: OAuth Proxy Without Consent Screen

错误22:OAuth代理未启用同意屏幕

Error:
SecurityWarning: Authorization bypass possible
Cause: OAuth Proxy without consent screen (security vulnerability) Solution: Always set
enable_consent_screen=True
- prevents confused deputy attacks (CRITICAL)
错误信息:
SecurityWarning: Authorization bypass possible
原因: OAuth代理未启用同意屏幕(安全漏洞) 解决方案: 始终设置
enable_consent_screen=True
- 防止混淆代理攻击(至关重要)

Error 23: Missing JWT Signing Key in Production

错误23:生产环境缺少JWT签名密钥

Error:
ValueError: JWT signing key required for OAuth Proxy
Cause: OAuth Proxy missing
jwt_signing_key
Solution: Generate:
secrets.token_urlsafe(32)
, store in
FASTMCP_JWT_SIGNING_KEY
env var, pass to
OAuthProxy(jwt_signing_key=...)
错误信息:
ValueError: JWT signing key required for OAuth Proxy
原因: OAuth代理缺少
jwt_signing_key
解决方案: 生成密钥:
secrets.token_urlsafe(32)
,存储在
FASTMCP_JWT_SIGNING_KEY
环境变量中,传递给
OAuthProxy(jwt_signing_key=...)

Error 24: Icon Data URI Format Error

错误24:图标数据URI格式错误

Error:
ValueError: Invalid data URI format
Cause: Incorrectly formatted data URI for icons Solution: Use
Icon.from_file("/path/icon.png", size="medium")
or
Image.to_data_uri()
(v2.13.1) - don't manually format
错误信息:
ValueError: Invalid data URI format
原因: 图标数据URI格式不正确 解决方案: 使用
Icon.from_file("/path/icon.png", size="medium")
Image.to_data_uri()
(v2.13.1) - 不要手动格式化

Error 25: Lifespan Behavior Change (v2.13.0)

错误25:生命周期行为变更(v2.13.0)

Error:
Warning: Lifespan runs per-server, not per-session
Cause: Expecting v2.12 behavior (per-session) in v2.13.0+ (per-server) Solution: v2.13.0+ lifespans run ONCE per server, not per session - use middleware for per-session logic
错误信息:
Warning: Lifespan runs per-server, not per-session
原因: 在v2.13.0+中仍期望v2.12的行为(每个会话执行一次) 解决方案: v2.13.0+的生命周期每个服务器仅执行一次,会话级逻辑使用中间件实现

Error 26: BearerAuthProvider Removed (v2.14.0)

错误26:BearerAuthProvider已移除(v2.14.0)

Error:
ImportError: cannot import name 'BearerAuthProvider' from 'fastmcp.auth'
Cause:
BearerAuthProvider
module removed in v2.14.0 Solution: Use
JWTVerifier
for token validation or
OAuthProxy
for full OAuth flows:
python
undefined
错误信息:
ImportError: cannot import name 'BearerAuthProvider' from 'fastmcp.auth'
原因: v2.14.0中移除了
BearerAuthProvider
模块 解决方案: 使用
JWTVerifier
进行令牌验证,或使用
OAuthProxy
实现完整OAuth流程:
python
undefined

Before (v2.13.x)

之前的写法(v2.13.x)

from fastmcp.auth import BearerAuthProvider
from fastmcp.auth import BearerAuthProvider

After (v2.14.0+)

现在的写法(v2.14.0+)

from fastmcp.auth import JWTVerifier auth = JWTVerifier(issuer="...", audience="...", public_key="...")
undefined
from fastmcp.auth import JWTVerifier auth = JWTVerifier(issuer="...", audience="...", public_key="...")
undefined

Error 27: Context.get_http_request() Removed (v2.14.0)

错误27:Context.get_http_request()已移除(v2.14.0)

Error:
AttributeError: 'Context' object has no attribute 'get_http_request'
Cause:
Context.get_http_request()
method removed in v2.14.0 Solution: Access request info through middleware or use
InitializeResult
exposed to middleware
错误信息:
AttributeError: 'Context' object has no attribute 'get_http_request'
原因: v2.14.0中移除了
Context.get_http_request()
方法 解决方案: 通过中间件访问请求信息,或使用中间件暴露的
InitializeResult

Error 28: Image Import Path Changed (v2.14.0)

错误28:Image导入路径变更(v2.14.0)

Error:
ImportError: cannot import name 'Image' from 'fastmcp'
Cause:
fastmcp.Image
top-level import removed in v2.14.0 Solution: Use new import path:
python
undefined
错误信息:
ImportError: cannot import name 'Image' from 'fastmcp'
原因: v2.14.0中移除了
fastmcp.Image
顶层导入 解决方案: 使用新的导入路径:
python
undefined

Before (v2.13.x)

之前的写法(v2.13.x)

from fastmcp import Image
from fastmcp import Image

After (v2.14.0+)

现在的写法(v2.14.0+)

from fastmcp.utilities import Image
undefined
from fastmcp.utilities import Image
undefined

Error 29: FastAPI Mount Path Doubling

错误29:FastAPI挂载路径重复

Error: Client can't connect to
/mcp
endpoint, gets 404 Source: GitHub Issue #2961 Cause: Mounting FastMCP at
/mcp
creates endpoint at
/mcp/mcp
due to path prefix duplication Solution: Mount at root
/
or adjust client config
python
undefined
错误信息: 客户端无法连接到
/mcp
端点,返回404 来源: GitHub Issue #2961 原因: 将FastMCP挂载到
/mcp
时,由于路径前缀重复,实际端点为
/mcp/mcp
解决方案: 挂载到根路径
/
,或调整客户端配置
python
undefined

❌ WRONG - Creates /mcp/mcp endpoint

❌ 错误写法 - 生成/mcp/mcp端点

from fastapi import FastAPI from fastmcp import FastMCP
mcp = FastMCP("server") app = FastAPI(lifespan=mcp.lifespan) app.mount("/mcp", mcp) # Endpoint becomes /mcp/mcp
from fastapi import FastAPI from fastmcp import FastMCP
mcp = FastMCP("server") app = FastAPI(lifespan=mcp.lifespan) app.mount("/mcp", mcp) # 实际端点为/mcp/mcp

✅ CORRECT - Mount at root

✅ 正确写法 - 挂载到根路径

app.mount("/", mcp) # Endpoint is /mcp
app.mount("/", mcp) # 端点为/mcp

✅ OR adjust client config

✅ 或调整客户端配置

In claude_desktop_config.json:

在claude_desktop_config.json中:

{"url": "http://localhost:8000/mcp/mcp", "transport": "http"}

**Critical**: Must also pass `lifespan=mcp.lifespan` to FastAPI (see Error #17).
{"url": "http://localhost:8000/mcp/mcp", "transport": "http"}

**关键提示**:必须同时将`lifespan=mcp.lifespan`传递给FastAPI(参考错误#17)。

Error 30: Background Tasks Fail with "No Active Context" (ASGI Mount)

错误30:后台任务提示“无活动上下文”(ASGI挂载)

Error:
RuntimeError: No active context found
Source: GitHub Issue #2877 Cause: ContextVar propagation issue when FastMCP mounted in FastAPI/Starlette with background tasks (
task=True
) Solution: Upgrade to fastmcp>=2.14.3
python
undefined
错误信息:
RuntimeError: No active context found
来源: GitHub Issue #2877 原因: 当FastMCP挂载到FastAPI/Starlette并使用后台任务(
task=True
)时,ContextVar传播出现问题 解决方案: 升级到fastmcp>=2.14.3
python
undefined

In v2.14.2 and earlier - FAILS

v2.14.2及更早版本 - 失败

from fastapi import FastAPI from fastmcp import FastMCP, Context
mcp = FastMCP("server") app = FastAPI(lifespan=mcp.lifespan)
@mcp.tool(task=True) async def sample(name: str, ctx: Context) -> dict: # RuntimeError: No active context found await ctx.report_progress(1, 1, "Processing") return {"status": "OK"}
app.mount("/", mcp)
from fastapi import FastAPI from fastmcp import FastMCP, Context
mcp = FastMCP("server") app = FastAPI(lifespan=mcp.lifespan)
@mcp.tool(task=True) async def sample(name: str, ctx: Context) -> dict: # RuntimeError: No active context found await ctx.report_progress(1, 1, "处理中") return {"状态": "OK"}
app.mount("/", mcp)

✅ FIXED in v2.14.3

✅ v2.14.3已修复

pip install fastmcp>=2.14.3

pip install fastmcp>=2.14.3


**Note**: Related to Error #17 (Lifespan Not Passed to ASGI App).

---

**注意**:与错误#17(未将生命周期传递给ASGI应用)相关。

---

Production Patterns, Testing, CLI

生产模式、测试、CLI

4 Production Patterns:
  1. Utils Module: Single
    utils.py
    with Config class, format_success/error helpers
  2. Connection Pooling: Singleton
    httpx.AsyncClient
    with
    get_client()
    class method
  3. Retry with Backoff:
    retry_with_backoff(func, max_retries=3, initial_delay=1.0, exponential_base=2.0)
  4. Time-Based Caching:
    TimeBasedCache(ttl=300)
    with
    .get()
    and
    .set()
    methods
Testing:
  • Unit:
    pytest
    +
    create_test_client(test_server)
    +
    await client.call_tool()
  • Integration:
    Client("server.py")
    +
    list_tools()
    +
    call_tool()
    +
    list_resources()
CLI Commands:
bash
fastmcp dev server.py                # Run with inspector
fastmcp install server.py             # Install to Claude Desktop
FASTMCP_LOG_LEVEL=DEBUG fastmcp dev  # Debug logging
Best Practices: Factory pattern with module-level export, environment config with validation, comprehensive docstrings (LLMs read these!), health check resources
Project Structure:
  • Simple:
    server.py
    ,
    requirements.txt
    ,
    .env
    ,
    README.md
  • Production:
    src/
    (server.py, utils.py, tools/, resources/, prompts/),
    tests/
    ,
    pyproject.toml

4种生产模式:
  1. 工具模块:单个
    utils.py
    文件,包含Config类、format_success/error辅助函数
  2. 连接池:单例
    httpx.AsyncClient
    ,带
    get_client()
    类方法
  3. 退避重试
    retry_with_backoff(func, max_retries=3, initial_delay=1.0, exponential_base=2.0)
  4. 基于时间的缓存
    TimeBasedCache(ttl=300)
    ,带
    .get()
    .set()
    方法
测试:
  • 单元测试:
    pytest
    +
    create_test_client(test_server)
    +
    await client.call_tool()
  • 集成测试:
    Client("server.py")
    +
    list_tools()
    +
    call_tool()
    +
    list_resources()
CLI命令:
bash
fastmcp dev server.py                # 带检查器运行
fastmcp install server.py             # 安装到Claude桌面端
FASTMCP_LOG_LEVEL=DEBUG fastmcp dev  # 调试日志
最佳实践: 带模块级导出的工厂模式、带验证的环境配置、全面的文档字符串(LLM会读取!)、健康检查资源
项目结构:
  • 简单结构:
    server.py
    requirements.txt
    .env
    README.md
  • 生产结构:
    src/
    (server.py、utils.py、tools/、resources/、prompts/)、
    tests/
    pyproject.toml

References & Summary

参考资料与总结

Official: https://github.com/jlowin/fastmcp, https://fastmcp.cloud, https://modelcontextprotocol.io, Context7:
/jlowin/fastmcp
Related Skills: openai-api, claude-api, cloudflare-worker-base, typescript-mcp Package Versions: fastmcp>=2.14.2 (PyPI), Python>=3.10 (3.13 supported in v2.14.1+), httpx, pydantic, py-key-value-aio, cryptography Last Updated: 2026-01-21
17 Key Takeaways:
  1. Module-level server export (FastMCP Cloud)
  2. Persistent storage (Disk/Redis) for OAuth/caching
  3. Server lifespans for resource management
  4. Middleware order: errors → timing → logging → rate limiting → caching
  5. Composition:
    import_server()
    (static) vs
    mount()
    (dynamic)
  6. OAuth security: consent screens + encrypted storage + JWT signing
  7. Async/await properly (don't block event loop)
  8. Structured error handling
  9. Avoid circular imports
  10. Test locally (
    fastmcp dev
    )
  11. Environment variables (never hardcode secrets)
  12. Comprehensive docstrings (LLMs read!)
  13. Production patterns (utils, pooling, retry, caching)
  14. OpenAPI auto-generation
  15. Health checks + monitoring
  16. Background tasks for long-running operations (
    task=True
    )
  17. Sampling with tools for agentic workflows (
    ctx.sample(tools=[...])
    )
Production Readiness: Encrypted storage, 4 auth patterns, 8 middleware types, modular composition, OAuth security (consent screens, PKCE, RFC 7662), response caching, connection pooling, timing middleware, background tasks, agentic sampling, FastAPI/Starlette mounting, v3.0 provider architecture
Prevents 30+ errors. 90-95% token savings.
官方链接: https://github.com/jlowin/fastmcp, https://fastmcp.cloud, https://modelcontextprotocol.io, Context7:
/jlowin/fastmcp
相关技能: openai-api, claude-api, cloudflare-worker-base, typescript-mcp 依赖版本: fastmcp>=2.14.2(PyPI), Python>=3.10(v2.14.1+支持3.13), httpx, pydantic, py-key-value-aio, cryptography 最后更新: 2026-01-21
17个关键要点:
  1. 模块级服务器导出(FastMCP Cloud要求)
  2. 持久化存储(磁盘/Redis)用于OAuth/缓存
  3. 服务器生命周期用于资源管理
  4. 中间件顺序:错误处理→计时→日志→限流→缓存
  5. 组合策略:
    import_server()
    (静态)vs
    mount()
    (动态)
  6. OAuth安全:同意屏幕+加密存储+JWT签名
  7. 正确使用Async/Await(不要阻塞事件循环)
  8. 结构化错误处理
  9. 避免循环导入
  10. 本地测试(
    fastmcp dev
  11. 使用环境变量(不要硬编码密钥)
  12. 全面的文档字符串(LLM会读取!)
  13. 生产模式(工具、连接池、重试、缓存)
  14. OpenAPI自动生成
  15. 健康检查+监控
  16. 后台任务用于长时间运行的操作(
    task=True
  17. 工具调用采样用于智能体工作流(
    ctx.sample(tools=[...])
生产就绪特性: 加密存储、4种认证模式、8种中间件类型、模块化组合、OAuth安全(同意屏幕、PKCE、RFC 7662)、响应缓存、连接池、计时中间件、后台任务、智能体采样、FastAPI/Starlette挂载、v3.0提供器架构
可预防30+种错误,节省90-95%的令牌消耗。