Model Context Protocol in OCaml
1--- 2title: Transports 3type: docs 4weight: 10 5--- 6 7{{< callout type="info" >}} **Protocol Revision**: 2025-03-26 {{< /callout >}} 8 9MCP uses JSON-RPC to encode messages. JSON-RPC messages **MUST** be UTF-8 encoded. 10 11The protocol currently defines two standard transport mechanisms for client-server 12communication: 13 141. [stdio](#stdio), communication over standard in and standard out 152. [Streamable HTTP](#streamable-http) 16 17Clients **SHOULD** support stdio whenever possible. 18 19It is also possible for clients and servers to implement 20[custom transports](#custom-transports) in a pluggable fashion. 21 22## stdio 23 24In the **stdio** transport: 25 26- The client launches the MCP server as a subprocess. 27- The server reads JSON-RPC messages from its standard input (`stdin`) and sends messages 28 to its standard output (`stdout`). 29- Messages may be JSON-RPC requests, notifications, responses—or a JSON-RPC 30 [batch](https://www.jsonrpc.org/specification#batch) containing one or more requests 31 and/or notifications. 32- Messages are delimited by newlines, and **MUST NOT** contain embedded newlines. 33- The server **MAY** write UTF-8 strings to its standard error (`stderr`) for logging 34 purposes. Clients **MAY** capture, forward, or ignore this logging. 35- The server **MUST NOT** write anything to its `stdout` that is not a valid MCP message. 36- The client **MUST NOT** write anything to the server's `stdin` that is not a valid MCP 37 message. 38 39```mermaid 40sequenceDiagram 41 participant Client 42 participant Server Process 43 44 Client->>+Server Process: Launch subprocess 45 loop Message Exchange 46 Client->>Server Process: Write to stdin 47 Server Process->>Client: Write to stdout 48 Server Process--)Client: Optional logs on stderr 49 end 50 Client->>Server Process: Close stdin, terminate subprocess 51 deactivate Server Process 52``` 53 54## Streamable HTTP 55 56{{< callout type="info" >}} This replaces the [HTTP+SSE 57transport]({{< ref "/specification/2024-11-05/basic/transports#http-with-sse" >}}) from 58protocol version 2024-11-05. See the [backwards compatibility](#backwards-compatibility) 59guide below. {{< /callout >}} 60 61In the **Streamable HTTP** transport, the server operates as an independent process that 62can handle multiple client connections. This transport uses HTTP POST and GET requests. 63Server can optionally make use of 64[Server-Sent Events](https://en.wikipedia.org/wiki/Server-sent_events) (SSE) to stream 65multiple server messages. This permits basic MCP servers, as well as more feature-rich 66servers supporting streaming and server-to-client notifications and requests. 67 68The server **MUST** provide a single HTTP endpoint path (hereafter referred to as the 69**MCP endpoint**) that supports both POST and GET methods. For example, this could be a 70URL like `https://example.com/mcp`. 71 72### Sending Messages to the Server 73 74Every JSON-RPC message sent from the client **MUST** be a new HTTP POST request to the 75MCP endpoint. 76 771. The client **MUST** use HTTP POST to send JSON-RPC messages to the MCP endpoint. 782. The client **MUST** include an `Accept` header, listing both `application/json` and 79 `text/event-stream` as supported content types. 803. The body of the POST request **MUST** be one of the following: 81 - A single JSON-RPC _request_, _notification_, or _response_ 82 - An array [batching](https://www.jsonrpc.org/specification#batch) one or more 83 _requests and/or notifications_ 84 - An array [batching](https://www.jsonrpc.org/specification#batch) one or more 85 _responses_ 864. If the input consists solely of (any number of) JSON-RPC _responses_ or 87 _notifications_: 88 - If the server accepts the input, the server **MUST** return HTTP status code 202 89 Accepted with no body. 90 - If the server cannot accept the input, it **MUST** return an HTTP error status code 91 (e.g., 400 Bad Request). The HTTP response body **MAY** comprise a JSON-RPC _error 92 response_ that has no `id`. 935. If the input contains any number of JSON-RPC _requests_, the server **MUST** either 94 return `Content-Type: text/event-stream`, to initiate an SSE stream, or 95 `Content-Type: application/json`, to return one JSON object. The client **MUST** 96 support both these cases. 976. If the server initiates an SSE stream: 98 - The SSE stream **SHOULD** eventually include one JSON-RPC _response_ per each 99 JSON-RPC _request_ sent in the POST body. These _responses_ **MAY** be 100 [batched](https://www.jsonrpc.org/specification#batch). 101 - The server **MAY** send JSON-RPC _requests_ and _notifications_ before sending a 102 JSON-RPC _response_. These messages **SHOULD** relate to the originating client 103 _request_. These _requests_ and _notifications_ **MAY** be 104 [batched](https://www.jsonrpc.org/specification#batch). 105 - The server **SHOULD NOT** close the SSE stream before sending a JSON-RPC _response_ 106 per each received JSON-RPC _request_, unless the [session](#session-management) 107 expires. 108 - After all JSON-RPC _responses_ have been sent, the server **SHOULD** close the SSE 109 stream. 110 - Disconnection **MAY** occur at any time (e.g., due to network conditions). 111 Therefore: 112 - Disconnection **SHOULD NOT** be interpreted as the client cancelling its request. 113 - To cancel, the client **SHOULD** explicitly send an MCP `CancelledNotification`. 114 - To avoid message loss due to disconnection, the server **MAY** make the stream 115 [resumable](#resumability-and-redelivery). 116 117### Listening for Messages from the Server 118 1191. The client **MAY** issue an HTTP GET to the MCP endpoint. This can be used to open an 120 SSE stream, allowing the server to communicate to the client, without the client first 121 sending data via HTTP POST. 1222. The client **MUST** include an `Accept` header, listing `text/event-stream` as a 123 supported content type. 1243. The server **MUST** either return `Content-Type: text/event-stream` in response to 125 this HTTP GET, or else return HTTP 405 Method Not Allowed, indicating that the server 126 does not offer an SSE stream at this endpoint. 1274. If the server initiates an SSE stream: 128 - The server **MAY** send JSON-RPC _requests_ and _notifications_ on the stream. These 129 _requests_ and _notifications_ **MAY** be 130 [batched](https://www.jsonrpc.org/specification#batch). 131 - These messages **SHOULD** be unrelated to any concurrently-running JSON-RPC 132 _request_ from the client. 133 - The server **MUST NOT** send a JSON-RPC _response_ on the stream **unless** 134 [resuming](#resumability-and-redelivery) a stream associated with a previous client 135 request. 136 - The server **MAY** close the SSE stream at any time. 137 - The client **MAY** close the SSE stream at any time. 138 139### Multiple Connections 140 1411. The client **MAY** remain connected to multiple SSE streams simultaneously. 1422. The server **MUST** send each of its JSON-RPC messages on only one of the connected 143 streams; that is, it **MUST NOT** broadcast the same message across multiple streams. 144 - The risk of message loss **MAY** be mitigated by making the stream 145 [resumable](#resumability-and-redelivery). 146 147### Resumability and Redelivery 148 149To support resuming broken connections, and redelivering messages that might otherwise be 150lost: 151 1521. Servers **MAY** attach an `id` field to their SSE events, as described in the 153 [SSE standard](https://html.spec.whatwg.org/multipage/server-sent-events.html#event-stream-interpretation). 154 - If present, the ID **MUST** be globally unique across all streams within that 155 [session](#session-management)—or all streams with that specific client, if session 156 management is not in use. 1572. If the client wishes to resume after a broken connection, it **SHOULD** issue an HTTP 158 GET to the MCP endpoint, and include the 159 [`Last-Event-ID`](https://html.spec.whatwg.org/multipage/server-sent-events.html#the-last-event-id-header) 160 header to indicate the last event ID it received. 161 - The server **MAY** use this header to replay messages that would have been sent 162 after the last event ID, _on the stream that was disconnected_, and to resume the 163 stream from that point. 164 - The server **MUST NOT** replay messages that would have been delivered on a 165 different stream. 166 167In other words, these event IDs should be assigned by servers on a _per-stream_ basis, to 168act as a cursor within that particular stream. 169 170### Session Management 171 172An MCP "session" consists of logically related interactions between a client and a 173server, beginning with the [initialization phase]({{< ref "lifecycle" >}}). To support 174servers which want to establish stateful sessions: 175 1761. A server using the Streamable HTTP transport **MAY** assign a session ID at 177 initialization time, by including it in an `Mcp-Session-Id` header on the HTTP 178 response containing the `InitializeResult`. 179 - The session ID **SHOULD** be globally unique and cryptographically secure (e.g., a 180 securely generated UUID, a JWT, or a cryptographic hash). 181 - The session ID **MUST** only contain visible ASCII characters (ranging from 0x21 to 182 0x7E). 1832. If an `Mcp-Session-Id` is returned by the server during initialization, clients using 184 the Streamable HTTP transport **MUST** include it in the `Mcp-Session-Id` header on 185 all of their subsequent HTTP requests. 186 - Servers that require a session ID **SHOULD** respond to requests without an 187 `Mcp-Session-Id` header (other than initialization) with HTTP 400 Bad Request. 1883. The server **MAY** terminate the session at any time, after which it **MUST** respond 189 to requests containing that session ID with HTTP 404 Not Found. 1904. When a client receives HTTP 404 in response to a request containing an 191 `Mcp-Session-Id`, it **MUST** start a new session by sending a new `InitializeRequest` 192 without a session ID attached. 1935. Clients that no longer need a particular session (e.g., because the user is leaving 194 the client application) **SHOULD** send an HTTP DELETE to the MCP endpoint with the 195 `Mcp-Session-Id` header, to explicitly terminate the session. 196 - The server **MAY** respond to this request with HTTP 405 Method Not Allowed, 197 indicating that the server does not allow clients to terminate sessions. 198 199### Sequence Diagram 200 201```mermaid 202sequenceDiagram 203 participant Client 204 participant Server 205 206 note over Client, Server: initialization 207 208 Client->>+Server: POST InitializeRequest 209 Server->>-Client: InitializeResponse<br>Mcp-Session-Id: 1868a90c... 210 211 Client->>+Server: POST InitializedNotification<br>Mcp-Session-Id: 1868a90c... 212 Server->>-Client: 202 Accepted 213 214 note over Client, Server: client requests 215 Client->>+Server: POST ... request ...<br>Mcp-Session-Id: 1868a90c... 216 217 alt single HTTP response 218 Server->>Client: ... response ... 219 else server opens SSE stream 220 loop while connection remains open 221 Server-)Client: ... SSE messages from server ... 222 end 223 Server-)Client: SSE event: ... response ... 224 end 225 deactivate Server 226 227 note over Client, Server: client notifications/responses 228 Client->>+Server: POST ... notification/response ...<br>Mcp-Session-Id: 1868a90c... 229 Server->>-Client: 202 Accepted 230 231 note over Client, Server: server requests 232 Client->>+Server: GET<br>Mcp-Session-Id: 1868a90c... 233 loop while connection remains open 234 Server-)Client: ... SSE messages from server ... 235 end 236 deactivate Server 237 238``` 239 240### Backwards Compatibility 241 242Clients and servers can maintain backwards compatibility with the deprecated [HTTP+SSE 243transport]({{< ref "/specification/2024-11-05/basic/transports#http-with-sse" >}}) (from 244protocol version 2024-11-05) as follows: 245 246**Servers** wanting to support older clients should: 247 248- Continue to host both the SSE and POST endpoints of the old transport, alongside the 249 new "MCP endpoint" defined for the Streamable HTTP transport. 250 - It is also possible to combine the old POST endpoint and the new MCP endpoint, but 251 this may introduce unneeded complexity. 252 253**Clients** wanting to support older servers should: 254 2551. Accept an MCP server URL from the user, which may point to either a server using the 256 old transport or the new transport. 2572. Attempt to POST an `InitializeRequest` to the server URL, with an `Accept` header as 258 defined above: 259 - If it succeeds, the client can assume this is a server supporting the new Streamable 260 HTTP transport. 261 - If it fails with an HTTP 4xx status code (e.g., 405 Method Not Allowed or 404 Not 262 Found): 263 - Issue a GET request to the server URL, expecting that this will open an SSE stream 264 and return an `endpoint` event as the first event. 265 - When the `endpoint` event arrives, the client can assume this is a server running 266 the old HTTP+SSE transport, and should use that transport for all subsequent 267 communication. 268 269## Custom Transports 270 271Clients and servers **MAY** implement additional custom transport mechanisms to suit 272their specific needs. The protocol is transport-agnostic and can be implemented over any 273communication channel that supports bidirectional message exchange. 274 275Implementers who choose to support custom transports **MUST** ensure they preserve the 276JSON-RPC message format and lifecycle requirements defined by MCP. Custom transports 277**SHOULD** document their specific connection establishment and message exchange patterns 278to aid interoperability.