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)

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 /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.2.0.tar.gz (17.5 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.2.0-py3-none-any.whl (15.8 kB view details)

Uploaded Python 3

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

Hashes for marimo_sandbox-0.2.0.tar.gz
Algorithm Hash digest
SHA256 c9b1523b1cb858b52f360c150d23c83b51ee6e4d86ab480d3db4223ba874623c
MD5 ae05a6d7a623d452b639e61349c3399b
BLAKE2b-256 92a69d7eb7dab3b4fc9e334b79cf47a469161537f78398e5c1c1931e5ad4b378

See more details on using hashes here.

Provenance

The following attestation bundles were made for marimo_sandbox-0.2.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.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

Hashes for marimo_sandbox-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 9494b0cbb547e2263e9eca404233e8f5761fe7ba25d3b685c3e9b82ca26a6dff
MD5 81e19f37c11212f24d3c6b96dde7b869
BLAKE2b-256 ae4ecc9f3e0ac8f80c323aba2afd8e4b29965546b696199b4cbc7f95dda7053a

See more details on using hashes here.

Provenance

The following attestation bundles were made for marimo_sandbox-0.2.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