第十一课
MCP 从零实现教程(十一)
第十一课:第一次使用官方 MCP SDK
目标:安装官方 SDK,并写出你的第一个官方 MCP Server。
📚 本课目标
今天开始,我们不再自己造轮子。
而是开始学习官方 SDK。
但是和别人不同的是:
别人学的是:
API
而你学的是:
API 背后的实现原理。
所以今天你看到任何代码,都应该能知道:
它对应我们前十课自己写的哪一部分。
📖 第一部分:为什么现在才开始用 SDK?
很多教程第一节课就是:
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("Demo")
然后告诉你:
这是 MCP。
但是你现在应该知道:
实际上:
FastMCP
│
├── Registry
├── Dispatcher
├── Lifecycle
├── JSON-RPC
├── Tool Discovery
├── Tool Call
└── Transport
这些东西,
你都已经自己写过了。
所以:
SDK 只是把前十课封装起来了。
📖 第二部分:安装官方 SDK
官方推荐两种方式。
如果你使用 uv(推荐):
uv add "mcp[cli]"
如果使用 pip:
pip install "mcp[cli]"
如果只是最基础的 SDK,也可以直接安装:
pip install mcp
官方目前推荐使用 uv 管理 Python 项目和依赖。
📖 第三部分:创建项目
建议重新创建一个新的目录。
mcp_demo/
├── server.py
├── pyproject.toml
└── .venv/
以后,
所有官方 SDK 示例,
都放这里。
不要和我们前十课的 mini_mcp 混在一起。
原因很简单:
mini_mcp
↓
学习原理
----------------
mcp_demo
↓
学习 SDK
两个项目承担不同职责。
💻 第四部分:写第一个官方 Server
创建:
server.py
输入:
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("Demo")
@mcp.tool()
def add(a: int, b: int) -> int:
"""两个数字相加"""
return a + b
if __name__ == "__main__":
mcp.run()
只有十几行。
是不是感觉非常熟悉?
📖 第五部分:逐行对照我们自己写的代码
第一行:
mcp = FastMCP("Demo")
对应:
我们自己写的:
TOOLS = {}
dispatcher = {}
server = {}
第二行:
@mcp.tool()
对应:
我们自己写的:
@tool
第三行:
mcp.run()
对应:
我们自己写的:
while True:
request = ...
dispatch(...)
看到这里,
是不是已经没有任何神秘感了?
💻 第六部分:再增加一个 Tool
继续增加:
@mcp.tool()
def multiply(a: int, b: int) -> int:
"""乘法"""
return a * b
现在:
Server:
已经拥有:
Tool
├── add
└── multiply
注意:
你没有:
TOOLS["multiply"] = ...
为什么?
因为:
SDK 自动完成了。
💻 第七部分:增加一个 Resource
继续:
@mcp.resource("greeting://{name}")
def greeting(name: str) -> str:
return f"你好,{name}"
你有没有发现?
它和 Tool 非常像。
只是:
以前:
@mcp.tool()
现在:
@mcp.resource(...)
SDK 自动把它放到了:
Resource Registry
这正对应我们第八课讲过的:
TOOLS
RESOURCES
PROMPTS
💻 第八部分:增加一个 Prompt
继续:
@mcp.prompt()
def review(code: str) -> str:
return f"""
请作为高级 Python 工程师,
帮我审查下面代码:
{code}
"""
现在:
你的 Server:
已经拥有:
Tool
+
Resource
+
Prompt
和官方 Quick Start 已经基本一致。
📖 第九部分:为什么没有 Schema?
很多同学会问:
以前我们不是写:
inspect.signature()
吗?
现在怎么没有?
因为:
SDK 自动读取:
def add(a: int, b: int):
自动生成:
{
"type":"object",
"properties":{
"a":{
"type":"integer"
},
"b":{
"type":"integer"
}
}
}
也就是说:
Python 的类型注解:
a: int
自动变成:
JSON Schema
所以:
以后一定要认真写:
def weather(city: str):
不要偷懒。
SDK 会利用这些类型生成输入 Schema、进行数据验证。
📖 第十部分:今天真正理解了一件事
如果今天让你重新实现:
@mcp.tool()
你应该知道:
SDK 内部,
大概就是:
class FastMCP:
def tool(self):
def wrapper(func):
self.tools[func.__name__] = func
return func
return wrapper
当然:
真正源码:
远比这个复杂。
但是:
思想完全一致。
所以:
以后:
你看 SDK,
不会觉得:
@mcp.tool()
是魔法。
而会知道:
它只是:
注册一个 Tool。
🧪 本课练习
请完成下面这个官方 Server。
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("My Demo")
@mcp.tool()
def hello(name: str) -> str:
"""打招呼"""
return f"你好,{name}"
@mcp.tool()
def square(x: int) -> int:
"""平方"""
return x * x
@mcp.resource("config://app")
def config() -> str:
return """
host=localhost
port=3306
"""
@mcp.prompt()
def summarize(text: str) -> str:
return f"""
请总结下面内容:
{text}
"""
if __name__ == "__main__":
mcp.run()
要求:
你能解释下面每一行代码,对应我们前十课自己实现的哪个模块。
例如:
|
SDK |
对应前十课 |
|---|---|
|
|
Server + Registry |
|
|
Tool Registry |
|
|
Resource Registry |
|
|
Prompt Registry |
|
|
Server + Dispatcher + Lifecycle |
如果你能全部对应出来,
说明:
你已经真正理解 SDK。
🎯 本课总结
今天,我们第一次使用官方 SDK。
但是,
今天真正学到的不是:
怎么写 FastMCP。
而是:
为什么 FastMCP 能这么简单。
因为:
它把我们前十课亲手实现的:
- Registry
- Dispatcher
- Lifecycle
- JSON-RPC
- Tool Discovery
- Tool Call
- Transport
全部封装好了。
所以你现在和大多数初学者最大的区别是:
你不是”会用 SDK”,而是知道 SDK 为什么这么设计。
🚀 第十二课预告
下一课,我们将第一次阅读官方 SDK 的设计思路。
但不会一上来啃全部源码。
我们会从一个最核心的问题开始:
@mcp.tool() 到底做了哪些事情?
我们会一步一步追踪:
@mcp.tool()
│
▼
Decorator
│
▼
Registry
│
▼
Schema 生成
│
▼
Dispatcher
│
▼
tools/list
到第十二课结束,你将真正具备阅读 MCP SDK 源码的能力,而不是只会调用它的 API。

浙公网安备 33010602011771号