[BUG] Docker-based MCP server containers not stopped when session ends
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
When an MCP server is configured to run via docker run in .mcp.json, the Docker container keeps running after closing Claude Code. This does not happen with non-Docker MCP servers (e.g., npx-based), which are properly cleaned up as direct child processes.
The root cause: docker run is the child process of Claude Code, but the actual container runs under the Docker daemon. Killing the docker run process does not kill the container.
A SessionEnd hook workaround is unsafe because stopping containers by image name (e.g., docker stop $(docker ps -q --filter ancestor=image-name)) would kill containers used by other concurrent Claude Code sessions — there's no way to map a container to a specific session.
What Should Happen?
The Docker container should be stopped when the Claude Code session ends, just like npx-based MCP servers are terminated.
Suggested fix: Claude Code could capture the Docker container ID when starting a Docker-based MCP server and run docker stop <container_id> during session cleanup. This would safely stop only the container belonging to the ending session.
Steps to Reproduce
- Configure a Docker-based MCP server in
.mcp.json:
``json``
{
"mcpServers": {
"postgres": {
"type": "stdio",
"command": "docker",
"args": ["run", "-i", "--rm", "crystaldba/postgres-mcp"]
}
}
}
- Start a Claude Code session (the MCP container starts automatically)
- Close/exit the Claude Code session
- Run
docker ps— the container is still running - Compare: configure an MCP server with
npxinstead ofdocker— it gets cleaned up properly on session end
Claude Model
Opus
Is this a regression?
I don't know
Claude Code Version
2.1.59
Platform
Anthropic API
Operating System
Other Linux
Terminal/Shell
Other
Additional Information
- OS: Arch Linux (6.18.9-arch1-2)
- Shell: fish
- The
--rmflag ondocker runonly removes the container after it stops, but nothing triggers the stop on session end.
9 Comments
Found 3 possible duplicate issues:
This issue will be automatically closed as a duplicate in 3 days.
🤖 Generated with Claude Code
ps aux. My issue is about docker containers as I described.I have exactly same issue on macOS
+1, same issue on MacOS, can we prioritize this?
A Stop hook can clean up Docker containers when the session ends:
The Stop hook fires on session end (normal completion, /exit, Ctrl+C) and stops any MCP containers. The PostToolUse hook tracks which containers were started during the session for reliable cleanup.
Workaround: Wrapper script + per-session PID watchdog
Each Docker MCP points to a small wrapper script instead of
dockerdirectly. The wrapper:CLAUDE_PID=$PPID— the Claude Code process that spawned it.os.setsid()(works on both macOS and Linux) that pollskill -0 $CLAUDE_PIDevery 2 s. When Claude exits by any means, the watchdog callsdocker stopon that container and terminates itself.execsdocker runwith the named container + two labels.Step-by-step setup
1. Create the wrapper script
Create
.claude/scripts/mcp-docker-launch.shin your project (adjust path as needed):Make it executable:
2. Update
.mcp.jsonFor each Docker-based MCP, change
"command": "docker"to the wrapper and remove the leading"run"fromargs(the wrapper adds it):Any Docker MCP that uses this wrapper gets automatic cleanup.
I'm on a mac, after installing the latest Docker
v.4.7.30somehow symlinks got updated and that caused mayhem.What I had to do to fix Claude is the following:
In
claude_desktop_config.json, update the "mcpServers" and "MCP_DOCKER" sectionfrom
to
I did have a global symlink to "/Users/my-name/.docker/bin/docker", but apparently Claude cannot pick that up from my
.bash_profile.So hardcoding the full path to the Docker executable did the trick..
Thanks for the report. This is the same issue as #1935 (stdio MCP child processes not terminated on exit). Consolidating tracking there.
This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.