Implementation Guide

    How to run a stdio MCP server in a container with no network access

    Launch the server through the container runtime instead of as a host process, keep stdin open, and set the network mode to none. The client still talks to the server over stdin and stdout, which need no network interface. Add a read-only root filesystem, dropped capabilities, no-new-privileges, a non-root user, minimal mounts and explicit environment variables. Then verify from inside the container. This constrains the process only. It does not govern what the server's tools do with the files, secrets and tool calls you still allow.

    Verify that isolation works

    1. 1

      Check interfaces

      List network interfaces. Only loopback should appear, with no external address or default route.

    2. 2

      Attempt outbound connections

      Try to resolve a hostname and open a connection to an external address. Both should fail immediately.

    3. 3

      Test filesystem writes

      Try to create a file in the root filesystem and in each mount. Writes should fail everywhere except the paths you intended to be writable.

    4. 4

      Inspect privileges

      Confirm the process runs as the non-root user and that its effective capability set is empty.

    5. 5

      Dump the environment

      Print environment variables and confirm that only the ones you passed are present, with no tokens or cloud credentials.

    6. 6

      Confirm the protocol still works

      Connect the real client and complete an initialisation and a tool call, to prove stdin and stdout function under the restrictions.

    Why stdio servers can run without a network

    MCP defines two transports: stdio for local servers and Streamable HTTP for remote ones. With stdio, the client launches the server as a process and exchanges messages through that process's standard streams. There is no listening MCP endpoint, so the transport itself needs no network interface.

    That is what makes a network-less container practical. If the container runtime is the launched process, the client can pipe messages through the runtime into the container. The server sees ordinary stdin and stdout, and it does not matter that it has no route anywhere.

    The transport property is not a security boundary, though. OWASP is explicit that stdio avoids a listening endpoint but does not restrict the server process's filesystem, network or credential access. A server started as a normal host process inherits whatever the invoking user can reach. The container is what removes that inheritance, and disabling the network is one of several restrictions it should apply.

    Configure the container

    Change the client's server entry so the command is the container runtime and the server is an argument. With Docker, the shape is: docker run --rm -i --network none --read-only --cap-drop ALL --security-opt no-new-privileges --user 10001:10001 your-mcp-server-image. Use -i so stdin stays open. Do not allocate a TTY, because terminal handling can corrupt the message stream. Write diagnostics to stderr, never to stdout.

    Build dependencies into the image ahead of time. A server that fetches packages at startup will fail with no network, and that failure is a useful signal that the server was relying on runtime downloads. Pin the image by digest where your process allows it, so the artifact you reviewed is the one that runs.

    Each setting addresses a distinct exposure:

    • Network mode none: The container gets only a loopback interface. Never use host networking, which removes the namespace separation entirely.
    • Read-only root filesystem: Prevents the server modifying its own image. Provide a small tmpfs if it needs scratch space.
    • Dropped capabilities and no-new-privileges: Start from zero Linux capabilities and block privilege gain through setuid binaries. Never run privileged, and do not widen the allowed system-call set.
    • Non-root user: Limits what the process can do if it escapes its own logic, and limits write access to mounted paths.
    • Minimal mounts: Mount only the directories the server needs, read-only where possible. Avoid sensitive host paths such as /etc or /boot, and keep credential stores, SSH keys and cloud CLI configuration out of reach.
    • Explicit environment variables: Pass only the variables the server requires, by name. Do not forward the client's full environment.

    What network isolation does not cover

    A no-network container closes the direct exfiltration path from the server process. Several other paths remain.

    Mounts are the first. Anything you mount into the container is readable by the server, and anything mounted writable can be changed. A broad mount of a home directory undoes most of the benefit. NIST's container guidance flags sensitive host directory mounts and privileged mode as insecure runtime configurations for this reason.

    Secrets are the second. Environment variables, mounted credential files and tokens in tool arguments are all visible to the process. Network isolation limits where they can go from the server, but not who sees them.

    The third is the stdio channel itself. Tool inputs and outputs pass through it, and the agent acts on what comes back. OWASP's Q3 2026 exploit roundup describes an approved productivity-suite server that behaved normally for its first three tool calls, then changed its tool metadata to steer the connected agent toward SSH keys, AWS credentials, shell history and Kubernetes configuration. The server used the trusted agent to collect the secrets rather than reading the files itself. OWASP characterises this as a runtime trust failure in an approved server. Containing the server process would not have stopped it, because the agent, not the server, performed the access.

    Two supporting practices help. Separate servers that handle payment, authentication or PII from general-purpose ones, so one compromise has limited reach. Keep an allowlist of approved servers and tools, and look for unapproved servers that developers run locally.

    When a server genuinely needs outbound access

    Some servers exist to wrap a remote API or SaaS product, and they cannot function with no network. Do not weaken the default for every server to accommodate them. Start by asking, for each local server, whether it needs outbound access at all. Many that read files, query local data or transform content do not.

    For those that do, narrow the exposure rather than opening it. OWASP's agentic guidance describes isolated environments with no network access except explicitly allowed endpoints. In practice that means a dedicated container network with egress restricted to the specific destinations the server uses, applied through firewall rules or an egress proxy that you operate. Give these servers their own container profile, their own credentials scoped to the single service, and no shared mounts with isolated servers.

    Record each exception with an owner and a reason. The exception list is also your inventory of servers whose isolation is weaker than the baseline, and it tells you where tool-level controls matter most.

    Where tool-call policy enforcement fits

    Container isolation constrains the process. It answers what the server can reach. It does not answer what the server is permitted to do through the tools and data you have deliberately given it, or what the agent does with the results.

    That second question is addressed by enforcing policy on individual tool calls in the execution path. Trussed enforces policy on tool calls, including those to MCP servers: allow, redact, block, rate limit, or escalate for human approval. Enforcement happens at runtime, not through review after the fact, which matters when an approved server changes its behaviour mid-session. Each decision produces audit-ready evidence of what a call was permitted to do, which is difficult to reconstruct from container settings alone.

    The two layers are complementary. Use the container to remove network access, inherited secrets and unnecessary filesystem reach. Use tool-call policy to govern the actions that remain inside that boundary.

    Layers around a local stdio MCP server

    Transport

    stdin and stdout only, no listening endpoint

    Container

    network none, read-only root, dropped capabilities, non-root user

    Inputs

    minimal mounts and explicit environment variables

    Tool calls

    policy applied to each call in the execution path

    Add policy on tool calls to your container baseline

    See how enforcement in the execution path applies allow, redact and block decisions to MCP tool calls and produces audit-ready evidence.

    Explore Agent and Tool-Call Enforcement
    Next step

    How does your AI governance program compare?

    See where your program has gaps in less than 2 minutes.