Skip to main content

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 .py file alongside its output
  • Viewablemarimo edit <notebook> opens it in the browser with reactive cells
  • Re-runnable — the notebook is standalone; python notebook.py works 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)
packages          PyPI packages to install before running (e.g. ["pandas", "httpx"])

Returns: run_id, status, stdout, stderr, error, notebook_path, view_command, and packages_installed (if any).

Packages are installed via uv pip install when uv is available, falling back to pip. Installation happens before the notebook runs, so the packages are immediately importable in your code.

rerun

Re-execute a previous run's code by run_id, optionally with modifications.

run_id            Run to re-execute
code              Override the code (default: use original)
description       Override the description (default: original + " (rerun)")
timeout_seconds   Max execution time (default 60)
sandbox           Run in Docker sandbox (default False)
packages          PyPI packages to install before running

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)

delete_run

Remove a run's database record and its notebook files from disk.

run_id         Run to delete
delete_files   Also remove the notebook directory (default True)

purge_runs

Bulk-delete runs older than N days to reclaim disk space.

older_than_days   Delete runs older than this many days (default 30)
delete_files      Also remove notebook directories (default True)

Returns deleted_runs, files_deleted, and run_ids.

check_setup

Verify marimo, Docker, and uv 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 /sandbox mount 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 return statements 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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

marimo_sandbox-0.4.0.tar.gz (20.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

marimo_sandbox-0.4.0-py3-none-any.whl (17.3 kB view details)

Uploaded Python 3

File details

Details for the file marimo_sandbox-0.4.0.tar.gz.

File metadata

  • Download URL: marimo_sandbox-0.4.0.tar.gz
  • Upload date:
  • Size: 20.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for marimo_sandbox-0.4.0.tar.gz
Algorithm Hash digest
SHA256 0ba1e5c2a81561fd257ea00e3c0e362af0866788145de920c21626d3dfd87f56
MD5 416c1f2bf63cf3d054b0ef0061fdb9e4
BLAKE2b-256 7591411aa55d9bb04f68fad5c7795c2aa775d232f1556e1c5bf87d9b34770ea3

See more details on using hashes here.

Provenance

The following attestation bundles were made for marimo_sandbox-0.4.0.tar.gz:

Publisher: publish.yml on mfbaig35r/marimo-sandbox

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file marimo_sandbox-0.4.0-py3-none-any.whl.

File metadata

  • Download URL: marimo_sandbox-0.4.0-py3-none-any.whl
  • Upload date:
  • Size: 17.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for marimo_sandbox-0.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 a469c96d6dfd0a7b324d162467780273d2afd7665bf85a54fae459a16d8b5dac
MD5 416f657ebcc50a02d15867a7bb206e5c
BLAKE2b-256 9de2f9b28ab5a3d9e7eb422855a29b92e02cd07c328e87cf4ec18505a355b4e6

See more details on using hashes here.

Provenance

The following attestation bundles were made for marimo_sandbox-0.4.0-py3-none-any.whl:

Publisher: publish.yml on mfbaig35r/marimo-sandbox

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page