本教学文档基于 FastMCP 2.0 官方文档(截至 2026 年),面向 Python 开发者,系统介绍如何构建、运行、部署完整的 MCP 服务器。
一、什么是 FastMCP 与 MCP?
FastMCP是构建模型上下文协议(MCP) 服务端的标准框架。MCP(Model Context Protocol)是一种标准化协议,用于安全地将 LLM 与工具、数据和交互模板连接起来,常被称为“AI 的 USB-C 接口”。
MCP 服务器通过三种核心能力扩展 LLM 能力:
- Resources(资源):只读数据暴露(类似 GET 接口),供 LLM 读取上下文。
- Tools(工具):可执行功能(类似 POST 接口),可产生副作用(如调用 API、执行计算)。
- Prompts(提示模板):可重用的交互模式(官方文档提及但未详述功能细节)。
FastMCP 2.0是当前活跃维护版本,远超基础 MCP SDK,提供生产级特性:异步支持、企业认证、部署工具、测试框架、OpenAPI 生成等。
二、安装 FastMCP
推荐安装方式(使用uv)
uv pipinstallfastmcp或使用pip:
pipinstallfastmcp验证安装
fastmcp version预期输出:
FastMCP version: 2.11.3 MCP version: 1.12.4 Python version: 3.12.2 Platform: macOS-15.3.1-arm64-arm-64bit FastMCP root path: ~/Developer/fastmcp⚠️重要提示:FastMCP 遵循语义化版本控制,但因 MCP 协议快速演进,次要版本(如 2.3.x → 2.4.0)。生产环境必须固定精确版本:
# ✅ 正确 fastmcp==2.11.0 # ❌ 错误(可能引入破坏性变更) fastmcp>=2.11.0三、创建第一个 FastMCP 服务器
1. 基础结构
创建my_server.py:
fromfastmcpimportFastMCP# 创建服务器实例mcp=FastMCP(name="MyFirstServer")2. 添加工具(Tool)
@mcp.tooldefadd(a:int,b:int)->int:"""将两个整数相加。"""returna+b3. 添加资源(Resource)
@mcp.resource("data://config")defget_config()->dict:"""以 JSON 形式提供配置信息。"""return{"version":"1.0","theme":"dark"}4. 完整示例
# my_server.pyfromfastmcpimportFastMCP mcp=FastMCP(name="DemoServer")@mcp.tooldefgreet(name:str)->str:"""向用户打招呼。"""returnf"Hello,{name}!"@mcp.resource("resource://status")defget_status()->dict:return{"status":"ok","server":mcp.name}5. 运行服务器
方法一:脚本直接运行(推荐用于开发)
# 在 my_server.py 末尾添加if__name__=="__main__":mcp.run("stdio")# 本地标准输入输出(传统方式)# 或 mcp.run("http", port=8000) # HTTP 服务运行:
python my_server.py方法二:使用 FastMCP CLI(不执行__main__块)
fastmcp run my_server:mcp--transportstdio# 或fastmcp run my_server:mcp--transporthttp--port8000💡 提示:CLI 模式不会执行
if __name__ == "__main__"块,而是直接导入mcp对象运行。
四、深入工具(Tools)
1. 基础定义
使用@mcp.tool装饰函数。FastMCP 自动提取:
- 工具名 → 函数名
- 描述 → 文档字符串
- 输入架构 → 参数类型注解
@mcp.tooldefmultiply(x:float,y:float)->float:"""计算两个数的乘积。"""returnx*y2. 装饰器参数(自定义元数据)
@mcp.tool(name="search_products",description="搜索产品目录,支持分类过滤。",tags={"catalog","search"},meta={"version":"1.2","team":"backend"},annotations={"title":"产品搜索","readOnlyHint":True,"openWorldHint":False,"idempotentHint":True})defsearch_impl(query:str,category:str|None=None)->list[dict]:return[{"id":1,"name":"Sample Product"}]支持的注解(Annotations):
| 注解 | 类型 | 默认值 | 用途 |
|---|---|---|---|
title | str | - | UI 显示名称 |
readOnlyHint | bool | False | 是否只读 |
destructiveHint | bool | True | 是否具破坏性 |
idempotentHint | bool | False | 是否幂等 |
openWorldHint | bool | True | 是否与外部系统交互 |
3. 类型注解与参数验证
支持广泛类型:
- 基本类型:
int,str,bool,float - 集合:
list[str],dict[str, int] - 可选:
str | None - 枚举/字面量:
Literal["A", "B"] - Pydantic 模型、
Path、UUID、datetime
参数描述(使用Annotated)
fromtypingimportAnnotatedfrompydanticimportField@mcp.tooldefresize_image(url:Annotated[str,"图像URL"],width:Annotated[int,Field(ge=1,le=2000,description="目标宽度")])->str:return"resized"4. 返回值处理
FastMCP 支持传统内容块 + 结构化输出双模式。
自动行为:
dict/Pydantic/数据类 →自动成为结构化输出int/str/list→仅当有返回类型注解时才生成结构化输出(包装为{"result": value})
完全控制:使用ToolResult
fromfastmcp.tools.toolimportToolResultfromfastmcp.sdk.typesimportTextContent@mcp.tooldefadvanced_tool()->ToolResult:returnToolResult(content=[TextContent(type="text",text="操作完成")],structured_content={"status":"success","code":200})5. 异步支持
importaiohttp@mcp.toolasyncdeffetch_url(url:str)->str:asyncwithaiohttp.ClientSession()assession:asyncwithsession.get(url)asresp:returnawaitresp.text()⚠️ 同步 CPU 密集型任务应使用
anyio.to_thread.run_sync()包装以避免阻塞。
6. 错误处理
- 普通异常(如
ValueError):默认返回详细错误(含堆栈) ToolError:始终返回客户端可见消息(即使启用mask_error_details)
fromfastmcp.exceptionsimportToolError@mcp.tooldefdivide(a:float,b:float)->float:ifb==0:raiseToolError("除数不能为零")returna/b全局隐藏敏感错误:
mcp=FastMCP(name="SecureServer",mask_error_details=True)7. 动态管理工具
@mcp.tooldeftemp_tool():return"temp"# 禁用/启用temp_tool.disable()temp_tool.enable()# 移除mcp.remove_tool("temp_tool")💡 工具状态变更会自动发送
notifications/tools/list_changed通知(需在请求上下文中)。
五、深入资源(Resources)
1. 基础动态资源
@mcp.resource("resource://greeting")defget_greeting()->str:return"Hello from FastMCP!"2. 自定义元数据
@mcp.resource(uri="data://app-status",name="ApplicationStatus",description="提供应用当前状态",mime_type="application/json",tags={"monitoring"},meta={"team":"infra"},annotations={"readOnlyHint":True,"idempotentHint":True})defget_status()->dict:return{"uptime":12345}3. 异步资源
importaiofiles@mcp.resource("file:///logs/app.log",mime_type="text/plain")asyncdefread_log()->str:asyncwithaiofiles.open("/logs/app.log")asf:returnawaitf.read()4. 静态资源类(无需函数)
fromfastmcp.resourcesimportFileResource,TextResource,DirectoryResourcefrompathlibimportPath# 静态文件readme=FileResource(uri="file://./README.md",path=Path("./README.md"),mime_type="text/markdown")mcp.add_resource(readme)# 预定义文本notice=TextResource(uri="resource://notice",text="系统维护通知")mcp.add_resource(notice)# 目录列表data_dir=DirectoryResource(uri="resource://files",path=Path("./data"),recursive=False)mcp.add_resource(data_dir)5. 资源模板(参数化 URI)
基础模板
@mcp.resource("weather:// {city} /current")defget_weather(city:str)->dict:return{"city":city,"temp":22}客户端可请求:
weather://london/currentweather://tokyo/current
多参数 + 查询参数(FastMCP ≥2.13.0)
@mcp.resource("api:// {endpoint} {?version,limit}")defcall_api(endpoint:str,version:int=1,limit:int=10)->dict:return{"endpoint":endpoint,"version":version,"limit":limit}请求示例:
api://users?version=2&limit=50
🔍 FastMCP 自动根据函数类型提示转换查询参数(如
int、bool)。
通配符路径(FastMCP ≥2.2.4)
@mcp.resource("files://{path*}")defget_file_content(path:str)->str:# 匹配 files://src/main.py 或 files://docs/api/v1.mdreturnf"Content of{path}"6. 上下文访问(Context)
fromfastmcpimportContext@mcp.resource("resource://request-info")asyncdefget_info(ctx:Context)->dict:return{"request_id":ctx.request_id}7. 禁用资源
@mcp.resource("secret://data",enabled=False)defget_secret():return"hidden"# 或动态控制get_secret.disable()get_secret.enable()六、高级服务器配置
1. 重复处理策略
mcp=FastMCP(name="StrictServer",on_duplicate_tools="error",# 工具重复:报错on_duplicate_resources="ignore"# 资源重复:忽略)选项:"warn"(默认)、"error"、"replace"、"ignore"
2. 严格输入验证(FastMCP ≥2.13.0)
mcp=FastMCP("StrictServer",strict_input_validation=True)- 默认(
False):自动转换"10"→10 - 严格(
True):拒绝类型不匹配输入
3. 安全配置
mcp=FastMCP(name="SecureServer",mask_error_details=True# 隐藏非 ToolError 的内部错误)七、部署与生产
1. 本地测试
python my_server.py# 使用 stdio# 或fastmcp run my_server:mcp--transporthttp--port80002. 客户端调用示例
# my_client.pyimportasynciofromfastmcp.clientimportClientasyncdefmain():asyncwithClient("http://localhost:8000/mcp")asclient:result=awaitclient.call_tool("greet",name="Alice")print(result)asyncio.run(main())3. 部署到 FastMCP Cloud(免费)
- 将
my_server.py推送到 GitHub - 登录 FastMCP Cloud
- 创建项目,入口点设为
my_server.py:mcp - 获得专属 URL:
https://your-project.fastmcp.app/mcp
八、最佳实践总结
| 场景 | 推荐做法 |
|---|---|
| 版本管理 | 固定fastmcp==x.y.z |
| 工具返回 | 优先返回dict/Pydantic 模型以启用结构化输出 |
| 敏感错误 | 使用ToolError或启用mask_error_details=True |
| I/O 操作 | 使用async def |
| CPU 密集型 | 用anyio.to_thread.run_sync()包装 |
| 参数描述 | 使用Annotated[类型, "描述"] |
| 动态能力 | 利用disable()/enable()/remove_tool()实现功能开关 |
| 资源模板 | 用{param}路径参数 +{?param}查询参数分离必选/可选 |