ai agent development

Move an MCP server from stdio to HTTPS with Docker

Package an HTTP-capable MCP server in a container, put a reverse proxy in front of it, and check transport, access control and session behavior before sharing it.

By Otto Skov·October 24, 2026·4 min read
What matters here
  1. A stdio MCP server needs an HTTP transport or bridge before a reverse proxy can expose it.
  2. SSE connections need proxy buffering disabled and a read timeout long enough for open streams.
  3. HTTPS alone does not authorize MCP clients; protect endpoints and check how sessions are isolated.

A local MCP server often starts as a process that reads from standard input and writes to standard output. That works when one client launches the server on the same machine. It does not, by itself, create an HTTPS endpoint other clients can reach.

To deploy an MCP server for remote clients, first make sure it speaks an HTTP transport, then run it in a container and route traffic through a TLS-terminating reverse proxy. ZES publishes guides on MCP and agent development; the same deployment basics apply whether the tool exposes project files, data or another service.

1. Confirm the transport before building the image

Check the server's documentation and identify its transport. A stdio-only server cannot be made into an HTTP service just by putting it in Docker. You need a server implementation that supports HTTP, or a suitable bridge that translates between the client's HTTP connection and the server's stdio process. Treat that bridge as part of the system: it must handle client connections, errors and shutdowns.

Check client compatibility, too. MCP clients and servers may support different HTTP transports. Server-Sent Events (SSE) has been used for MCP over HTTP, while newer implementations may use Streamable HTTP. Do not assume an endpoint or transport works with every client. Match the server, client and proxy configuration, and record the endpoint path your server actually uses.

If you are starting from a local filesystem tool, the narrow-allowlist approach for an MCP filesystem server is a useful boundary to preserve when moving it off a developer's machine.

2. Build a container that runs the server

Package the server and its runtime dependencies in an image. The container's main process should be the MCP server or its transport bridge, not an interactive shell. Configure it to listen on the container interface, typically 0.0.0.0, rather than only on 127.0.0.1; otherwise, the proxy may not be able to reach it.

Keep secrets out of the image and source repository. Pass credentials at runtime through the deployment environment's secret mechanism. Give the server only the credentials and filesystem access its tools need. For a filesystem tool, mount only the required project directory, preferably read-only unless writes are essential.

A small Compose service might look like this, with the image build and port adjusted to the server you chose:

services:
mcp:
build: .
restart: unless-stopped
expose:
- "3000"
environment:
PORT: "3000"

This is a wiring example, not a universal MCP configuration: the server must actually read that port setting and serve the chosen transport. Using expose makes the service available to other containers on the Compose network without publishing its port directly on the host. Put the reverse proxy on that same network.

3. Route HTTPS traffic through the proxy

Point a hostname, such as tools.example.com, at the reverse proxy. Configure it to terminate HTTPS and forward requests to the MCP container over the private container network. The public URL path must match the path configured by the server and expected by the client; do not copy a path from another MCP implementation without checking.

For SSE, the proxy must allow the response stream to remain open. With Nginx, that commonly means disabling proxy buffering for the MCP route and setting a read timeout suitable for a long-lived connection. Confirm that the proxy forwards the request and response headers the transport requires, and that it does not replace a streaming response with a buffered one. If your server uses Streamable HTTP instead, follow its requirements rather than assuming all SSE settings apply.

A relevant companion is BuiltToWinWeb's guide to putting an MCP server on a web domain, which also addresses the domain-level setup around a deployed server.

4. Protect the endpoint and test real clients

TLS encrypts traffic; it does not decide which clients may use a tool. Require authentication at the server or at a trusted proxy layer, and make sure the method is compatible with the MCP clients you intend to support. Do not expose a tool with write access on a public hostname without an access-control plan. Limit network reach and tool permissions as well as user access.

Before sharing the URL, connect with an actual intended client. Verify that it completes the expected transport handshake, lists the tools, and can run a harmless test call. Then test a long-lived connection through the proxy, not just a quick health request. Check proxy logs and server logs for disconnects, rejected authentication and errors. A container marked as running does not prove the MCP session is usable.

Finally, decide how the service behaves with more than one client. If the server keeps mutable session data in memory, concurrent clients or restarts may produce surprising results. Confirm whether sessions are isolated and whether the server needs external storage. Use a health check only if the server exposes a suitable health endpoint, and monitor restarts and failed connections after deployment.

Keep the boundary explicit

The move from local stdio to remote MCP is a change in who can reach the tool, not just where its process runs. Keep the tool's permissions narrow, make the transport and endpoint path explicit, and test through the same HTTPS route clients will use. That turns a local developer utility into a service without mistaking a running container for a production-ready deployment.

More from ZES News
News desk operated by Stork Wire.