第六课
MCP 从零实现教程(六)
第六课:让你的 Mini MCP Server 真正跑起来
目标:让另一个 Python 程序真的能够连接你的 MCP Server。
📚 本课目标
学完本课后,你将理解:
- Server 为什么要一直运行
- Client 和 Server 是如何通信的
- 什么是 Transport(传输层)
- 为什么 MCP 有 STDIO 和 HTTP 两种运行方式
今天最大的变化:
前五课我们都是:
Python 函数
│
▼
dispatch(request)
今天开始变成:
Client
│
▼
发送请求
│
▼
Server
│
▼
dispatch(request)
这一步开始,你写的不再只是一个 Python 程序,而是一个真正意义上的 Server。
根据 MCP 官方规范,目前标准支持两种 Transport:
- STDIO(标准输入输出)
- Streamable HTTP
对于本地工具,客户端通常启动 MCP Server 子进程,然后通过 STDIN/STDOUT 通信。
📖 第一部分:为什么需要 Server?
目前我们的程序是这样的:
request = {
"method": "tools/call",
...
}
dispatch(request)
程序执行一次:
开始
↓
执行 dispatch()
↓
结束
结束以后:
程序退出。
但是真正的 MCP Server 不是这样。
它应该:
启动
↓
等待请求
↓
处理请求
↓
继续等待
↓
处理请求
↓
继续等待
也就是说:
Server 是一直运行的。
📖 第二部分:什么叫监听请求?
最简单的方法:
一直循环。
while True:
print("等待客户端请求...")
运行以后:
等待客户端请求...
等待客户端请求...
等待客户端请求...
...
当然,
真正服务器不会一直打印。
它会一直:
等待输入。
💻 第三部分:模拟客户端发送请求
最简单的方法:
使用:
input()
例如:
while True:
command = input("请输入:")
print(command)
运行:
请输入:
hello
输出:
hello
这就是:
等待客户端输入。
💻 第四部分:输入 JSON
上一课:
我们写的是:
request = {
"method": "tools/call"
}
现在:
改成:
import json
while True:
text = input()
request = json.loads(text)
print(request)
运行:
输入:
{
"method":"tools/list"
}
Python 输出:
{
"method": "tools/list"
}
是不是已经开始接收 JSON 了?
💻 第五部分:调用 Dispatcher
现在:
收到 JSON 后,
直接:
while True:
text = input()
request = json.loads(text)
response = dispatch(request)
print(response)
是不是很自然?
整个流程:
JSON
↓
Dispatcher
↓
Tool
↓
Result
↓
打印
💻 第六部分:输出 JSON
真正 MCP 不会:
print(response)
因为:
Python 字典:
{
"a":1
}
不是 JSON。
所以:
改成:
print(json.dumps(response))
完整:
import json
while True:
text = input()
request = json.loads(text)
response = dispatch(request)
print(json.dumps(response))
💻 第七部分:完整 Server
import json
def server():
print("Mini MCP Server 已启动")
while True:
text = input()
request = json.loads(text)
response = dispatch(request)
print(json.dumps(response))
server()
运行:
终端:
Mini MCP Server 已启动
输入:
{
"method":"tools/list"
}
输出:
{
"result":{
"tools":[
...
]
}
}
是不是已经有 Server 的样子了?
💻 第八部分:写一个 Client
以前:
客户端不存在。
今天:
我们自己写。
import json
request = {
"method":"tools/list"
}
print(json.dumps(request))
是不是很简单?
Client:
负责:
发送 JSON
Server:
负责:
接收 JSON
📖 第九部分:真正 MCP 是怎么通信的?
我们今天:
Client
↓
input()
↓
Server
真实 MCP(STDIO):
Claude Desktop
↓
STDIN
↓
你的 MCP Server
↓
STDOUT
↓
Claude Desktop
也就是说:
今天我们写的:
input()
未来:
其实就是:
stdin.read()
今天的:
print()
未来:
其实就是:
stdout.write()
本质完全一样。
MCP 官方要求:
- Client 启动 Server 子进程
- Client 把 JSON-RPC 消息写入 Server 的 stdin
- Server 把 JSON-RPC 响应写入 stdout
- stdout 不能输出任何非协议内容(日志应该写到 stderr)。
📖 第十部分:为什么官方喜欢 STDIO?
因为:
不用网络。
例如:
Cursor
↓
启动
filesystem_server.py
↓
stdin/stdout
↓
完成
整个过程:
没有:
- HTTP
没有:
- Socket
没有:
- Web Server
速度非常快。
所以:
本地 Tool:
几乎都是:
STDIO
远程 MCP:
才使用:
Streamable HTTP
🧪 本课练习
修改你的 Server。
要求:
支持连续执行:
第一次:
{
"method":"tools/list"
}
返回:
{
"result":{
"tools":[...]
}
}
第二次:
{
"method":"tools/call",
"params":{
"name":"add",
"arguments":{
"a":10,
"b":20
}
}
}
返回:
{
"result":30
}
要求:
程序不要退出。
能够一直等待新的请求。
🎯 本课总结
今天,你已经拥有了:
✅ Tool Registry
✅ Dispatcher
✅ JSON-RPC
✅ tools/list
✅ tools/call
✅ 持续运行的 Mini MCP Server
这是一个重要的里程碑。
你已经不再只是写几个 Python 函数,而是在构建一个真正可以与其他程序通信的服务。
🚀 第七课预告(真正进入 MCP SDK)
前六课,我们一直在自己造轮子。
下一课,我们会第一次引入官方 MCP SDK。
但不同的是:
别人学习 SDK 时看到:
@mcp.tool()
def weather():
...
可能觉得这是魔法。
而你已经知道:
实际上 SDK 只是帮你完成了:
@tool
↓
Registry
↓
Dispatcher
↓
JSON-RPC
↓
STDIO
↓
Server
所以第七课我们会做一件非常有意思的事情:
把我们自己写的 Mini MCP Server,与官方 MCP SDK 的实现逐行对照。
你会发现,两者在核心思想上几乎一致,只是官方 SDK 把很多重复工作自动化了。这也是为什么我一直坚持先带你手写,再学框架。

浙公网安备 33010602011771号