MCP (Model Context Protocol,模型上下文协议) 是当前最热门的协议,特指由 Anthropic 于 2024 年 11 月开源的 AI 连接标准,被誉为 "AI 的 USB-C 接口"。
俗话说内行看门道,外行看热闹。现在来搭建环境抓包MCP实战分析下,拖掉这个协议神秘的外衣(规则分析)。
环境搭建
搭建好dify平台
MCP配置好

对应的Agent也配置好

使用python,跑一个MCP服务
代码如下:
python
#!/usr/bin/env python3
"""
简单的MCP测试服务
功能:提供一个自定义运势计算工具
端口:8077
"""
from mcp.server.fastmcp import FastMCP
# 创建MCP服务器
mcp = FastMCP("simple-test-server", port=8077, host="0.0.0.0")
@mcp.tool()
async def number_fortune_teller(x: float, y: float) -> str:
"""
数字占卜师 - 根据两个神秘数字预测你的运势
参数:
- **x**: 第一个神秘数字
- **y**: 第二个神秘数字
返回:
str: 基于数字的神秘预测结果
"""
# 计算神秘指数
magic_number = abs(int((x + y) * 7.777)) % 1000
# 幸运动物预测
animals = ["🐉龙", "🦄独角兽", "🐧企鹅", "🦋蝴蝶", "🐙章鱼", "🦩火烈鸟", "🐨考拉", "🦔刺猬"]
lucky_animal = animals[magic_number % len(animals)]
# 今日运势
fortunes = [
"今天会遇到意想不到的惊喜!",
"小心!今天可能会掉进兔子洞",
"今天特别适合学习新技能",
"会收到来自远方的神秘消息",
"今天的咖啡会格外香醇",
"可能会遇到会说话的猫",
"今天适合穿亮色衣服",
"会发现隐藏的宝藏(可能是袜子)"
]
today_fortune = fortunes[magic_number % len(fortunes)]
# 幸运数字
lucky_num = (magic_number * 3 + 42) % 100
# 奇怪的建议
advice = [
"多吃紫色的食物", "倒着走7步", "对镜子眨眼3次",
"给植物唱歌", "用左手刷牙", "数一数天空中的云朵",
"向路过的狗狗问好", "在11:11许个愿"
]
weird_advice = advice[magic_number % len(advice)]
result = f"""
🔮 数字占卜结果 🔮
━━━━━━━━━━━━━━━━━━━━━━━━━
📊 输入数字: {x} 和 {y}
✨ 神秘指数: {magic_number}
🍀 幸运动物: {lucky_animal}
🌟 今日运势: {today_fortune}
🎯 幸运数字: {lucky_num}
💡 神秘建议: {weird_advice}
━━━━━━━━━━━━━━━━━━━━━━━━━
⚠️ 此预测仅供娱乐,请勿当真 ⚠️
"""
return result
if __name__ == "__main__":
print("启动简单MCP测试服务...")
print("服务器地址: http://0.0.0.0:8077")
print("SSE端点: http://localhost:8077/sse")
print("使用本地docker启动的dify使用:SSE端点: http://host.docker.internal:8077/sse")
print("可用工具:")
print("- number_fortune_teller: 数字占卜师(根据数字预测运势)")
mcp.run(transport="sse")
运行截图如下:

抓包分析
打开Wireshark,使用调试和预览输入:
我的幸运数字是5和10请使用你的工具预测下

看下Wireshark抓包,主要分析下,MCP。

首先是sse,这个和MCP服务对应起来了。
SSE(HTTP Server-Sent Events):支持跨网络、长连接、服务端主动推送。
SSE 在 MCP 里的工作流程(极简)
- 客户端先请求:GET /sse
- 服务端保持连接不断开(chunked 流式响应)
- 服务端通过这条连接主动推送消息、通知、事件给客户端
- 客户端再用普通 HTTP POST 发请求给服务端
对应的http层数据如下:

从中可以知道,业务室的本次对话,对应的除了see的3个post请求。

这里和MCP标准的流程一样了。
- GET 不先返回,是因为它是长连接推送通道
- 3 个 POST 是控制指令
- POST 全部跑完,服务端才通过 GET 把结果推回来
1)GET /sse :客户端发起,连接挂起,等待服务端推消息
2)POST ① initialize
- 告诉 MCP 服务:我是谁、版本多少
- MCP 服务回复:我支持什么能力
3)POST ② tools/list
- 客户端问:你有哪些工具可以用?
- MCP 服务返回工具清单(比如文件读取、数据库查询)
4)POST ③ tools/call
- 客户端真正调用工具
5)GET /sse 终于返回
POST ① initialize
从中可以看到dify给MCP服务端的一些信息

MCP回复Accepted

POST ② tools/list
使用http流看看


notifications/initialized,通知已初始化,然后mcp回复,好像也合理。
4)POST ③ tools/call
同样也查看下http流

调用了number_fortune_teller工具,其中参数为5,10。这个和python搭建的MCP能对上了。
最后一个最关键就是see这个长连接了
1)GET /sse :客户端发起,连接挂起,等待服务端推消息
查看下这个tcp流。

bash
event: endpoint data: /messages/?session_id=1d9a46a3b1cd45c38ec13b120ed82c72
- 作用:给 Dify 一个专属的消息地址,后续的 POST /messages 都要带这个 session_id。
- 473/489/502 这 3 个 POST 请求,用的就是这个 session_id。
javascript
{
"jsonrpc": "2.0",
"id": 0,
"result": {
"protocolVersion": "2025-06-18",
"capabilities": {
"prompts": {"listChanged": false},
"resources": {"subscribe": false, "listChanged": false},
"tools": {"listChanged": false}
},
"serverInfo": {"name": "simple-test-server", "version": "1.27.0"}
}
}
- 作用:服务端响应 Dify 发来的 initialize 请求:
- 支持的协议版本是 2025-06-18
- 支持 prompts、resources、tools 这几种能力
- 的服务名是 simple-test-server,版本 1.27.0
- 这就是 MCP 协议的 "握手成功" 证明,说明服务和 Dify 版本兼容,连接正常。
javascript
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [{"type": "text", "text": "..."}],
"structuredContent": {"result": "..."},
"isError": false
}
}
- 作用:服务端把你在 Dify 里调用工具的执行结果,推送给 Dify。
- isError: false 说明调用成功了,content 里就是工具返回的文本结果
将数据转utf8

可见MCP服务端中回的数据了。

总结
① SSE(GET /sse):是一条单向的、从服务器到客户端的 "数据返回通道",所有指令的执行结果,都通过它推回来。
② 3 个 POST(/messages):是客户端发给服务器的控制指令(比如初始化、确认、调用工具),服务器只会立刻回复 202 Accepted,表示 "指令收到了,结果稍后从 SSE 通道发送"。
所以,MCP其实还是基于上个世纪90年代的HTTP协议,在这基础上,做了一些业务规则而形成的协议。可以理解为他是基于HTTP的应用协议,通过sse,和几个post规则来的。