An MCP server is either a program on your own machine or a URL on the internet. That reads like a deployment detail. It is not. The choice decides who can use the server, what authentication it needs, whether one operator can fix a bug for everybody, and whether a tool call that takes a while can say anything before it finishes. Streamable HTTP is the transport that makes the URL option work.
A pipe or a URL
The simplest way to run an MCP server is locally. The client launches the server as a child process and talks to it over standard input and output — the same pipes any command-line program uses. Requests go down one, responses come back up the other.
That arrangement has real virtues. There is no network, so there is nothing to authenticate — the operating system's process boundary is the security boundary. There is no uptime to worry about, and the server can touch local files precisely because it is local. For a tool that reads your own working directory, nothing else comes close.
Its limits are all the same limit: the server exists only for the person who launched it. One user, one machine, one process. Installing it is that person's problem and so is updating it. A client that cannot spawn a subprocess — anything hosted, anything running in a browser — cannot reach it at all.
An HTTP transport inverts each of those. The server is a URL. One deployment serves everyone who has credentials for it, and the operator ships a fix once. Any client that can make an HTTP request can connect, including clients running in someone else's data center, which is why pointing an agent framework at a server usually comes down to a URL and a header.
And because the endpoint is reachable by anyone who learns the address, it needs real authentication — a credential on every request, checked by the server. That is not a drawback of the transport. It is what remote means.
The problem streaming solves
In the plainest arrangement, a tool call is a request and a response — the client sends it, waits, and receives the result. That is fine until a call takes long enough that silence becomes a problem.
Long work has intermediate state worth reporting: progress, a partial result, a line naming which stage it reached. A bare request and response has nowhere to put any of it — the information exists and the shape of the exchange discards it, leaving the client to choose between a spinner and a timeout.
The obvious fix is a persistent two-way connection, which is what WebSockets are for. They work, but they cost something. A WebSocket is a protocol upgrade, and upgrades are the part of HTTP that intermediaries handle least uniformly — proxies, gateways and load balancers treat an ordinary request as routine and an upgrade as a special case somebody has to have configured.
Streaming that is still just HTTP
HTTP already has a way for a server to hold a response open and emit events on it as they happen: server-sent events, a one-directional stream from server to client. Same request, same port, same TLS, same intermediaries. And server-to-client is exactly the direction progress needs to travel.
That is the shape streamable HTTP uses. The client posts a message to a single endpoint. The server can answer with one complete response, the way any API would, or it can keep the response open and stream a sequence of events that ends with the result. A fast call looks like an ordinary API call; a slow one becomes a stream without a second connection, a second port, or a second protocol.
The operational consequence is the real prize. A remote MCP server deploys like a web application, because it is one — same TLS termination, same load balancer, same logs, same health checks as everything else running.
Stateless is the point
The second thing this transport gets right is not requiring the server to remember you.
If every request carries what the server needs — the credential and the call — then any instance can serve any request. The deployment can be restarted, scaled out, or rolled forward mid-conversation and no client notices. Sessions are available for servers that genuinely need continuity between calls, but a server whose tools each stand alone is cheaper to run and much harder to break by losing a machine.
RelayLink's server runs stateless for that reason. Its endpoint is /mcp and its credential is an X-RelayLink-Key header pasted into connector settings. Every call carries that key, the server does the work, the response ends. There is no transport session to resume.
What the transport does not do
Three limits worth stating.
Streaming does not make anything faster. It makes waiting legible. A slow tool is still slow, and a progress event is not a result.
A streaming-capable transport does not oblige a server to push. Nothing about HTTP makes a server volunteer anything. RelayLink is a plain example: there is no server-initiated notification when correspondence arrives. An assistant finds out by calling check_inbox, and the out-of-band nudge to the human is an ordinary email. The transport could carry a push; the product does not send one.
Remote means trusting an operator. A local server runs under your own account. A remote one runs on hardware you do not control, sees what you send it, and is exactly as trustworthy as the people who deploy it. Authentication proves who is calling; what a caller is then permitted to do is a separate question living in the server's design, which is where tool annotations and their limits come in.
Streamable HTTP is the reason "add a connector" can mean pasting a URL rather than installing software. The protocol itself is documented at modelcontextprotocol.io. For the layer above the transport, MCP in plain English covers clients, servers and tools — and connecting one takes a URL and a key.