跳到主要内容

FastMCP — 架构与原理

30 秒导读: FastMCP 是一套 Python 框架,让你只写一个普通函数、加上类型注解,就得到一台符合 MCP(Model Context Protocol,模型上下文协议)规范的服务器——参数校验、JSON schema、协议握手、stdio/HTTP 传输全部自动生成。它同时提供一个对称的 Client,以及把多台服务器拼在一起(挂载、代理、从 OpenAPI 生成)的能力。

本项目体量大、子系统多(服务器、客户端、providers、中间件、传输、任务、鉴权……),所以文档拆成多章。本页是 Layer 0(这是什么)+ Layer 1(顶层全景)+ 阅读地图;各机制细节见分章。


1. 这是什么(零基础也能懂)

一句话定义

FastMCP = 「写一个 Python 函数 → 得到一个 AI 能调用的工具」 的框架。它把「让大模型安全地调用你的代码 / 读你的数据」这件事的所有协议脏活包掉。

先搞清背景:MCP 是什么、为什么需要它

大模型本身只会生成文本。要让它「查天气」「读数据库」「调你的 API」,得有一个标准协议规定:

  • 模型端怎么知道有哪些工具可用(工具列表、每个工具的参数长啥样);
  • 模型想调用某工具时,请求/响应怎么在两端传递。

这个标准就是 MCP(由 Anthropic 提出)。它规定了 tools/listtools/callresources/read 等一批 JSON-RPC 方法。FastMCP 是 MCP 在 Python 里最主流的实现——README 自称「some version of FastMCP powers 70% of MCP servers」,且 FastMCP 1.0 已被并入官方 MCP Python SDK(README.md)。

解决什么问题 / 给谁用

任何想把自己的函数、API、数据暴露给 AI的 Python 工程师用。手写 MCP 服务器要自己:定义每个工具的 JSON schema、校验模型传来的参数、处理协议握手与生命周期、选传输方式……FastMCP 的主张是:

这些你都不该写。你只写业务函数,FastMCP 从函数签名 + 类型注解 + docstring 里把上面这些全部推导出来

用起来什么样

这是一个完整可跑的 MCP 服务器(取自 README.md):

from fastmcp import FastMCP

mcp = FastMCP("Demo 🚀") # 建一台服务器

@mcp.tool # 把函数注册成工具
def add(a: int, b: int) -> int:
"""Add two numbers"""
return a + b

if __name__ == "__main__":
mcp.run() # 起服务(默认 stdio 传输)

就这几行,你得到了:一个名为 add 的工具、{a: int, b: int} 的输入 schema、"Add two numbers" 的描述、参数类型校验、以及一台能被任意 MCP 客户端连上的服务器。你没写一行协议代码。

一句话直觉 / 类比

把 FastMCP 想成 MCP 世界的 FastAPI。FastAPI 让你写个带类型注解的函数 + 装饰器,就得到一个带自动 OpenAPI 文档、自动请求校验的 HTTP 端点;FastMCP 让你写个带类型注解的函数 + @mcp.tool,就得到一个带自动 JSON schema、自动参数校验的 MCP 工具。两者都靠 pydantic 从类型注解生成 schema,套路一模一样——只是目标协议从 HTTP 换成了 MCP。

本节不碰底层。记住一句话就行:FastMCP 的价值 = 「函数签名 → MCP 协议」的自动翻译。


2. 顶层全景(它大概怎么转)

三大支柱

README 把 FastMCP 分成三块,正好是理解全局的骨架:

支柱干什么主要代码位置
Servers(服务器)把工具 / 资源 / 提示暴露给大模型fastmcp_slim/fastmcp/server/
Clients(客户端)用统一 API 连接任意 MCP 服务器fastmcp_slim/fastmcp/client/
组合 / 集成挂载、代理、从 OpenAPI / FastAPI 生成fastmcp/server/server.py(mount/as_proxy/from_openapi)

注意仓库布局:真正的包代码在 fastmcp_slim/fastmcp/ 下(这是 v3 的 uv workspace 结构,pyproject.toml[tool.uv.workspace] 列出 fastmcp_slimfastmcp_remote)。顶层的 fastmcp 只是个聚合发行壳。本文所有引用都以克隆根为基准,即 fastmcp_slim/fastmcp/...

