# MCP transports

MCP defines two transports. **stdio** runs the server as a child process and speaks newline-delimited JSON over its standard input and output. **Streamable HTTP** runs the server somewhere else and speaks JSON-RPC over a single POST endpoint. Connect is remote, so it offers Streamable HTTP only, at `/mcp`.

- **Status:** Reference
- **Audience:** developer
- **Last verified:** 2026-09-10
- **Canonical:** https://connectbyjbrh.com/docs/protocols/mcp-transports/

## Choosing between them

The choice is made by where the server lives, not by preference. A server that reads files on your laptop has to run on your laptop, and stdio is the natural fit: no port, no certificate, no origin, and the operating system's process lifetime is the session lifetime. A server that reads something on the internet has no reason to be launched as a subprocess, and shipping a binary to every client to proxy an HTTP call would be work in exchange for nothing.

|  | stdio | Streamable HTTP |
|---|---|---|
| Where the server runs | As a child process of the client | Anywhere reachable by URL |
| Framing | Newline-delimited JSON on stdin/stdout | JSON-RPC in an HTTP request body |
| Lifetime | The process | Per request — nothing is held between them |
| Who can reach it | Only the parent process | Anyone who can reach the URL |
| Origin checks | Not applicable | Required when an `Origin` header is present |
| Distribution | Client must install or launch the server | Client needs the URL only |
| Used by Connect | No | Yes — `POST /mcp` |

> **Careful** Never write log output to standard output in a stdio server. That stream is the protocol channel; a stray `print` becomes a malformed message and the client sees a parse error rather than your log line. Standard error is the correct place.

## What revision 2026-07-28 removed from the HTTP transport

Earlier revisions gave the HTTP transport two features that looked useful and cost more than they returned. Both are gone.

**Protocol-level sessions** — A server used to mint an `Mcp-Session-Id` during `initialize` and expect it back on every later request. That made an ostensibly stateless HTTP endpoint stateful, which is a problem the moment there is more than one server process behind a load balancer. The header is now ignored.
**The standalone GET stream** — A client used to open `GET /mcp` and hold it as a server-to-client event stream, resuming with `Last-Event-ID` after a drop. Streams are no longer resumable and the standalone stream is gone; `Last-Event-ID` is ignored.

In exchange, every POST now carries what the server needs to know about it: the protocol version and client info in `params._meta`, mirrored into the `MCP-Protocol-Version`, `Mcp-Method` and `Mcp-Name` headers. A middlebox can route on the headers without parsing the body, and the server refuses any request where the two disagree, with `-32020`.

The practical effect is that a Streamable HTTP endpoint is now an ordinary POST endpoint. It can sit behind any load balancer, scale to any number of processes, and be tested with a single `curl` command that needs no prior handshake.

## Does Connect use both transports?

No. Connect's MCP server is remote and speaks Streamable HTTP only, at `POST /mcp`. There is no stdio build, no downloadable binary and no package to install: a client needs the URL and nothing else.

`GET /mcp` and `DELETE /mcp` answer `405` with `Allow: POST`. That is a deliberate answer rather than a missing route — an older client that opens the standalone stream is told plainly instead of waiting on a connection that would never carry a message.

A local proxy that wraps the HTTP endpoint in stdio, as several client ecosystems provide, works fine. Connect neither ships nor endorses a particular one; from the server's point of view a proxy is just another HTTP client.

## Failure modes you will actually hit

1. Point a client at `https://connectbyjbrh.com/mcp` and call `tools/list`.
   - Result: A JSON-RPC result with ten tool descriptors. If you get `405`, your client issued a GET.
2. Send more than 120 requests in a minute from one address.
   - Result: `429`, with the limit named in the error message. Back off; the window is a rolling minute, not a fixed one.
3. Send a JSON array of messages.
   - Result: `400`. Batching is not accepted — send one JSON-RPC message per request.
4. Send a body larger than 256 KB.
   - Result: `413`, refused before parsing.

One asymmetry catches people out: a notification — a message with no `id` — gets `202` and an empty body, not a JSON-RPC result. A client that waits for a response to `notifications/initialized` waits forever.

## Questions

### Is Streamable HTTP the same thing as SSE?

Not any more. An earlier revision layered server-sent events over a separate GET stream, and people came to call the whole transport 'SSE'. Revision 2026-07-28 removed the standalone stream, so Connect's endpoint is a plain POST that returns a JSON body. See [Streamable HTTP](/docs/protocols/streamable-http/) for the transport in detail.

### Can I run Connect's MCP server locally over stdio?

There is no stdio build to run. The documentation tools read a generated corpus that is published on the website, so a local copy would have nothing to read that the URL does not already give you. A generic stdio-to-HTTP proxy from your client's ecosystem is the supported way to bridge, if your client only speaks stdio.

### Does the transport decide whether a tool needs authentication?

No. The transport carries messages; authorisation is a separate concern. Connect's public documentation tools need no credential because of what they read, not because of how they are reached.

## Related

- [Model Context Protocol](https://connectbyjbrh.com/docs/protocols/mcp/)
- [Streamable HTTP](https://connectbyjbrh.com/docs/protocols/streamable-http/)
- [MCP security](https://connectbyjbrh.com/docs/protocols/mcp-security/)
- [Using Connect from any MCP client](https://connectbyjbrh.com/developers/mcp-client-generic/)
- [JSON-RPC 2.0](https://connectbyjbrh.com/docs/protocols/json-rpc/)

## What this page is based on

- https://modelcontextprotocol.io/specification/2026-07-28
- `backend/app/mcp_server.py` — the POST-only route, limits and 405 handler
- `docs-source/facts.py` — PROTOCOLS['mcp'].transport
