Agents and tools
stdio and HTTP transports
Two ways to move MCP messages: a local subprocess over stdin/stdout, or a remote HTTP server with OAuth.
MCP's data model stays the same either way: JSON-RPC requests such as tools/list and tools/call. The transport is how those bytes move. Pick wrong and you either cannot share the connector, or you publish a remote shell on an open port.
Concept
Before you start: a transport is the pipe under the protocol. stdio means the host spawned a process and speaks on stdin/stdout. Streamable HTTP means the server listens on a URL.
The big idea
stdio. The host starts the server as a subprocess. Credentials often come from that process's environment. There is no network surface. The trust boundary is "code you chose to run on this machine." This fits local tools: filesystem access, IDE helpers, a personal billing CLI.
Streamable HTTP. The server listens on a URL. The client connects remotely. This is what shared team servers and SaaS connectors need. Authorization typically follows an OAuth 2.1-style profile so users grant scoped access without pasting long-lived API keys into config files.
Trade-off
Use stdio for personal and local development tools. Use HTTP plus OAuth when several users or machines must share a connector. Do not expose a privileged stdio-style server over raw HTTP without auth. That publishes a remote shell for whoever can hit the port.
Walking through the isolation difference
A stdio server is a per-user process. Customer A's session cannot reuse Customer B's connection state, because there is no shared process. That is simpler isolation, and a worse fit for shared SaaS.
An HTTP server serving many users must authenticate every call. Reusing one customer's connection state for another is a tenancy bug, the same class of bug as any multi-tenant API.
Timeouts sit on both sides. Hosts abandon slow calls. Set a server-side timeout under the host's limit and return a structured error the model can retry or explain.
Log the tool name, latency, error class and a hash of the arguments. Do not log raw payloads that hold personal data. Correlate with the host's conversation id if the host sends one.
stdio: host spawns process → env credentials → no network port
HTTP: client opens URL → OAuth grant → shared, multi-userSchema changes travel over either transport the same way. Removing a required field without a new tool name breaks every prompt that learned the old shape. Publish a changelog, and bump the server version the host pins.
Common mistakes
- Putting a local privileged server on HTTP with no auth. The process was safe only because it was not reachable.
- One OAuth grant that does everything. Scope down. Split servers by trust level.
- Assuming stdio solves multi-tenancy in a SaaS host. Stdio isolation is per process. A shared HTTP server needs per-call auth.
Check yourself
- A filesystem helper should run on which transport? stdio. It is local, and the trust boundary is the process you spawned.
- Why does a shared billing connector need HTTP plus OAuth? Several users and machines must call it, and they should grant scoped access instead of sharing a long-lived key.
Key takeaways
- stdio is a local subprocess. HTTP is a remote, shareable server.
- OAuth is how remote users grant scoped access without pasting keys.
- Authenticate every HTTP call. Never reuse one tenant's connection for another.
Further learning
Next, see what a hostile or sloppy server can do in MCP security.
Related
Tools, resources and prompts
MCP servers expose three primitives: tools the model calls, resources the app can read, and prompt templates the user can insert.
MCP security
A connected server can steer the model, act with the user's token and read tool results that contain attacker text. Pin, scope and enforce policy in code.
OAuth and OpenID Connect
OAuth 2.0 delegates access to a third-party app. OpenID Connect adds a login identity on top. The authorization code flow with PKCE is the safe default.