一张图:一次工具调用怎么流动

怎么读这张图:从上到下是一次 tools/call 的生命周期;左边是「注册期」(启动时发生一次),右边是「运行期」(每次调用)。

注册期(启动一次) 运行期(每次调用)
┌───────────────────────────────┐ ┌──────────────────────────────────┐
│ @mcp.tool │ │ MCP 客户端发来 tools/call │
│ def add(a:int,b:int)->int │ │ │ │
│ │ │ │ ▼ │
│ ▼ │ │ ① 低层 SDK 服务器收 JSON-RPC │
│ ① 解析函数签名 │ │ (LowLevelServer) │
│ ParsedFunction.from_function│ │ │ │
│ │ │ │ ▼ │
│ ▼ │ │ ② 中间件洋葱(可选) │
│ ② pydantic 生成 JSON schema │ │ │ │
│ │ │ │ ▼ │
│ ▼ │ │ ③ 找到 Tool(providers 聚合) │
│ ③ 存进 LocalProvider 注册表 │─────▶│ │ │
│ │ │ ▼ │
└───────────────────────────────┘ │ ④ 依赖注入 + pydantic 校验参数 │
│ │ │
│ ▼ │
│ ⑤ 调用你的 add(),转成 MCP 结果 │
└──────────────────────────────────┘

部件一句话职责

部件干什么在哪个文件
FastMCP服务器门面对象,你所有 @mcp.tool 都挂它上面server/server.py:314(class FastMCP)
LocalProvider存放「装饰器注册的」工具/资源/提示的本地注册表server/providers/local_provider/local_provider.py:51
Provider / AggregateProvider组件来源的统一抽象;FastMCP 本身就是个聚合 providerserver/providers/base.py:57server/providers/aggregate.py:47
ParsedFunction把函数签名解析成 name/描述/输入 schema/输出 schematools/function_parsing.py:169
FunctionTool / Tool一个工具的运行时对象,负责校验参数并执行tools/function_tool.py:191tools/base.py:180
LowLevelServer包住官方 MCP SDK 的低层服务器,接 JSON-RPCserver/low_level.py:157
Context工具运行时能拿到的「与客户端对话的能力」(日志/进度/sampling/elicitation)server/context.py:137
Client对称的客户端,一个入参推断出传输方式client/client.py:130
Middleware横切逻辑(鉴权/限流/日志)的洋葱链server/middleware/middleware.py:88

主线走一遍(高层)

  1. 你写函数 + @mcp.tool → FastMCP 在注册期解析签名、生成 schema、把 FunctionTool 存进 LocalProvider
  2. mcp.run() → 起一台传输(stdio / HTTP),内部是官方 MCP SDK 的 LowLevelServer,FastMCP 把 tools/listtools/call 等处理函数接上去(server/mixins/mcp_operations.py:54_setup_handlers)。
  3. 客户端调用 → 请求进 call_tool,穿过中间件链,经 providers 聚合找到工具,做依赖注入 + pydantic 参数校验,执行你的函数,把返回值转成 MCP 的内容块。

3. 阅读地图(按这个顺序读)

顺序章节讲什么适合想搞懂……
101-server-and-decorators.md服务器对象 + 三个装饰器的注册机制@mcp.tool 到底做了什么」
202-schema-generation.md函数 → JSON schema 的核心魔法「schema/校验是怎么凭空长出来的」(全项目最精华)
303-request-lifecycle.md一次调用的完整链路 + 依赖注入 + 错误分类「请求进来后经过哪些环节」
404-providers-and-composition.mdProvider 抽象、挂载/代理/OpenAPI「怎么把多台服务器拼一起 / 动态提供工具」
505-client-and-transports.mdClient 与传输推断、内存测试「怎么连服务器 / 怎么写测试」
606-context-middleware-boundaries.mdContext 能力、中间件、边界与代码地图「工具里怎么反向调用大模型 / 加横切逻辑」

只想快速判断相关性的 agent: 你要找的十有八九是第 2 章(schema 生成)或第 3 章(调用链路)——那是 FastMCP 区别于「手写 SDK」的核心价值所在。