跳到主要内容

Post Transport

提示

在阅读本篇文章前,建议先熟悉 MCP(Model Context Protocol)的基本概念

什么是 Transport

Transport 是 MCP Client 与 MCP Server 依赖的通信层。MCP Client 能向 MCP Server 请求上下文,MCP Server 能向 MCP Client 发送响应提供上下文,而 Transport 则负责这二者之间的通信。

MCP Transport 不是具体实现,而是一个接口。目前官方有两种实现:

  • Stdio Transport:通过标准输入输出进行通信,适用于本地的 MCP Server
  • SSE Transport:通过 SSE(Server Sent Event)进行通信,适用于远程的 MCP Server

我们根据云开发特定的场景,自定义实现了 Transport 接口,基于 HTTP Post 请求。我们称之为 Post Transport。

什么是 Post Transport

官方 SDK 提供的 SSE Transport 并不是很适合在云函数上构建 MCP Server。传统的云函数是无状态的,而 SSE Transport 是有状态的。

因此,我们实现了无状态的基于 HTTP Post 进行通信的 Transport,即 Post Transport。

Post Transport 适合在云函数场景构建本身也是无状态的 MCP Server。

当 MCP Server 也是有状态时,就需要使用 SSE Transport 了。假设我们要构建一个 puppeteer MCP Server,它通过 puppeteer 提供两个工具:

  1. 导航到某个网址
  2. 在当前网址截图

很明显,导航到某个网址会影响截图的结果——导航到百度后再截图和导航到知乎再截图,会得到不同的结果。 我们称这样的 MCP Server 为有状态的。

理解服务状态性的关键:

  • 有状态服务:请求之间存在“记忆”依赖,后续请求的处理结果受先前请求的影响。如同电话客服,需要记住整个对话上下文才能有效响应。
  • 无状态服务:每个请求都是独立事件,处理结果仅取决于当前请求内容和外部共享数据。如同自动售货机,每次投币购买都是独立交易。

为什么 SSE Transport 不适合在云函数场景使用

使用 SSE Transport 时建立链接过程如下:

  1. Client 向 Server 的服务 URL(假定为 /sse)发送 HTTP GET 请求,Server 接收到请求后,建立起 SSE 长链接。建立链接后,Server 所有的消息都会从这个 SSE 长链接发送给 Client
  2. Server 通过这个 SSE 长链接发送一条消息,其中包含了另一个 URL(假定为/messages)。后续 Client 向 Server 发送的消息都会从这个 URL 通过 HTTP Post 发送,以此区分开从 /sse 发起的建立链接的请求
  3. 后续 Client 对 Server 发送的具体请求,如请求工具列表、请求调用工具等都会从 /messages 发送出去,但是 Server 的响应内容都从 SSE 链接返回,举个请求工具列表的例子:
    1. Client 从 /sse 发一个 HTTP Post 请求给 Server
    2. Server 接收到后,返回 "Accepted" 字符串,无其他实际的响应内容
    3. Server 从一开始建立的 SSE 链接中返回具体的工具列表

为什么说这是个有状态的 Transport 呢?就是因为 Server 在 /messages 接收到的消息,需要从 /sse 建立的长链接中返回。

具体到云函数场景,假设我们需要且能够在云函数中使用 SSE Transport,会有这样的一个流程:

  1. 第一次调用 A,Client 和 Server 建立起了长链接
  2. 第二次调用 B,Client 向 Server 请求工具列表,此时需要某种机制,能让 Server 在调用 A 中建立的长链接返回消息

这在云函数中是非常少见的场景。一般来说,我们要求云函数的实现为无状态的,幂等的。