MCP 是什么
MCP(Model Context Protocol)的核心思路就一句话:把"工具"抽象成一个标准化的服务端,用于模型和工具之间的解耦。
bash
之前: 模型 → 应用代码 → 本地函数
现在: 模型 → MCP Client → MCP Server → 实际工具/服务
MCP的三种通信机制
- stdio(标准输入输出)
纯本地,不走网络
bash
Host/Client 进程
↓ 启动子进程
MCP Server 进程
↓ stdin/stdout 读写 JSON-RPC 消息
- SSE(Server-Sent Events)
客户端会与服务端建立一个长链接,服务端可以通过这个链接主动推送;请求和响应走的是不同的通道;比如客户端给服务器用QQ发消息,服务端用微信给客户端推送数据;
客户端通过 HTTP POST 发 JSON-RPC 请求
服务端通过一条持久的 SSE 连接往回推结果
双向通信但用了两个通道:POST 走请求,SSE 走响应流
优点:真正的远程调用、浏览器友好、服务端可以主动推送
缺点:SSE 是单向的,服务端没法真正"调回"客户端;连接断了要重连;架构上比较别扭------请求和响应走不同通道
- Streamable HTTP
可以理解成 POST 请求,请求工具,返回结果;
还可以兼容之前的SSE 让服务端主动推送;
bash
Client ──HTTP POST──→ Server
Client ←──HTTP 响应── Server(可以是普通 JSON,也可以是流式 SSE)
SSE 本身是什么
SSE(Server-Sent Events)本质就是一个浏览器原生的、服务端往客户端单向推数据的 HTTP 流
bash
GET /events HTTP/1.1
Accept: text/event-stream
← 服务端一直往这条连接里写数据:
event: message
data: {"foo": "bar"}
data: {"foo": "baz"}
...永不关闭
协议层面就规定了:客户端发一次请求,服务端持续往回写。客户端不能通过这条连接往服务端发东西。
所以叫"单向"------只有服务端→客户端这一个方向能流动数据。
所以"双向"是靠两个独立的 HTTP 连接拼出来的,不是一个通道天然支持双向。所以,请求和响应走的通道不一样。
既然是单向的为什么还要建立长连接
MCP 里有些消息不是客户端发起请求然后等服务端回的,而是服务端自己想说话。
比如:
通知(Notification)------服务端状态变了,想告诉客户端一声
Sampling------Server 对 Client 说"帮我调一下你的模型生成一段文本"
Elicitation------Server 对 Client 说"弹个框让用户填个参数"
资源变更通知------文件改了、数据库变了,推给客户端刷新上下文
这些场景有个共同特点:不是客户端先问的,是服务端主动要开口;
众所周知,服务端是没办法给客户端主动发消息的(客户端大概率没有公网地址),长连接就是给服务端一个能主动触达客户端的通道;
bash
POST /message → 客户端随时能找服务端说话(短连接,用完就走)
SSE /sse → 服务端随时能找客户端说话(长连接,一直挂着)
举例说明
- stdio
bash
你的电脑上跑着两个进程:
进程A(AI 应用) 进程B(天气 MCP Server)
| |
|--- stdin: {"method": "tools/call", |
| "params": {"name": "get_weather", |
| "arguments": {"city": "北京"}} |
| |
| | (查数据库/调 API)
| |
|<-- stdout: {"temperature": "28°C", |
| "condition": "晴"} |
就像你写了个程序,fork 了一个子进程,往它的键盘输入里打字,它从屏幕输出里回你结果。进程间通过管道通信,纯本地,没有网络;
- SSE 方式
bash
你的电脑(Client) 云端天气服务(Server)
| |
|--- POST /message ---------->|
| {"method": "tools/call", |
| "params": {"city": "北京"}}
| |
| | (处理请求)
| |
| 同时,早就建好的一条连接: |
|<=== SSE 长连接一直挂着 =====|
| |
| 服务端往这条流里推结果: |
|<-- event: result ----------|
| {"temperature": "28°C", |
| "condition": "晴"} |
注意这里是 POST 出去了,但结果不是从 POST 的响应里回来的,是从那条早就建好的 SSE 长连接里推过来的。就像你往客服发了条微信(POST),但客服回你的消息是从另一个窗口弹出来的(SSE 流)。
- Streamable HTTP 方式
bash
你的电脑(Client) 云端天气服务(Server)
| |
|--- POST /message ---------->|
| {"method": "tools/call", |
| "params": {"city": "北京"}}
| |
| | (处理请求)
| |
|<-- HTTP 200 OK ------------|
| Content-Type: application/json
| Body: {"temperature": "28°C", "condition": "晴"}
一个 POST,一个响应,跟调普通 REST API 一模一样。
既然POST 就可以解决,为什么还要搞出个SSE
MCP 的初衷并不是"解耦工具和模型";
Anthropic 设计 MCP 时的野心比"工具调用标准化"大得多。他们想解决的是:
让 AI 应用能像人一样,无缝接入所有数字资源。
不只是调个 API 拿个结果,而是:
读文件、查数据库、翻浏览器书签
感知环境变化(文件改了、邮件来了、issue 更新了)
跟用户交互(弹确认框、要额外输入)
让工具之间协作(Server A 调 Server B,或者 Server 让模型生成内容)
所以你看 MCP 的三大原语------Tools、Resources、Prompts------它的定位是"AI 的通用接口层",类比 USB 协议,什么设备都能插;
但是,实际落地时大部分场景就是工具调用
现实很骨感:
90% 的 MCP Server 只实现了 Tools
Resources 有人用但少
Prompts 用的人更少
Sampling、Elicitation 几乎没人实现
因为当前 AI 应用的主流形态是"用户问→模型答→中间调个工具拿结果",这个循环里根本不需要服务端反向通信、不需要主动通知、不需要用户交互原语。
所以,Streamable HTTP 本质上是一次功能降级操作,是对现实的妥协;