pi-mcp-router
extensionPath-scoped, multi-account MCP routing for Pi
by — · v1.6.0 · published 1mo ago
$ pi install npm:pi-mcp-routerSignals
Download trend
2.4K downloads · last 12 weeks (weekly)
README
Pi MCP Router
Path-scoped, multi-account routing for pi-mcp-adapter 2.11.0. Servers are exposed as account__server; matching parent and nested rules are additive.
Install
Install permanently:
pi install npm:pi-mcp-router
Or try it temporarily:
pi -e npm:pi-mcp-router
Do not also install/load pi-mcp-adapter as a Pi package: that would initialize an unfiltered second copy. The package bundles a private, version-pinned adapter with a narrow verified isolation patch; no install-script approval is needed.
Create ~/.pi/mcp-router.json (override with PI_MCP_ROUTER_CONFIG):
{
"version": 1,
"accounts": { "work": { "servers": { "github": { "url": "https://example.test/mcp", "description": "GitHub issues and pull requests", "authOnSessionStart": "if-needed" } } } },
"access": [{ "path": "/absolute/project", "accounts": ["work"] }],
"settings": { "defaultServers": ["github"] }
}
Rules use canonical real paths, so symlinks cannot escape or duplicate scopes. Paths must exist. Runtime files are mode 0600 under $XDG_RUNTIME_DIR/pi-mcp-router, falling back to the system temporary directory as pi-mcp-router-<uid>; account remote state is separated with MCP_REMOTE_CONFIG_DIR. Config updates use an exclusive lock, atomic rename, and .bak backup.
/mcp-route supports add [account server url [off|if-needed|always]] (interactive when omitted), describe <account> <server> <free-form description...> (omit the description to clear it), auth <account> <server> <mode>, list, show [account], allow <path> <account>, disallow, remove <account> <server>, account remove <account>, test [path], sandbox-domains [copy [index]|allow <project|global>], reload, and edit. allow/disallow expand ~ and environment variables and store the existing path's canonical absolute form. Manually edited access roots must already be absolute and canonical. Changes require restart; reload reports this explicitly.
authOnSessionStart defaults to off and is omitted when saved. if-needed prompts only when the adapter reports needs-auth; always checks authentication every session. With UI, opted-in routed servers are confirmed one at a time (30-second timeout), authenticated through the adapter's existing OAuth flow, and reconnected after success. Cancel or timeout stops the queue; an ordinary authentication failure continues to the next server. Non-interactive sessions skip startup authentication.
/mcp-auth-all [pattern] is available only for an active filtered route. With no pattern it targets every OAuth-capable routed server; otherwise it targets matching logical names (for example, revilo__books*). Only * is a wildcard; matching is case-sensitive and anchored to the whole name, while every other character is literal. It shows one confirmation listing the selected servers (sorted by logical name with sanitized descriptions), then authenticates and reconnects successes sequentially regardless of authOnSessionStart. Failures do not stop later servers; the final summary reports authentication outcomes while reconnect details remain in their per-server notifications. /mcp-auth and /mcp reconnect remain unchanged.
sandbox-domains lists exact HTTP(S) DNS hosts selected for the current directory. With pi-sandbox and UI available, the bare command (or allow project) confirms one append to <project>/.pi/sandbox.json; allow global separately warns and confirms the cross-project ~/.pi/agent/sandbox.json scope. Writes preserve unknown fields, reject active project/global deny conflicts, lock, back up, and atomically replace the file at mode 0600. Wildcards are never added. Without UI or pi-sandbox, it only lists copy guidance. copy <index> remains available. Run /reload after a write; no live refresh is claimed. A domain allowance grants host-wide outbound access, not only the MCP URL.
Security
With enabled pi-sandbox 0.6.3, selected HTTP(S) DNS hosts are checked against its effective merged default/global/project rules before adapter startup. Denies win; denied and missing hosts are excluded for the session. A single session-start prompt can add only missing exact hosts to the project config, and /reload is required. Unknown sandbox versions fail open with a warning.
An authoritative SDK UnauthorizedError, or a raw isError tool result containing exactly one text entry (at most 1000 characters) with bounded reauthentication wording, closes stale state after dispatch. Recognized wording includes reauthenticate/reauthorize, required authentication/authorization/login/OAuth, expired or invalid token/session/credentials, and 401/403 only near explicit authentication language. Text is normalized for case, whitespace, Unicode compatibility, and dashes; negations, educational examples, bare status/Forbidden text, and a different explicit MCP server name are rejected. Opted-in always/if-needed servers authenticate and reconnect once across concurrent proxy/direct/UI calls. On-demand authorization-code recovery uses the current Pi session's UI/browser flow, awaits its callback, then reconnects; the original request is never replayed, and callers receive reauthenticated_retry_required and must retry explicitly. Other results and errors retain adapter behavior.
No matching route means the adapter is not initialized. Routed startup fails closed if config validation or the adapter isolation guard fails. URLs and secret-like fields are redacted by show. An explicit user --mcp-config intentionally bypasses routing. The --mcp-config=path spelling is normalized to the adapter-supported --mcp-config path form; its normal merge behavior then applies and a warning is printed.