Two ways to bolt MCP onto a coding agent
Approach B shipped in Pi 0.99.0. MCP stays the wire protocol; tools default to codemode exposure. The model writes JavaScript inside a QuickJS sandbox, fires tools in parallel, filters the junk, and only the distilled result re-enters context. Release line: v0.99.0 (29 Sep 2026).
Approach A is still what most stacks do: dump every tool schema into the model at session start. Mario Zechner’s Nov 2025 measurements – Playwright MCP ~13.7k tokens across 21 tools, Chrome DevTools MCP ~18k across 26 – land before you ask anything useful (Mario’s write-up).
| Dimension | Approach A (dump schemas) | Approach B (Pi MCP+Codemode) |
|---|---|---|
| Tool schemas in context | All of them, every turn | Off model by default; listed for scripts |
| Multi-tool work | One round-trip per call | Parallel JS in sandbox |
| Huge tool payloads | Land in the transcript | Filter before the model sees them |
| Who chooses this | Most agents historically | Pi core as of 0.99.0 |
B is the day-to-day default for coding agents. A still fits tiny always-on tool packs – and Pi still offers direct exposure when you want that.
Think of codemode like a sous-chef: the model doesn’t taste every raw pan on the line. It writes a short ticket, the kitchen runs the heat, and only the plated note comes back. That’s the whole bet.
They didn’t stage a full apology tour either. Bloated servers still get called out. The shift was practical – shape the protocol from inside the agent instead of yelling from the sidelines (Earendil: You Said No MCP!).
Hands-on setup (Pi.dev after “You Said No MCP”)
Pi 0.99.0 is the cutover. Homepage copy flipped from “No MCP” to “Now with MCP+Codemode” on pi.dev. Older build? Upgrade first.
- Install or update (macOS/Linux installer, or npm on Node.js 22.19+ per the quickstart):
curl -fsSL https://pi.dev/install.sh | sh
# or
npm install -g --ignore-scripts @earendil-works/pi-coding-agent
pi --version
- Add a server. User-global writes
~/.pi/agent/mcp.json. Project-local needs-land a trusted project:
pi mcp add filesystem -- npx -y @modelcontextprotocol/server-filesystem .
pi mcp list
pi
Remote HTTP, straight from the official MCP docs:
pi mcp add docs --url https://example.com/mcp --bearer-token-env-var DOCS_TOKEN
- In-session:
/mcpshows state, tool counts, exposure, OAuth, reconnect, enable/disable. Edit config outside the session?/reloador start fresh. - Default exposure is already
codemode(as of the 0.99 docs). Pi auto-enables the codemode tool when a codemode-style server connects. Want codemode with zero MCP servers?"defaultTools": ["+codemode"]in~/.pi/agent/settings.json. - OAuth-style servers: URL only in config, then
pi mcp login <server>or Sign in from/mcp– no tokens pasted into JSON.
Config shape matches other clients, so Cursor/Claude mcpServers blocks often paste cleanly. Secrets stay ${ENV} or !command – never hardcoded tokens.
Pick the right exposure
This is the real control knob. Tools register as mcp__<server>__<tool>. Exposure decides whether the model ever sees them as first-class tools.
| Exposure | Model sees tools? | Best for |
|---|---|---|
codemode (default) |
No – scripts only (listed in codemode desc) | Most MCP servers |
codemode-deferred |
No – not even inline list; search by name | Huge, rarely used servers |
deferred |
After tool_search loads matches |
Large sets without codemode |
direct |
Yes, like built-ins | Tiny, always-needed tool packs |
hidden |
Registered but unreachable | Kill switches / partial enable via toolExposure |
Per-tool overrides use toolExposure – exact names or * patterns. Docs pattern: search_code on direct, hide delete_*, leave the rest deferred. Codemode declarations share an inlineBudget (default ~3000 estimated tokens per Pi settings docs); overflow stays reachable with searchTools() inside scripts.
Common pitfalls
- Old adapter still installed.
pi-mcp-adapter(or anything that owns/mcp) replaces built-in MCP. Sessions stop readingmcp.jsonuntil you remove the extension – called out in the official MCP docs. - Project config ignored.
.pi/mcp.jsonloads only after project trust, because stdio servers execute commands. Personal creds belong in~/.pi/agent/mcp.json. - SSE URLs. Legacy SSE is rejected. Prefer streamable HTTP; many servers that advertise
/ssealso speak HTTP at/mcp. - Shell-string commands.
commandis one executable; arguments go inargs. Don’t paste a full shell line. - Forgot
/reload. Outside edits need reload or a new session. - Slow startups. First prompt waits up to ~10s for connections; slower servers appear when ready. Default per-request timeout is 60s (progress pings reset it).
Server names: letters, digits, _, - only. Invalid entries get skipped; the rest still connect. pi mcp list exits 1 while anything’s wrong; tails live in ~/.pi/agent/mcp.log.
What codemode actually does
Not a toy REPL. Scripts call tools.<name>(args), can Promise.allSettled them, and return only what you text() / return. State rides the session transcript.
Why JS? Small engines ship as WASM with isolation that doesn’t feel like a science project – Earendil’s post is blunt about that tradeoff.
Model path: text over 20KB gets a middle-truncation marker plus a temp-file path for the full blob. Codemode scripts always receive the whole CallToolResult. Filter in the sandbox, or direct exposure will still lose the middle on huge payloads.
Honest gap: no official post-0.99.0 head-to-head publishes exact token savings for default codemode vs direct on Playwright/Chrome in live sessions. Mario’s 13.7k/18k numbers state the problem. They’re not a savings receipt for 0.99.0.
When you should not use this
Skip built-in MCP+Codemode when a thin CLI or Pi skill already covers the job. Mario’s original case still stands for browser automation you can express as a few bash scripts and a short README.
Pro tip: Start with zero MCP servers. Add one only when OAuth, shared schemas across agents, or a hosted service beats a local script. Already living in bash pipes? Stay there.
Also skip – or disable builtin:mcp in pi config – if you intentionally want old adapter behavior. Embedding via the SDK is opt-in; SDK sessions don’t auto-load built-in extensions the way the CLI does.
So is MCP the destination, or just a compatibility adapter you reach for when scripts stop scaling? Worth answering before you fill mcp.json.
FAQ
Did Pi fully reverse its “No MCP” stance?
No. MCP on their terms: default codemode, exposure controls, same criticism of bloated servers. Primary source: the Earendil post.
I added a server but the model never calls it – what now?
Check exposure first. On default codemode, the model shouldn’t invoke mcp__... tools directly – it should write a codemode script. If auto-enable is off and neither codemode nor tool_search is active, Pi warns once because nothing can reach undeclared tools.
Run /mcp, confirm connected, then prompt explicitly for a codemode script against that server. Two-tool pack you always want hot? Flip that server to direct.
Is this the same as the Pi Network crypto project?
No. Different product. This is the open-source terminal coding agent at pi.dev (Earendil), not minepi.com.
Next action: upgrade to 0.99.x, run pi mcp add filesystem -- npx -y @modelcontextprotocol/server-filesystem ., open /mcp, and ask Pi to list tools through codemode on a real file task. About five minutes. Real signal.