Post Transport
Before reading this article, it is recommended to familiarize yourself with the basic concepts of MCP (Model Context Protocol).
What is Transport
Transport is the communication layer on which MCP Client and MCP Server depend. MCP Client can request context from MCP Server, and MCP Server can send responses to provide context to MCP Client. Transport is responsible for the communication between the two.
MCP Transport is not a concrete implementation but an interface. Currently, there are two official implementations:
- Stdio Transport: communicates via standard input/output, suitable for local MCP Server.
- SSE Transport: communicates via SSE (Server Sent Event), suitable for remote MCP Server.
Based on specific cloud development scenarios, we custom-implemented the Transport interface using HTTP Post requests. We call it Post Transport.
What is Post Transport
The SSE Transport provided by the official SDK is not well-suited for building MCP Server on cloud functions. Traditional cloud functions are stateless, while SSE Transport is stateful.
Therefore, we implemented a stateless Transport for communication based on HTTP Post, namely Post Transport.
Post Transport is suitable for building MCP Server in cloud function scenarios, which is itself stateless.
When the MCP Server is also stateful, it is necessary to use SSE Transport. Suppose we want to build a puppeteer MCP Server, which provides two tools via puppeteer:
- Navigate to a URL
- Take a screenshot of the current webpage
Obviously, navigating to a URL affects the screenshot results—taking a screenshot after navigating to Baidu versus Zhihu yields different outcomes. We refer to such MCP Server as stateful.
Key to Understanding Service Statefulness:
- Stateful service: Requests have a "memory" dependency between them, and the processing results of subsequent requests are affected by previous requests. Similar to a telephone customer service representative, who needs to remember the entire conversation context to respond effectively.
- Stateless service: Each request is an independent event, and the processing result depends solely on the current request content and externally shared data. Similar to a vending machine, where each coin-operated purchase is an independent transaction.
Why SSE Transport Is Not Suitable for Use in Cloud Function Scenarios
When using SSE Transport, the connection establishment process is as follows:
- The client sends an HTTP GET request to the server's service URL (assumed to be
/sse
). Upon receiving the request, the server establishes a long-lived SSE connection. Once the connection is established, all messages from the server are sent to the client through this SSE connection. - The server sends a message through this long-lived SSE connection containing another URL (assumed to be
/messages
). Subsequent messages from the Client to the server are sent via HTTP Post to this URL, distinguishing them from the connection-establishing requests initiated at/sse
. - Subsequent specific requests from the Client to the Server, such as requesting the tool list or invoking tools, are sent via
/messages
. However, all responses from the Server are returned through the SSE connection. For example, when requesting the tool list:- Client sends an HTTP Post request from
/sse
to the Server - Upon receiving it, the Server returns the string
"Accepted"
with no other actual response content. - The Server returns the specific tool list through the initially established SSE connection.
- Client sends an HTTP Post request from
Why is this a stateful Transport? Because the messages received by the Server at /messages
need to be returned through the long-lived connection established at /sse
.
Specifically in the cloud function scenario, assuming we need and can use SSE Transport in cloud functions, the following process would occur:
- The first time A is invoked, the Client and Server establish a long-lived connection.
- The second time B is invoked, the Client requests the tool list from the Server. At this point, some mechanism is required to allow the Server to return messages through the long-lived connection established in Invocation A.
This is a very rare scenario in cloud functions. Generally, we require cloud function implementations to be stateless and idempotent.