跳到主要内容

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 中建立的长链接返回消息

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