In the recent article, Building Isolated AI Code Environments with Cerebras and Docker Compose, our friends at Cerebras showcased how one can build a coding agent to use worlds fastest Cerebras’ AI inference API, Docker Compose, ADK-Python, and MCP servers.
In this post, we’ll dive deeper into the underlying technologies and show how the pieces come together to build an AI agent environment that’s portable, secure, and fully containerized. You’ll learn how to create multi-agent systems, run some agents with local models in Docker Model Runner, and integrate custom tools as MCP servers into your AI agent’s workflow.
We’ll also touch on how to build a secure sandbox for executing the code your agent writes, an ideal use case for containers in real-world development.
始める
To begin, clone the repository from GitHub and navigate into the project directory.
Get the code for the agent, and prepare the .env file to provide your Cerebras API key:
git clone https://github.com/dockersamples/docker-cerebras-demo && cd docker-cerebras-demo
Next, prepare the .env file to provide your Cerebras API key. You can get a key from the Cerebras Cloud platform.
# This copies the sample environment file to your local .env file
cp .env-sample .env
Now, open the .env
file in your favorite editor and add your API key to the CEREBRAS_API_KEY
line. Once that’s done, run the system using Docker Compose:
docker compose up --build
The first run may take a few minutes to pull the model and containers. Once it’s up, you can see the agent at localhost:8000
.
The first run may take a few minutes to pull the necessary Docker images and the AI model. Once it’s running, you can access the agent’s interface at http://localhost:8000
. From there, you can interact with your agent and issue commands like “write code,” “initialize the sandbox environment,” or request specific tools like “cerebras, curl docker.com for me please.”
Understanding the Architecture
This demo follows the architecture from our Compose for Agents repository, which breaks down an agent into three core components:
- The Agentic Loop: This is the main application logic that orchestrates the agent’s behavior. In our case, it’s an ADK-Python-based application. The ADK-Python framework also includes a visualizer that lets you inspect tool calls and trace how the system reached specific decisions.

- The MCP Tools: These are the external tools the agent can use. We provide them securely via the Docker MCP Gateway. In this app we use context7 and node sandbox MCP servers.
- The AI Model: You can define any local or remote AI model you want to use. Here, we’re using a local Qwen model for routing between the local agent and the powerful Cerebras agent which will use Cerebras API.
Cerebras Cloud serves as a specialized, high-performance inference backend. It can run massive models, like a half-trillion parameter Qwen coder, at thousands of tokens per second. While our simple demo doesn’t require this level of speed, such performance is a game-changer for real-world applications.
Most of the prompts and responses are a few hundred tokens long, as they are simple commands to initialize a sandbox or write some JavaScript code in it. You’re welcome to make the agent work harder and see Cerebras’ performance on more verbose requests.
For example, you can ask the Cerebras agent to write some JavaScript code, and see it call the functions from the MCP tools to read and write the files and run them as you see on the screenshot below.

Building a Custom Sandbox as an MCP Server
A key feature of this setup is the ability to create a secure sandbox for code execution. To do this, we’ll build a custom MCP server. In our example, we enable two MCP servers:
context7
: This gives our agent access to the latest documentation for various application frameworks.node-code-sandbox
: This is our custom-made sandbox for executing the code our agent writes.
You can find the implementation of our Node.js sandbox server in the node-sandbox-mcp GitHub repository. It’s a Quarkus application written in Java that exposes itself as an stdio
mcp-server and uses the awesome Testcontainers library to create and manage the sandbox containers programmatically.
An important detail is that you have full control over the sandbox configuration. We start the container with a common Node.js development image and, as a crucial security measure, disable its networking. But since it’s a custom MCP server, you can enable any security measures you deem necessary.
Here’s a snippet of the Testcontainers-java code used to create the container:
GenericContainer sandboxContainer = new GenericContainer<>("mcr.microsoft.com/devcontainers/javascript-node:20")
.withNetworkMode("none") // disable network!!
.withWorkingDirectory("/workspace")
.withCommand("sleep", "infinity");
sandboxContainer.start();
Testcontainers provides a flexible, idiomatic API to interact with the sandbox. Running a command or writing a file becomes a simple one-line method call:
// To execute a command inside the sandbox
sandbox.execInContainer(command);
// To write a file into the sandbox
sandbox.copyFileToContainer(Transferable.of(contents.getBytes()), filename);
The actual implementation has a bit more glue code for managing background processes or selecting the correct sandbox if you’ve created multiple, but these one-liners are the core of the interaction.
Packaging and Using the Custom Server
To use our custom server, we first need to package it as a Docker image. For Quarkus applications, a single command does the trick:
./mvnw package -DskipTests=true -Dquarkus.container-image.build=true
This command produces a local Docker image and outputs its name, something like:
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor] Built container image shelajev/node-sandbox:1.0.0-SNAPSHOT
Since we’re running everything locally, we don’t even need to push this image to a remote registry. You can inspect this image in Docker Desktop and find its hash, which we’ll use in the next step.

