An MCP server that lets agents go "code mode" and execute code in isolated Docker containers. The idea is that agents are apparently bad at using mcp tools when they have too many options. Which is why we write a simplified MCP that only has very few, but powerful tools. The MCP is intended to allow the agent to just read documentation, and write code that runs or calls APIs directly instead of having to put thousands of tokens explaining each mcp tool and its parameters with each message.
Agents pick from a set of approved images (e.g. python, node, ubuntu) and
run code without touching the host. The images are either a single dockerfile (oneshot) or a compose setup (persistent).
- Oneshot images (python, node): Each
send_linescall spins up a fresh container, pipes the code to the interpreter via stdin, and returns the output. - Persistent images (ubuntu): A long-running container is started via
docker compose. Code is written to a temp script inside the container and executed withsh. State persists across calls until the session is stopped.
Here's an example of how a conversation with an agent using the MCP tools might look:
User: Hey agent, please get me the latest pull requests.
Agent: Sure! I'll use the GitHub CLI tool in a Python environment to fetch the latest pull requests. First, I'll start a session with the Python image.
{ "tool": "start_session", "args": { "image": "python" } } { "session_id": "abc123" }Agent: Great, I have a session running with ID abc123. Now I'll send the code to fetch the latest pull requests using the GitHub CLI.
{ "tool": "send_lines", "args": { "session_id": "abc123", "lines": [ "import os", "os.system('gh pr list --limit 5')" ] } } { "stdout": "Pull request 1: Fix bug in authentication etc...", "stderr": "", "return_code": 0 }Agent: There's a fix for the authentication bug. It looks good, do you want me to merge it? ...
There's purposefully not many tools to choose from so that your context window is not overwhelmed with too many options.
| Tool | Description |
|---|---|
list_images() |
List available image names |
start_session(image) |
Start a session for an image |
send_lines(session_id, lines) |
Send code to a session for execution |
stop_session(session_id) |
Stop and clean up a session |
The tools start_session and send_lines also have additional parameters for advanced use cases:
- mounting filesystem for one-shot sessions
- storing files with specific paths into persistent sessions instead of just executing code snippets
Container resource limits are configurable via CLI flags:
$ code-mode-mcp --network none --memory 512m --cpus 1 --pids-limit 256use --help to see all available options:
Export the built-in image definitions, customize them, and point the server at your copy:
# Export built-in images to a local directory
$ code-mode-mcp --export-images ./my-images
# Edit docker files of one-shot images
vim ./my-images/python/Dockerfile
# Add a new persistent image by creating a compose.yaml and Dockerfile
mkdir ./my-images/nginx
vim ./my-images/nginx/Dockerfile
vim ./my-images/nginx/compose.yaml
# Run with your custom images. You agent should now be able to tell you that a python and nginx image are available to start a session with.
$ code-mode-mcp --image-dir ./my-imagesAvailable images are detected based on if a directory contains a Dockerfile and/or a compose file. The name of the image is determined by the parent directory of the Dockerfile.
MIT License