一、环境准备

二、抓包内容分析

1、整体交互过程如图:

\wechat_2025-05-19_100640_734.png

  • 核心有两个请求,一个是get /sse,一个是post /mcp/message?sessionId=?

  • 这个就是协议中要求的,mcp server要提供两个endpoint

The server MUST provide two endpoints:
服务器必须提供两个端点:

An SSE endpoint, for clients to establish a connection and receive messages from the server
一个 SSE 终端节点,供客户端建立连接并从服务器接收消息
A regular HTTP POST endpoint for clients to send messages to the server
一个常规的 HTTP POST 端点,供客户端向服务器发送消息

2、接下来,看下完整的/sse交互过程,如下;

GET /sse HTTP/1.1
host: localhost:8080
connection: keep-alive
Accept: text/event-stream
accept-language: *
sec-fetch-mode: cors
user-agent: node
pragma: no-cache
cache-control: no-cache
accept-encoding: gzip, deflate

HTTP/1.1 200 OK
transfer-encoding: chunked
Content-Type: text/event-stream;charset=UTF-8

51
event:endpoint
data:/mcp/message?sessionId=52e8afc3-8ca1-489a-bba5-ad65c19ab57b


ce
event:message
data:{"jsonrpc":"2.0","id":0,"result":{"protocolVersion":"2024-11-05","capabilities":{"logging":{},"tools":{"listChanged":true}},"serverInfo":{"name":"my-weather-server","version":"0.0.1"}}}


405
event:message
data:{"jsonrpc":"2.0","id":1,"result":{"tools":[{"name":"toUpperCase","description":"Put the text to upper case","inputSchema":{"type":"object","properties":{"input":{"type":"string"}},"required":["input"],"additionalProperties":false}},{"name":"getAlerts","description":"Get weather alerts for a US state. Input is Two-letter US state code (e.g. CA, NY)","inputSchema":{"type":"object","properties":{"state":{"type":"string"}},"required":["state"],"additionalProperties":false}},{"name":"getWeatherForecastByLocation","description":"Get weather forecast for a specific latitude/longitude","inputSchema":{"type":"object","properties":{"latitude":{"type":"number","format":"double"},"longitude":{"type":"number","format":"double"}},"required":["latitude","longitude"],"additionalProperties":false}},{"name":"getScore","description":"Get score for name. Input is someone's name (e.g. lisi)","inputSchema":{"type":"object","properties":{"name":{"type":"string"}},"required":["name"],"additionalProperties":false}}]}}


72
event:message
data:{"jsonrpc":"2.0","id":2,"error":{"code":-32601,"message":"Method not found: resources/list"}}


7c
event:message
data:{"jsonrpc":"2.0","id":3,"error":{"code":-32601,"message":"Method not found: resources/templates/list"}}


76
event:message
data:{"jsonrpc":"2.0","id":4,"result":{"content":[{"type":"text","text":"\"80.0\""}],"isError":false}}


  • 第一行是客户端发起的,连接mcp-server

  • 第二行是服务端回复ok,成功建立连接

  • 第三行是服务端告诉客户端A regular HTTP POST endpoint for clients to send messages to the server

  • 为啥要分开两个接口,因为sse是只能服务端给客户端发送持续的消息,客户端是没办法直接用这个接口去发送消息的

  • 第四行是服务端提供它支持的协议,是"protocolVersion":"2024-11-05"

  • 第五行是服务端提供它支持的Tools有哪些,这里列出的了getScore、 getWeatherForecastByLocation等

  • 第六行是服务端告诉客户端,resources/list接口不存在

  • 第七行是服务端告诉客户端,resources/templates/list接口不存在

  • 第八航是服务端返回客户端的请求,lisi的分数是80.0

3、接下来,看另外一个请求,/mcp/message?sessionId=?

POST /mcp/message?sessionId=52e8afc3-8ca1-489a-bba5-ad65c19ab57b HTTP/1.1
host: localhost:8080
connection: keep-alive
content-type: application/json
accept: */*
accept-language: *
sec-fetch-mode: cors
user-agent: node
accept-encoding: gzip, deflate
content-length: 155

{"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"Cline","version":"3.15.5"}},"jsonrpc":"2.0","id":0}HTTP/1.1 200 OK
content-length: 0

POST /mcp/message?sessionId=52e8afc3-8ca1-489a-bba5-ad65c19ab57b HTTP/1.1
host: localhost:8080
connection: keep-alive
content-type: application/json
accept: */*
accept-language: *
sec-fetch-mode: cors
user-agent: node
accept-encoding: gzip, deflate
content-length: 46

{"method":"tools/list","jsonrpc":"2.0","id":1}HTTP/1.1 200 OK
content-length: 0

POST /mcp/message?sessionId=52e8afc3-8ca1-489a-bba5-ad65c19ab57b HTTP/1.1
host: localhost:8080
connection: keep-alive
content-type: application/json
accept: */*
accept-language: *
sec-fetch-mode: cors
user-agent: node
accept-encoding: gzip, deflate
content-length: 50

{"method":"resources/list","jsonrpc":"2.0","id":2}HTTP/1.1 200 OK
content-length: 0

POST /mcp/message?sessionId=52e8afc3-8ca1-489a-bba5-ad65c19ab57b HTTP/1.1
host: localhost:8080
connection: keep-alive
content-type: application/json
accept: */*
accept-language: *
sec-fetch-mode: cors
user-agent: node
accept-encoding: gzip, deflate
content-length: 60

{"method":"resources/templates/list","jsonrpc":"2.0","id":3}HTTP/1.1 200 OK
content-length: 0

  • 第一次请求,是初始化initialize

  • 第二次请求,是查看tools列表,tools/list

  • 第三次请求,是查看资源列表,resources/list

  • 第四次请求,是查看资源模板列表,resources/templates/list

  • 这里可以发现,sessionId都是用同一个,这个应该就是状态管理了

4、这里没发现请求lisi分数的请求,翻了一下,是在后面一条tcp stream里面,如下:

POST /mcp/message?sessionId=52e8afc3-8ca1-489a-bba5-ad65c19ab57b HTTP/1.1
host: localhost:8080
connection: keep-alive
content-type: application/json
accept: */*
accept-language: *
sec-fetch-mode: cors
user-agent: node
accept-encoding: gzip, deflate
content-length: 103

{"method":"tools/call","params":{"name":"getScore","arguments":{"name":"lisi"}},"jsonrpc":"2.0","id":4}HTTP/1.1 200 OK
content-length: 0

  • 第一次请求,就是调用tools工具,查询lisi的分数

  • 这里可以发现,sessionId和上面的都是用同一个

三、总结

  • mcp协议核心两个角色,mcp server和mcp client

  • mcp server会提供两个端点,一个用于服务端给客户端持续发送内容,一个用户客户端向服务端发送单次请求

  • 这两个端点都是基于http协议的

  • 顺便提一句,目前已经出了最新版的mcp协议,使用Stramable HTTP替换原来的SSE,可以参考https://mp.weixin.qq.com/s/wZ47ZETmjO0RwsJIbCFdJw

  • 只不过目前还有很多软件都还没适配最新的协议,比如日常用的Cline和Cursor都还是2024-11-05版本的协议

  • 最新版协议2025-03-26,https://modelcontextprotocol.io/specification/2025-03-26


mcp

登陆发表评论