Integrating the Sandbox via the MCP Gateway
With our custom MCP server image ready, it’s time to plug it into the MCP Gateway. We’ll create a custom catalog file (mcp-gateway-catalog.yaml) that enables both the standard context7
server and our new node-code-sandbox
.
Currently, creating this file is a manual process, but we’re working on simplifying it. The result is a portable catalog file that mixes standard and custom MCP servers.
Notice two key things in the configuration for the node-code-sandbox MCP server in the catalog:
longLived: true
: This tells the gateway that our server needs to persist between the tool calls to track the sandbox’s state.image:
: We reference the specific Docker image using itssha256
hash to ensure reproducibility.
If you’re building the custom server for the sandbox MCP, you can replace the image reference with the one your build step produced.
longLived: true
image: olegselajev241/node-sandbox@sha256:44437d5b61b6f324d3bb10c222ac43df9a5b52df9b66d97a89f6e0f8d8899f67
Finally, we update our docker-compose.yml
to mount this catalog file and enable both servers:
mcp-gateway:
# mcp-gateway secures your MCP servers
image: docker/mcp-gateway:latest
use_api_socket: true
command:
- --transport=sse
# add any MCP servers you want to use
- --servers=context7,node-code-sandbox
- --catalog=/mcp-gateway-catalog.yaml
volumes:
- ./mcp-gateway-catalog.yaml:/mcp-gateway-catalog.yaml:ro
When you run docker compose up
, the gateway starts, which in turn starts our node-sandbox
MCP server. When the agent requests a sandbox, a third container is launched – the actual isolated environment.

You can use tools like Docker Desktop to inspect all running containers, view files, or even open a shell for debugging.

The Security Benefits of Containerized Sandboxes
This containerized sandbox approach is a significant security win. Containers provide a well-understood security boundary with a smaller vulnerability profile than running random internet code on your host machine, and you can harden them as needed.
Remember how we disabled networking in the sandbox container? This means any code the agent generates cannot leak local secrets or data to the internet. If you ask the agent to run code that tries to access, for example, google.com
, it will fail.

This demonstrates a key advantage: granular control. While the sandbox is cut off from the network, other tools are not. The context7
MCP server can still access the internet to fetch documentation, allowing the agent to write better code without compromising the security of the execution environment.

Oh, and a neat detail is that when you stop the containers managed by compose, it also kills the sandbox MCP server, and that in turn triggers Testcontainers to clean up all the sandbox containers, just like it cleans after a typical test run.
Next Steps and Extensibility
This coding agent is a great starting point, but it isn’t production-ready. For a real-world application, you might want to grant controlled access to resources like the npm registry. You could, for example, achieve this by mapping your local npm cache from the host system into the sandbox. This way, you, the developer, control exactly which npm libraries are accessible.
Because the sandbox is a custom MCP server, the possibilities are endless. You can build it yourself, tweak it however you want, and integrate any tools or constraints you need.
結論
In this post, we demonstrated how to build a secure and portable AI coding agent using Docker Compose and the MCP Toolkit. By creating a custom MCP server with Testcontainers, we built a sandboxed execution environment that offers granular security controls, like disabling network access, without limiting the agent’s other tools. We connect this coding agent to Cerebras API, so we get incredible inference speed. This architecture provides a powerful and secure foundation for building your own AI agents. We encourage you to clone the repository and experiment with the code! You probably already have Docker and can sign up for a Cerebras API key here.