a token-efficient MCP server for live marimo notebooks
minimo is an MCP server that connects an agent to running marimo notebooks. It is a sibling of marimo-pair but designed to be more context efficient, which, in turn, makes it easier to use with small models. Through seven tools, the agent can find reachable notebooks, read cells, look up names in the live kernel, try code in a scratchpad, edit cells with pre-write checks, manage packages, and retrieve content that an earlier result truncated.
minimo requires Python 3.10 or later and a running marimo notebook. The project is not on PyPI yet, so every host below runs it from a checkout.
claude mcp add minimo -- uv run --directory /path/to/minimo minimoAdd the server to opencode.json in the project, or to
~/.config/opencode/opencode.json for every project.
{
"mcp": {
"minimo": {
"type": "local",
"command": ["uv", "run", "--directory", "/path/to/minimo", "minimo"],
"enabled": true
}
}
}Note that opencode starts one server process per opencode run, so the
session budget resets each turn under that host.
codex mcp add minimo -- uv run --directory /path/to/minimo minimoOr add the server to ~/.codex/config.toml directly.
[mcp_servers.minimo]
command = "uv"
args = ["run", "--directory", "/path/to/minimo", "minimo"]Most hosts take the common mcpServers JSON.
{
"mcpServers": {
"minimo": {
"command": "uv",
"args": ["run", "--directory", "/path/to/minimo", "minimo"]
}
}
}minimo finds a notebook served by a --no-token marimo with no
configuration. Name notebooks behind a token, and notebooks on another
machine, in $XDG_CONFIG_HOME/minimo/notebooks.json, which falls back to
~/.config/minimo/notebooks.json. The file looks like this.
{
"notebooks": {
"nb": {
"base_url": "http://127.0.0.1:2718",
"notebook": "nb.py",
"token_file": "~/.config/minimo/nb.token"
}
}
}The fields token, token_file, and token_env name a credential. The
credential value never appears in a tool result, a log line, or a URL.
| Tool | Answers |
|---|---|
list_notebooks |
which notebooks the server can reach, and which registered servers did not answer |
read_notebook |
the cells as they are now, with id, name, code, defs, refs, status, and errors |
discover |
whether a name is importable here, what the name holds and offers, and where the name is bound |
run_code |
what Python does in a scratchpad over the live kernel namespace |
write_cells |
whether a create, edit, delete, or move batch committed, with a verdict and a blast radius |
packages |
what an add or remove changed, with importability measured afterwards rather than inferred |
recall |
the content an elision removed, whole or narrowed by grep and start |
An agent working in a notebook usually fails by filling its context, not by lacking ability. A tool that answers a one-line question with a thousand lines of notebook output leaves less room for the work that prompted the question.
minimo therefore treats tool results as a spend against an allowance. The limits come from recorded sessions.
| Scope | Limit | Basis |
|---|---|---|
| one session | 40,000 characters of tool results | one recorded transcript ran to 38,727 characters end to end. A session that spends more than that on results has replaced the conversation |
| any one field | 4,000 characters | the largest item in that transcript was 11,811 characters, 30.5% of the whole, and concerned an unrelated file |
| a factual field, however starved | 240 characters | below 240 characters a result reports that a fact exists without reporting any of the fact |
A clamped result names the affected field, the original size, and the kept
size, and the disclosure carries a reference string. The recall tool
exchanges the reference string for the removed content. minimo never
truncates silently, because an agent that cannot tell a short answer from a
shortened answer re-reads everything.
The envelope also marks repetition. When a result is identical to one the
session already delivered, the payload carries a repeat_of field that
names the earlier call.
write_cells returns a verdict instead of a notebook. The result reports
whether the batch committed, which checks reached a verdict, and which
cells went stale, so the agent does not re-read the notebook to learn what
the edit did.
discover answers questions about names without a file read. The tool
reports importability, attributes, signatures, and doc lines from the
running kernel, and one call answers many names. When nothing in the kernel
has a name, the tool asks the package index instead of guessing.
run_code runs Python in a scratchpad copied from the kernel's globals.
Code that raises in the scratchpad would raise in a cell, and the notebook
stays unchanged either way.
list_notebooks separates an empty list from an unanswered server, so a
missing notebook prompts one more call rather than a wrong conclusion.
recall returns content the envelope removed, so a truncation costs a
follow-up call instead of a full re-read.
The package minimo.measure checks the budget claims. The battery runs
tasks against a real model and a real kernel, captures the transcripts, and
reports what each episode spent and whether the episode delivered.
python -m minimo.measure.battery_cli --model gpt-oss:20b --suffix r1 --out runs/The grader recomputes every reading from the captured episode rather than trusting the runner's own report. When the grader cannot read an episode, the grader excludes the episode by name and reason and never counts the episode as a failure.
src/minimo/
catalogue.py every tool, defined once as data
envelope/ the budget, the shrinking rules, and the disclosures
handlers/ one module per tool
core/ graph checks, plans, conflicts, and name resolution
kit/ the program minimo runs inside the kernel
discovery/ finding reachable notebooks
transport/ the HTTP and SSE wire to marimo
measure/ the battery and the grader, off the agent path
docs/architecture.md maps the bounded contexts, the entities, and the
techniques. docs/style.md records the style rules and their enforcement.
The project is early. The surface works against a live kernel, and the
limits above come from recorded sessions rather than a broad campaign. The
docs/ directory holds the design record and the transcripts behind the
limits.