Skip to content

Running MCP tools from Docker doesn't properly terminate the container #547

Closed

Description

@dgouvea

Describe the bug
When running MCP tools from Docker, the close doesn't properly terminate the container. It keeps running in the background.
The tools are working correctly. However, because they have to run using -i it keeps running the container.
The main problem is that when the StdioClientTransport .close() is called, it executes this._abortController.abort(), but doesn't terminate the container for some reason. So when my application finishes, it never exits, because the child process is still running.

To Reproduce
Steps to reproduce the behavior:

  1. Create an MCP client and configure a Docker MCP server:
{
  "mcpServers": {
    "time": {
      "command": "docker",
      "args": [
        "run",
        "-i",
        "--rm",
        "mcp/time"
      ]
    }
  }
}
  1. Use a prompt to call the MCP server
  2. Call StdioClientTransport .close()
  3. Your application will hang and never finish

Expected behavior
It should terminate all child processes started by StdioClientTransport. If the process doesn't terminate properly, it should be killed.

Logs
No relevant logs.

Additional context
I am running it on Mac OS Sequoia using the latest version of Docker and the latest version of the library 1.12.0.

Activity

  1. added a commit that references this issue on May 26, 2025
  2. dgouvea commented on May 26, 2025

    @dgouvea
    Author

    I proposed a fix for this problem here, and I am open to any changes you suggest.

  3. rishitank commented on Jun 16, 2025

    @rishitank

    +1, This is a crucial issue, which if not fixed would cause your local setup to be overcrowded with orphaned Docker Containers that should have been stopped. This is especially the case if you are using dockerized MCP servers across multiple projects where each project is using an AI coding agent. Currently the only workaround at the MCP server level is to fork their repository and implement proper process shutdown behaviour yourself, build and then run the docker container, which is not the most scalable solution if you rely on many MCP servers for different things.

  4. rishitank commented on Jun 18, 2025

    @rishitank

    Alternatively, I was able to work around this by passing the --init flag to the docker run command.

    Summary

    The --init flag for docker run tells Docker to inject a minimal init process (based on Tini) as PID 1 inside the container, which forwards signals (e.g., SIGTERM, SIGINT) to your application and reaps zombie child processes automatically, ensuring clean shutdowns and preventing process table leaks without requiring any changes to your Docker images. oai_citation:0‡docs.docker.com oai_citation:1‡baeldung.com

    What Is the --init Flag?

    • When you add --init to docker run, Docker launches its built-in init binary (docker-init, Tini-based) as the first process (PID 1) inside the container before your specified command. oai_citation:2‡docs.docker.com

    How It Works Internally

    1. Init Injection
      Docker locates the docker-init executable bundled with the daemon (often /usr/bin/docker-init) and starts it as PID 1, then execs your application process. oai_citation:3‡stackoverflow.com
    2. Signal Forwarding
      The init process proxies signals (SIGTERM, SIGINT, etc.) from the Docker daemon to all descendant processes, allowing each to handle shutdown gracefully. oai_citation:4‡docs.docker.com
    3. Zombie Reaping
      As PID 1, the init process performs wait() calls on exited child processes, preventing zombie accumulation in the container. oai_citation:5‡docs.docker.com

    Benefits of Using --init

    Usage Examples

    # Run an image with the built-in init for PID 1 semantics
    docker run --init my-image
  5. sanguino commented on Sep 6, 2025

    @sanguino

    Hi,

    @rishitank It works!!! Thank you so much, I was going crazy

  6. felixweinberger commented on Nov 3, 2025

    @felixweinberger
    Contributor

    Closing as this seems resolved by the response from @rishitank, thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions