Pi moved to its new home at earendil-works on 2026-05-07
(https://pi.dev/news/2026/5/7/pi-has-a-new-home). Affected packages:
@mariozechner/pi-coding-agent -> @earendil-works/pi-coding-agent
@mariozechner/pi-tui -> @earendil-works/pi-tui
@mariozechner/pi-ai -> @earendil-works/pi-ai
@mariozechner/pi-agent-core -> @earendil-works/pi-agent-core
The old @mariozechner/* packages are deprecated on npm with the
explicit message 'please use @earendil-works/pi-coding-agent instead
going forward', and the version stream has moved on (old top-out
0.73.1; new currently 0.74.0). Anyone npm-installing the old names
gets a deprecation warning + a stale binary.
Sweep:
- All 7 extension TypeScript files: import statements updated.
- README, AGENTS, install.sh: textual references and the github.com/
mariozechner/pi-coding-agent URL pointed at github.com/earendil-works/
pi (the new monorepo root; coding-agent now lives at
packages/coding-agent inside it).
- Bun build of mcp-loader, ext-toggle, ssh-controlmaster verified clean.
Brew install references (`brew install pi-coding-agent`) left as-is:
the homebrew formula still works at 0.73.1 and a tap update is
tracked upstream at earendil-works/pi#2755. Historical CHANGELOG
entries are untouched.
- New RemoteMcpClient implementing MCP streamable-HTTP per spec 2025-03-26:
POST JSON-RPC, parse application/json or text/event-stream responses,
round-trip optional Mcp-Session-Id, optional auth via 'headers' config.
- Refactor StdioMcpClient to share an IMcpClient interface with the remote
client; extension entry dispatches on cfg.type. Drops the v1 'remote
skipped with warning' code path.
- Bump MCP_PROTOCOL_VERSION to 2025-11-25 (single constant, both clients).
- 404 self-heal: when a remote returns 404 to a request carrying our
Mcp-Session-Id, drop the id, re-initialize, retry the request once
(per spec 2025-11-25 \u00a72.2). allowReinitOn404=false on the retry path
prevents recursion. Verified via mock-server smoke test.
- Sanitize pi-facing tool names to ^[A-Za-z][A-Za-z0-9_]{0,63}$. Anthropic
allows hyphens but Bedrock's Anthropic shim rejects them, causing entire
turns to 4xx silently when context7's hyphenated tools (resolve-library-id,
query-docs) were registered. Original MCP-side names are preserved in the
tool-execute closure, so sanitization is purely pi-facing.
- /mcp slash command: drop 'remote (skipped)' status label.
- Docs: README and AGENTS updated for transports, headers config, 404
self-heal, tool-name sanitization rationale, OAuth limitation.
End-to-end verified: context7 connects through pi, returns useful docs
(Bun streaming/SSE example fetched successfully).
Mirrors /ext UX (space=stage, enter=apply+reload, esc=cancel) but for
MCP servers in the settings.json `mcp` block. Tracks per-server runtime
state captured at extension load time so users can see at a glance
which servers are running / failed / disabled / remote-skipped /
invalid, with tool counts for the running ones.
Toggling writes back to settings.json — disabling sets enabled:false,
re-enabling removes the explicit key (default is true) to keep the
file tidy. Then ctx.reload() picks up the change.
Closes the visibility gap surfaced by 'searxng_search isn't in /ext':
MCP-provided tools are runtime-spawned, not file-based extensions, so
they need their own list view. /mcp fills that hole.
Reads an `mcp` block from ~/.pi/agent/settings.json (same shape as
opencode and Claude Desktop) and connects to each declared MCP server,
exposing all of their tools to pi as native tools namespaced as
<server-name>_<tool-name>.
Why: pi has no built-in MCP loader. Adding each new MCP server as a
hand-rolled extension (the way mempalace.ts does it) doesn't scale.
This is the config-driven generalization — one extension, any number
of servers, no per-server boilerplate.
Settings.json schema matches opencode and Claude Desktop verbatim:
{
"mcp": {
"searxng": {
"type": "local",
"command": ["uvx", "mcp-searxng"],
"env": { "SEARXNG_URL": "https://searxng.your-host.lan" }
},
"context7": {
"type": "remote",
"url": "https://mcp.context7.com/mcp"
}
}
}
Per-server keys: type (local/remote), command, url, enabled, env.
Implementation:
• StdioMcpClient class spawns subprocess, performs MCP initialize
handshake (protocol 2024-11-05), lists tools, exposes a callTool()
method. Newline-delimited JSON-RPC over stdio.
• Each MCP tool registered via pi.registerTool with the server-
namespaced name, the upstream MCP inputSchema passed through
via Type.Unsafe (TypeBox is JSON-Schema-compatible at runtime).
• Per-server fail-soft: a server that won't start logs one stderr
line and is skipped; others continue.
• SIGTERM all subprocesses on session_shutdown so /reload doesn't
leak processes.
Tool naming: prefix with <serverName>_ except when the upstream tool
name already starts with that prefix (mempalace's tools are already
mempalace_search, mempalace_kg_query, etc — avoids double-prefixing).
Coexists with mempalace.ts but does not replace it. The mempalace
bridge has bespoke agent-identity injection that's worth preserving.
v1 limitations:
• Stdio transport only. Remote (streamable-HTTP) servers are
detected and skipped with a warning. v2 will add streamable-HTTP.
• No reconnect on subprocess death — same limitation as mempalace.ts.
Verification:
• node --check syntax clean
• Standalone smoke test against `uvx mcp-server-time`: handshake +
tools/list (2 tools) + tools/call (get_current_time) all green
on the same JSON-RPC code that lives inside the loader.
Debug: set PI_MCP_LOADER_DEBUG=1 to surface per-server stderr.