8.1 传输抽象:读写流与业务解耦


文档摘要

8.1 传输抽象:读写流与业务解耦 本节摘要:第 8 章开篇,先讲传输层的总纲——传输与业务完全解耦。核心洞见是: 是一个异步上下文管理器,进入时产出一对 读写流,业务逻辑通过它收发消息,对「跑在哪」毫无感知。这一节用一张图说清「同一套服务端代码 + 不同传输 = 不同部署形态」,这是整个 SDK 工程设计的精华,也是后续四节(stdio/HTTP/SSE/内存)的总纲。 一、传输层要解决的问题 先明确传输层干什么。MCP 消息(JSON-RPC)从客户端到服务端,总要有东西把它搬过去。这个「搬运」就是传输层: 「搬运」的方式有很多——可以是子进程的标准输入输出、可以是 HTTP 请求、可以是服务器发送事件。这些方式的底层机制天差地别,但它们要干的事是一样的:把消息从一端搬到另一端。

8.1 传输抽象:读写流与业务解耦

本节摘要:第 8 章开篇,先讲传输层的总纲——传输与业务完全解耦。核心洞见是:Transport 是一个异步上下文管理器,进入时产出一对 (read, write) 读写流,业务逻辑通过它收发消息,对「跑在哪」毫无感知。这一节用一张图说清「同一套服务端代码 + 不同传输 = 不同部署形态」,这是整个 SDK 工程设计的精华,也是后续四节(stdio/HTTP/SSE/内存)的总纲。

一、传输层要解决的问题

先明确传输层干什么。MCP 消息(JSON-RPC)从客户端到服务端,总要有东西把它搬过去。这个「搬运」就是传输层:

客户端 服务端 │ │ │ 消息怎么过去? │ │ ┌──────────────────┐ │ │ │ 传输层(搬运) │ │ │ └──────────────────┘ │ │ │

「搬运」的方式有很多——可以是子进程的标准输入输出、可以是 HTTP 请求、可以是服务器发送事件。这些方式的底层机制天差地别,但它们要干的事是一样的:把消息从一端搬到另一端。

二、Transport 抽象:读写流

SDK 把「搬运」抽象成一个统一接口——Transport,它是一个异步上下文管理器,进入时产出一对读写流:

# 概念性伪代码,展示 Transport 的本质 class Transport(Protocol): async def __aenter__(self) -> tuple[ReadStream, WriteStream]: ...

readwrite 都是异步流:

  • read:从对端收消息(异步迭代或异步读)
  • write:向对端发消息(异步写)

业务逻辑(服务端或客户端核心)只通过这对读写流收发消息,完全不知道传输底层是子进程、HTTP 还是别的

三、业务与传输的解耦

这是本章最关键的图,展示「同一套业务 + 不同传输 = 不同部署形态」:

你的服务端代码 (MCPServer + 工具/资源/提示词) │ │ 通过读写流收发消息 ▼ ┌─────────────────┐ │ Transport 抽象 │ └─────────────────┘ ┌─────────┼─────────┐ ▼ ▼ ▼ ┌────────┐ ┌──────┐ ┌──────┐ │ stdio │ │ HTTP │ │ SSE │ ... 不同传输 └────────┘ └──────┘ └──────┘ │ │ │ ▼ ▼ ▼ 子进程 HTTP 服务 旧版 HTTP (本地) (生产) (遗留)

关键点:业务代码(最上层)只写一份。你不用为每种传输写不同版本——同一套 MCPServer + 工具/资源/提示词,可以分别用 stdio、HTTP、SSE 跑。这就是「业务与传输解耦」的字面含义。

四、为什么这个解耦有价值

这个解耦不是炫技,它带来三个实际好处:

好处 说明
代码复用 业务写一次,多种部署形态通用
测试简化 用内存传输测,不用真起子进程/HTTP 服务
演进自由 传输升级(如 SSE→HTTP),业务不动

第三个尤其重要——历史上 MCP 的 HTTP 传输从 SSE 演进到流式 HTTP(2025-03-26)。因为业务与传输解耦,这个演进对业务代码几乎透明,只需换传输配置。

五、读写流的统一性

无论哪种传输,读写流的消息格式是一样的——都是 JSON-RPC 帧(或内存传输的直接对象)。这意味着业务逻辑处理消息的代码,对不同传输完全一致:

# 业务逻辑(概念性,服务端核心) async def run_server(read, write): async for message in read: # 收消息(任何传输都这样) result = handle(message) # 业务处理 await write.send(result) # 发消息(任何传输都这样)

不同传输的差别,只在「read/write 怎么实现」:

  • stdio:read 从 stdin 读、write 往 stdout 写
  • HTTP:read 从 HTTP 请求体读、write 往 HTTP 响应写
  • 内存:read/write 是直接函数调用,无序列化

业务逻辑不用关心这些差异——它只看到统一的读写流。

六、服务端与客户端各自的传输

传输不只服务端有——客户端也有传输。两端通过各自的传输「对接」:

客户端核心 服务端核心 │ │ │ 用客户端传输发 │ 用服务端传输收 ▼ ▼ ┌──────────┐ 消息流 ┌──────────┐ │ 客户端 │ ◄─────► │ 服务端 │ │ Transport│ │ Transport│ └──────────┘ └──────────┘ │ │ │ 用客户端传输收 │ 用服务端传输发 ▼ ▼

两端的传输必须匹配——客户端用 stdio 传输,服务端也得用 stdio;客户端用 HTTP,服务端也得用 HTTP。第 9、10 章讲客户端时,会讲客户端的传输接入;本章先聚焦服务端传输。

💡 技巧:理解了「传输是读写流抽象」,你就理解了为什么第 1.3 节的内存连接(Client(mcp))能工作——它就是用「直接分发」代替了读写流,跳过了 JSON-RPC 序列化。这是同一个解耦思想的极致体现:既然业务只关心读写流,那「读写流」的实现可以是真 IO,也可以是直接函数调用。

七、本章后续怎么讲

本章接下来四节,分别讲四种传输:

传输 重点
8.2 stdio 本地默认,子进程模型
8.3 流式 HTTP 生产级,2025-03-26 主力
8.4 SSE 旧版遗留,已弃用
8.5 内存 + 传输安全 测试传输 + DNS 重绑定防护

每节讲清「这种传输怎么工作、怎么启动、适用场景、注意事项」。读完本章,你能为不同部署场景选对传输,并理解它们为什么能互换。

本节要点回顾

  1. 传输层负责搬运 MCP 消息,从客户端到服务端。
  2. Transport 是异步上下文管理器,进入时产出 (read, write) 读写流。
  3. 业务通过读写流收发消息,对传输底层无感——这是业务与传输解耦的本质。
  4. 同一套业务代码可跑多种传输,这是「解耦」的字面含义。
  5. 解耦带来三个好处:代码复用、测试简化、演进自由。
  6. 读写流消息格式统一(JSON-RPC),业务处理代码对不同传输完全一致。
  7. 客户端与服务端各有传输,两端传输必须匹配

总纲清楚了,下一节讲最常见的 stdio 传输——本地默认,子进程模型。


发布者: 作者: 灏天文库 转发
评论区 (0)
U