Local Sandbox MCP Environment
# Local Sandbox MCP Environment
An [MCP](https://modelcontextprotocol.io) server that gives an LLM a **secure local workspace**: it can write files, run code in a locked-down Docker container, and query an isolated SQLite database, with no access to the rest of your machine.
## The problem
An AI that only *suggests* code is limited. An AI that runs code directly on your computer is dangerous: it could delete files, read secrets, use the network, or loop forever. This project lets the model write, run, see errors, and fix its own code, safely.
## Demo

## Architecture
```mermaid
flowchart LR
A[Claude Desktop<br/>MCP client] -- stdio --> B[MCP Server<br/>FastMCP]
B --> C[Workspace<br/>safe_path checks]
B --> D[Executor]
B --> E[(SQLite<br/>read-only)]
D -- docker run --> F[Container<br/>no network, limited,<br/>read-only]
F -. mounts read-only .-> C
```
## Tools
| Tool | Purpose |
|---|---|
| `list_files`, `read_file`, `write_file` | Manage files inside `workspace/` |
| `run_python` | Run a workspace script in an isolated container |
| `describe_schema` | Show the database tables |
| `query_db` | Run read-only `SELECT` queries |
## Threat model
| Threat | Defense | Tested by |
|---|---|---|
| Path traversal (`../`, absolute paths) | `safe_path` resolves paths and checks they stay inside `workspace/` | `tests/test_workspace.py` |
| Destructive SQL (`DROP`, `DELETE`, ...) | `SELECT`/`WITH`-only check **plus** SQLite `mode=ro` | `tests/test_database.py` |
| Stacked SQL statements | `sqlite3` rejects multiple statements | `test_multiple_statements_rejected` |
| Infinite loops / CPU hogging | 10s timeout; container force-removed | `test_infinite_loop_times_out` |
| Orphaned containers | Unique `--name` + `docker rm -f` in `finally` | `test_no_orphan_container_after_timeout` |
| Network access / data exfiltration | `--network none` | `test_network_blocked` |
| Modifying host files | Workspace mounted `:ro`, `--read-only` root filesystem | `test_workspace_is_read_only` |
| Memory / fork bombs | `--memory`, `--cpus`, `--pids-limit` | Manual |
| Privilege escalation | Non-root user, `--cap-drop ALL`, `no-new-privileges` | Configuration |
| Output flooding | Output truncated at 10,000 characters | Manual |
## Setup
Requirements: Python 3.10+, [uv](https://docs.astral.sh/uv/), Docker (running).
```bash
git clone https://github.com/Prakhar021-hub/local-sandbox-mcp.git
cd local-sandbox-mcp
uv sync
docker build -t sandbox-mcp-runner docker/
uv run pytest -v
```
### Try it in the MCP Inspector
```bash
PYTHONPATH=src uv run mcp dev dev_server.py
```
### Connect to Claude Desktop
Add to `~/Library/Application Support/Claude/claude_desktop_config.json` under `mcpServers`:
```json
"local-sandbox": {
"command": "/path/to/uv",
"args": ["--directory", "/path/to/local-sandbox-mcp",
"run", "python", "-m", "local_sandbox_mcp.server"],
"env": {
"PYTHONPATH": "src",
"PATH": "/usr/local/bin:/opt/homebrew/bin:/usr/bin:/bin"
}
}
```
Restart Claude Desktop (Cmd+Q) and try: *"Write a script that prints the first 10 Fibonacci numbers, run it, and show me the output."*
## Project structure
```
src/local_sandbox_mcp/ server, executor, database, workspace, config, logging
docker/Dockerfile minimal non-root Python runner image
tests/ pytest suite that attacks the sandbox
```
## Limitations
Docker containers share the host kernel, so this is strong isolation for local development, but not a substitute for a VM-level sandbox against a determined attacker. Intended for local, single-user use.
## License
MITTDQS
Scored across 6 tools
Each tool targets a clearly distinct resource and action: file CRUD, Python execution, and read-only database access are cleanly separated. The only adjacent pair, describe_schema and query_db, is well differentiated by one returning metadata and the other returning query results.
All six tools follow a consistent snake_case verb_noun pattern (run_python, describe_schema, query_db, list_files, write_file, read_file). No mixed conventions or vague verbs.
Six tools is a tight, well-scoped surface for a sandbox environment; every tool earns its place with no redundancy. Nothing feels padded or thin.
File read/write/list, code execution, and DB inspection cover the core sandbox workflow, but there is no delete_file or directory-creation operation, which agents may need when cleaning up or organizing the workspace. A way to pass arguments/stdin to run_python is also absent but workable.