feat: Remove MCP specific code
This commit is contained in:
45
README.md
45
README.md
@@ -4,11 +4,9 @@ A Docker-based sandbox and LangChain tool set for LLM agents that need a safe, i
|
||||
|
||||
## What it provides
|
||||
|
||||
- **`DockerSandbox`** — manages a single long-running Docker container: lifecycle (`start`/`stop`), file writes via the tar archive API, and command execution with timeout enforcement.
|
||||
- **`DockerSandbox`** — manages a single long-running Docker container: lifecycle (`start`/`stop`), file writes via the tar archive API, and command execution with timeout enforcement. Volumes, ports, environment variables, and capabilities are all caller-supplied.
|
||||
- **LangChain tools** — a ready-to-use set of tools that expose the sandbox to an agent: `bash`, `read_file`, `write_file`, `edit_file`, `list_dir`, `delete_file`, `move_file`, `copy_file`, `make_dir`, `search_files`, `grep`.
|
||||
|
||||
The sandbox directory is bind-mounted inside the container, so the agent works with stable paths regardless of where the sandbox lives on the host.
|
||||
|
||||
## Requirements
|
||||
|
||||
- Python ≥ 3.11
|
||||
@@ -37,18 +35,29 @@ docker-agent-sandbox = { path = "../docker-agent-sandbox" }
|
||||
from docker_agent_sandbox import DockerSandbox
|
||||
|
||||
sandbox = DockerSandbox(
|
||||
sandbox_dir="/tmp/my-sandbox", # bind-mounted into the container
|
||||
container_name="my-agent-run",
|
||||
container_workdir="/workspace", # path inside the container
|
||||
image="my-agent-image",
|
||||
dockerfile_dir="/path/to/dockerfile", # only needed if building the image
|
||||
volumes={"/host/sandbox": {"bind": "/workspace", "mode": "rw"}},
|
||||
ports={"8080/tcp": None}, # Docker assigns a random host port
|
||||
environment={"MY_VAR": "value"},
|
||||
working_dir="/workspace",
|
||||
cap_drop=["ALL"],
|
||||
cap_add=["SYS_PTRACE"],
|
||||
security_opt=["no-new-privileges"],
|
||||
)
|
||||
|
||||
sandbox.build_image_if_missing()
|
||||
sandbox.start()
|
||||
```
|
||||
|
||||
### 2. Run commands and write files
|
||||
### 2. Inspect mapped ports
|
||||
|
||||
```python
|
||||
host_port = sandbox.get_host_port("8080/tcp")
|
||||
```
|
||||
|
||||
### 3. Run commands and write files
|
||||
|
||||
```python
|
||||
exit_code, output = sandbox.exec("ls -la")
|
||||
@@ -56,7 +65,7 @@ sandbox.write_file("/workspace/hello.py", "print('hello')")
|
||||
exit_code, output = sandbox.exec("python /workspace/hello.py")
|
||||
```
|
||||
|
||||
### 3. Bind tools to a LangChain agent
|
||||
### 4. Bind tools to a LangChain agent
|
||||
|
||||
```python
|
||||
from docker_agent_sandbox import make_bash_tool, make_file_ops_tools
|
||||
@@ -66,7 +75,7 @@ tools = make_file_ops_tools(sandbox) + [make_bash_tool(sandbox)]
|
||||
# Pass `tools` to your LangChain / LangGraph agent as usual.
|
||||
```
|
||||
|
||||
### 4. Tear down
|
||||
### 5. Tear down
|
||||
|
||||
```python
|
||||
sandbox.stop()
|
||||
@@ -74,24 +83,30 @@ sandbox.stop()
|
||||
|
||||
## API reference
|
||||
|
||||
### `DockerSandbox(sandbox_dir, container_name, container_workdir, pin_mcp_port, image, dockerfile_dir)`
|
||||
### `DockerSandbox(container_name, image, dockerfile_dir, volumes, ports, environment, working_dir, network_mode, cap_drop, cap_add, security_opt)`
|
||||
|
||||
| Parameter | Default | Description |
|
||||
|---|---|---|
|
||||
| `sandbox_dir` | — | Host directory bind-mounted into the container |
|
||||
| `container_name` | — | Docker container name |
|
||||
| `container_workdir` | `"/workspace"` | Working directory inside the container |
|
||||
| `pin_mcp_port` | `8080` | Port exposed by a sidecar MCP server (if any) |
|
||||
| `image` | `"docker-agent-sandbox"` | Docker image tag to run |
|
||||
| `dockerfile_dir` | `None` | Directory containing the `Dockerfile`; required only if calling `build_image_if_missing` |
|
||||
| `volumes` | `{}` | Volume bindings passed directly to Docker (same format as `docker-py`) |
|
||||
| `ports` | `{}` | Port bindings passed directly to Docker, e.g. `{"8080/tcp": None}` for a random host port |
|
||||
| `environment` | `{}` | Environment variables injected into the container |
|
||||
| `working_dir` | `None` | Default working directory for `exec` calls (uses image `WORKDIR` if omitted) |
|
||||
| `network_mode` | `"bridge"` | Docker network mode |
|
||||
| `cap_drop` | `None` | Linux capabilities to drop |
|
||||
| `cap_add` | `None` | Linux capabilities to add |
|
||||
| `security_opt` | `None` | Docker security options |
|
||||
|
||||
#### Methods
|
||||
|
||||
| Method | Description |
|
||||
|---|---|
|
||||
| `build_image_if_missing()` | Builds the image from `dockerfile_dir` if not already present locally |
|
||||
| `start()` | Removes any existing container with the same name, starts a fresh one, and waits for the MCP port |
|
||||
| `start()` | Removes any existing container with the same name and starts a fresh one |
|
||||
| `stop()` | Removes the container |
|
||||
| `get_host_port(container_port)` | Returns the host port Docker mapped to `container_port` (e.g. `"8080/tcp"`) |
|
||||
| `exec(command, timeout=120)` | Runs a bash command; returns `(exit_code, stdout+stderr)` |
|
||||
| `write_file(path, content)` | Writes a UTF-8 file inside the container using the tar archive API |
|
||||
|
||||
@@ -111,7 +126,3 @@ sandbox.stop()
|
||||
| `make_make_dir_tool(sandbox)` | `make_dir` | `mkdir -p` |
|
||||
| `make_search_files_tool(sandbox)` | `search_files` | `find` by name glob |
|
||||
| `make_grep_tool(sandbox)` | `grep` | Extended-regex search with optional recursion |
|
||||
|
||||
## Security notes
|
||||
|
||||
Containers are started with `cap_drop=ALL`, `cap_add=SYS_PTRACE` (needed for debuggers/tracers), and `no-new-privileges`. Network mode is `bridge` with no explicit outbound rules — restrict further via Docker network policies if needed.
|
||||
|
||||
Reference in New Issue
Block a user