In this guide
A tool that reads a developer's local project has a different operating problem from a service shared by a team. Both can expose the same MCP methods. They should not automatically inherit the same transport and deployment plan.
Transport selection determines who starts the process, who can reach it, where credentials live and what must survive a disconnect. Begin there, rather than choosing HTTP because it feels more familiar or stdio because it sounds private.
The examples here use the dated MCP transport specification as their protocol baseline. Check the version negotiated by your actual client and SDK before applying version-specific behavior.
Start with process ownership
With stdio, the client launches a subprocess and exchanges protocol messages through standard input and output. That fits a local integration whose lifecycle belongs to one client. The server must keep ordinary logs off standard output, because that stream carries protocol messages.
With Streamable HTTP, the server runs independently and clients connect to an endpoint. That is useful when the integration needs a shared deployment, centralized operations or access from another machine. It also gives you a network service to authenticate, monitor and maintain.
Those are operating tradeoffs, not security grades. A local subprocess can still read files, launch other processes or use credentials available to it. A remote service can have strong isolation and narrow permissions. Ask which boundary you can operate reliably.
| Situation | Reasonable starting point | Extra question to resolve |
|---|---|---|
| One desktop client reading a local checkout | stdio | Which files and environment variables reach the subprocess? |
| Several people using one managed integration | HTTP | How are identity and tenant permissions enforced per request? |
| A local service used by more than one client | Local HTTP, if needed | How are browser-origin requests and credentials handled? |
| A containerized worker launched for one job | Either, depending on the client | Who owns shutdown, output limits and cleanup? |
The table is a decision aid. It does not imply that a particular client supports every transport or deployment pattern.
Local HTTP needs an explicit threat model
Binding a listener to loopback reduces network reachability. It does not mean every request arriving there comes from the intended client. Browser behavior, local applications and configuration mistakes still matter.
For Streamable HTTP, the referenced transport specification requires Origin validation and an HTTP 403 response when that header is present and invalid. It also recommends loopback binding for a local service and authentication for connections. In a concrete deployment, also review accepted Host values, reverse-proxy behavior and forwarded headers. These checks should reflect a fixed deployment policy rather than trusting whatever hostname the incoming request happens to contain.
Do not treat CORS configuration as authentication. CORS governs particular browser access behavior; it does not identify a principal to your service. A command-line client is not obliged to enforce a browser's CORS rules. Decide separately who may call the endpoint and what that caller may do.
When no Origin header is present, follow the protocol and your client requirements deliberately. An absent browser header should not turn a protected endpoint into an anonymous endpoint. Authentication and operation-level authorization must still apply.
A container can change your assumption
Consider a local file-search server. In a direct installation it listens on loopback. Someone packages it in a container, switches the listener to all interfaces inside the container and publishes its port with a short example command.
The internal bind may be necessary for container networking. The host-side publication is a separate decision. A host publication restricted to loopback has different reachability from one available on all host interfaces. The documentation should say which one is intended.
Test the command users will actually copy, including the port mapping and token configuration. A secure application default cannot compensate for an example that exposes the listener more broadly without explaining the change.
Keep startup behavior explicit. If a shared-network configuration requires credentials, fail with an actionable message when credentials are missing. A warning buried among successful startup logs is easy to mistake for a safe working configuration.
Disconnects are part of the design
A dropped connection is not reliable evidence that a state-changing operation never happened. The referenced Streamable HTTP specification explicitly distinguishes disconnection from cancellation. Your application still needs to resolve the outcome of operations with external effects.
Imagine a tool creates a support case, then the connection drops before the result arrives. Blindly repeating the creation can produce two cases. Give the operation a server-enforced idempotency design or a way to look up the previously accepted request. Define the scope and lifetime of any deduplication key; a key reused across different arguments should not silently reuse an unrelated result.
For stdio, test the analogous process failure. If the client kills the subprocess after a downstream write, a restarted server still needs an honest answer about the operation's outcome. A transport change does not remove the ambiguity of an interrupted write.
Check the deployed path
Run a small acceptance matrix before calling a transport configuration ready:
- The intended client can initialize and discover tools using the supported protocol version.
- A missing or wrong credential cannot invoke a protected operation.
- An unapproved Origin or hostname does not bypass the endpoint's deployment policy.
- The listener and published port have the intended reachability.
- Logs never corrupt a stdio protocol stream.
- An interrupted operation is reported as completed, failed or unknown using evidence, rather than guessed from the socket state.
Use a non-sensitive test resource for these checks. For a local deployment, inspect reachability from another machine only where you are authorized to test the network.
Choose the smallest operating commitment
If one client owns a local process and no sharing is needed, stdio can avoid unnecessary network-service operations. If the service must be shared, HTTP may be the simpler system overall, provided identity, isolation and lifecycle management are designed with it.
Write the decision down with the expected clients, credential model and reachability. Revisit it when any of those change. Moving a service from one desktop to a shared deployment deserves a fresh review of those assumptions, even when the MCP methods stay the same.
Sources and further reading
- MCP transports
stdio and Streamable HTTP models, security requirements and disconnect/cancellation distinction.