FastMCP server: run Python in auditable Marimo notebooks
Project description
marimo-sandbox
A FastMCP server that runs Python code inside auditable Marimo
notebooks. Every execution is saved as a human-readable .py file you can open,
inspect, and re-run at any time.
Why
When an AI agent (Claude Code, etc.) runs Python on your behalf, you get back stdout and maybe a traceback. You can't see the full code in context, can't re-run it, can't modify it interactively.
marimo-sandbox fixes this by wrapping every execution in a Marimo notebook:
- Auditable — the exact code that ran is saved as a
.pyfile alongside its output - Viewable —
marimo edit <notebook>opens it in the browser with reactive cells - Re-runnable — the notebook is standalone;
python notebook.pyworks without the server - Persistent — all runs are stored in SQLite with stdout, stderr, and status
Install
pip install marimo-sandbox
# or with uv:
uv pip install marimo-sandbox
Requires Python 3.11+ and marimo:
pip install marimo
Add to Claude Code
claude mcp add marimo-sandbox -- python -m marimo_sandbox
Or with uv:
claude mcp add marimo-sandbox -- uvx marimo-sandbox
Set a custom data directory (where notebooks and the database are stored):
claude mcp add marimo-sandbox \
-e MARIMO_SANDBOX_DIR=/your/preferred/path \
-- python -m marimo_sandbox
Tools
run_python
Run Python code and get back results + a notebook you can open.
code Python source to execute
description Short label for this run (shown in list_runs)
timeout_seconds Max execution time (default 60)
sandbox Run in Docker with --network=none (default False)
Returns: run_id, status, stdout, stderr, error, notebook_path, view_command
open_notebook
Open a previous run in Marimo's interactive editor.
run_id ID returned by run_python
port Local port for the editor (default 2718)
Returns a url to open in your browser. You can then edit cells and re-run them.
list_runs
List recent runs with status, description, and timestamp.
limit Max results (default 20)
status Filter: 'success', 'error', or 'pending'
get_run
Full details of a specific run.
run_id Run to look up
include_code Include submitted code (default True)
include_notebook_source Include full .py notebook source (default False)
check_setup
Verify marimo and Docker are available and show the data directory.
Notebooks
Generated notebooks live at:
~/.marimo-sandbox/notebooks/{run_id}/notebook.py
Open any of them directly:
marimo edit ~/.marimo-sandbox/notebooks/run_a1b2c3d4/notebook.py
Or run headlessly:
python ~/.marimo-sandbox/notebooks/run_a1b2c3d4/notebook.py
Sandbox mode (Docker)
For untrusted code, run_python(sandbox=True) runs inside Docker with:
--network=none— no outbound connections--memory=512m— memory cap--cpus=1— CPU cap--read-only— read-only root filesystem- writable
/sandboxmount for the notebook and result file
Build the sandbox image first:
docker build -f Dockerfile.sandbox -t marimo-sandbox:latest .
Add packages your code needs to Dockerfile.sandbox and rebuild.
Configuration
| Env var | Default | Description |
|---|---|---|
MARIMO_SANDBOX_DIR |
~/.marimo-sandbox |
Where notebooks and DB are stored |
MARIMO_SANDBOX_DOCKER_IMAGE |
marimo-sandbox:latest |
Docker image for sandbox mode |
Notebook structure
Every generated notebook has four fixed cells:
| Cell | Purpose |
|---|---|
__setup__ |
Imports marimo, returns (mo,) |
__context__ |
Displays run metadata (description, run_id, timestamp) |
__execution__ |
Your code, plus a sandbox_executed sentinel in the return tuple |
__record__ |
Depends on sandbox_executed — only runs on success; writes result sidecar |
The __record__ → __execution__ dependency means: if your code raises an
exception, __record__ never runs (Marimo's DAG won't execute a cell whose
dependencies failed). The executor detects the missing sidecar and reports an
error with the captured stderr.
Development
# Install in editable mode with dev dependencies
uv pip install -e ".[dev]"
# Lint
ruff check src/ tests/
# Unit tests (fast, no subprocess)
pytest tests/ -m "not slow" -v
# Integration tests (run real Marimo subprocesses)
pytest tests/ -m slow -v
Known limitations
- Top-level
returnstatements in submitted code are rejected (they exit the cell function before the sentinel is set). Wrap such code in a function. sys.exit()in user code is detected and reported as an error.- Generated notebooks always import
marimo. If marimo is not installed in the execution environment, the notebook will fail.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file marimo_sandbox-0.2.0.tar.gz.
File metadata
- Download URL: marimo_sandbox-0.2.0.tar.gz
- Upload date:
- Size: 17.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c9b1523b1cb858b52f360c150d23c83b51ee6e4d86ab480d3db4223ba874623c
|
|
| MD5 |
ae05a6d7a623d452b639e61349c3399b
|
|
| BLAKE2b-256 |
92a69d7eb7dab3b4fc9e334b79cf47a469161537f78398e5c1c1931e5ad4b378
|
Provenance
The following attestation bundles were made for marimo_sandbox-0.2.0.tar.gz:
Publisher:
publish.yml on mfbaig35r/marimo-sandbox
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
marimo_sandbox-0.2.0.tar.gz -
Subject digest:
c9b1523b1cb858b52f360c150d23c83b51ee6e4d86ab480d3db4223ba874623c - Sigstore transparency entry: 1304917024
- Sigstore integration time:
-
Permalink:
mfbaig35r/marimo-sandbox@f9e69b86b54c5a2858dc23eb50427c0866a6538b -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/mfbaig35r
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@f9e69b86b54c5a2858dc23eb50427c0866a6538b -
Trigger Event:
push
-
Statement type:
File details
Details for the file marimo_sandbox-0.2.0-py3-none-any.whl.
File metadata
- Download URL: marimo_sandbox-0.2.0-py3-none-any.whl
- Upload date:
- Size: 15.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9494b0cbb547e2263e9eca404233e8f5761fe7ba25d3b685c3e9b82ca26a6dff
|
|
| MD5 |
81e19f37c11212f24d3c6b96dde7b869
|
|
| BLAKE2b-256 |
ae4ecc9f3e0ac8f80c323aba2afd8e4b29965546b696199b4cbc7f95dda7053a
|
Provenance
The following attestation bundles were made for marimo_sandbox-0.2.0-py3-none-any.whl:
Publisher:
publish.yml on mfbaig35r/marimo-sandbox
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
marimo_sandbox-0.2.0-py3-none-any.whl -
Subject digest:
9494b0cbb547e2263e9eca404233e8f5761fe7ba25d3b685c3e9b82ca26a6dff - Sigstore transparency entry: 1304917154
- Sigstore integration time:
-
Permalink:
mfbaig35r/marimo-sandbox@f9e69b86b54c5a2858dc23eb50427c0866a6538b -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/mfbaig35r
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@f9e69b86b54c5a2858dc23eb50427c0866a6538b -
Trigger Event:
push
-
Statement type: