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.