pi-mcp-extension
v1.5.0
Published
MCP (Model Context Protocol) client extension for the Pi coding agent — connect Pi to any MCP server
Downloads
531
Maintainers
Readme
pi-mcp-extension
Connect Pi to any MCP server. Supabase, DeepSource, Playwright, Context7, filesystem, databases — if it speaks MCP, Pi can use it.
pi-mcp-extension is a production-ready Model Context Protocol client extension for the Pi coding agent. It manages server connections, discovers tools, and bridges them into Pi so the LLM can call them directly.
Features
- Multi-transport —
stdiosubprocesses,streamable-http, and legacysseout of the box - Auto-discovery — Paginated
tools/listwith cursor following (MCP 2025-03-26 spec) - Live tool refresh —
notifications/tools/list_changedtriggers re-discovery without restart - Clean cancellation —
AbortSignalpropagation vianotifications/cancelled - Smart reconnection — Fixed delay retry schedule (1s → 3s → 5s → 10s → 30s), configurable max retries
- Health checks — Opt-in periodic pings to detect stale connections
- Safe process lifecycle — PID tracking with safety-net
SIGKILLfor orphaned subprocesses - Stable tool names — Sanitized, collision-avoiding names (max 64 chars) that stay constant across reconnects
- No tool churn — Activate/deactivate pattern ensures tools don't flicker during reconnection
- Global + project config — Layered config (project overrides global) with per-server tuning
- Tool annotations —
readOnlyHint,destructiveHint,idempotentHint,openWorldHintsurfaced in tool descriptions - Structured error handling — Distinct error codes for config, connection, protocol, and tool-level failures
Installation
pi install npm:pi-mcp-extensionOr try without installing:
pi -e npm:pi-mcp-extensionQuick Start
Install the extension:
pi install npm:pi-mcp-extensionCreate a config file at
~/.pi/agent/mcp.json(global) or.pi/mcp.json(project-level):{ "mcpServers": { "supabase": { "transport": "streamable-http", "url": "https://mcp.supabase.com/mcp", "lifecycle": "eager" } } }Start Pi — your MCP tools are ready. Use
/mcpto check server status.
Configuration
Config files are loaded from two locations. Project config overrides global config via shallow merge (server-level replacement).
| Location | Scope |
|---|---|
| ~/.pi/agent/mcp.json | Global — applies to all projects |
| .pi/mcp.json | Project — overrides global per-server |
Full Example
{
"settings": {
"toolPrefix": "mcp", // Tools appear as mcp_<server>_<tool> (default: "mcp")
"requestTimeoutMs": 30000, // Per-request timeout in ms (default: 30000)
"maxRetries": 5 // Max reconnection attempts, 0-10 (default: 5)
},
"mcpServers": {
// ── HTTP-based servers ───────────────────────────────────────────────────
"supabase": {
"transport": "streamable-http",
"url": "https://mcp.supabase.com/mcp",
"lifecycle": "eager"
},
"deepsource": {
"transport": "streamable-http",
"url": "https://mcp.deepsource.io/mcp",
"lifecycle": "eager"
},
// ── Legacy SSE servers ───────────────────────────────────────────────────
"legacy-server": {
"transport": "sse",
"url": "https://example.com/sse",
"lifecycle": "lazy"
},
// ── stdio subprocess servers ─────────────────────────────────────────────
"pathfinder": {
"command": "/path/to/pathfinder-mcp",
"transport": "stdio",
"lifecycle": "eager"
},
"context7": {
"command": "npx",
"args": ["-y", "@context7/mcp"],
"transport": "stdio",
"lifecycle": "lazy"
},
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/workspace"],
"transport": "stdio",
"lifecycle": "lazy",
"env": {
"NODE_ENV": "production"
}
}
}
}Global Settings
| Field | Type | Default | Description |
|---|---|---|---|
| toolPrefix | string | "mcp" | Prefix for registered tools: <prefix>_<server>_<tool>. Must match ^[a-zA-Z][a-zA-Z0-9_]*$. |
| requestTimeoutMs | number | 30000 | Default per-request timeout in milliseconds |
| maxRetries | number | 5 | Max reconnection attempts (0–10) before giving up |
Per-Server Config
| Field | Type | Default | Description |
|---|---|---|---|
| transport | "stdio" \| "streamable-http" \| "sse" | "stdio" | Transport protocol |
| command | string | — | Executable to spawn (required for stdio) |
| args | string[] | [] | Arguments for the command |
| env | Record<string, string> | — | Extra environment variables for the child process |
| url | string | — | Server URL (required for streamable-http/sse) |
| lifecycle | "eager" \| "lazy" | "lazy" | eager = auto-start on session start, lazy = manual via /mcp:start |
| requestTimeoutMs | number | global setting | Per-server timeout override |
| healthCheckIntervalMs | number | disabled | Opt-in ping interval for connection health monitoring |
Commands
| Command | Description |
|---|---|
| /mcp | Show status summary of all configured servers |
| /mcp <name> | Show detailed status and stderr log for a specific server |
| /mcp:start <name> | Start a server (resets retry count) |
| /mcp:stop <name> | Stop a running server and deactivate its tools |
How It Works
┌─────────────────────────────────────────────────────────┐
│ Pi Agent │
│ │
│ ┌──────────┐ ┌────────────────┐ ┌─────────────┐ │
│ │ index.ts │───▶│ server-manager │───▶│ tool-bridge │ │
│ │ (entry) │ │ (lifecycle) │ │ (MCP → Pi) │ │
│ └──────────┘ └───────┬────────┘ └──────┬──────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌──────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ config │ │ MCP SDK │ │ TypeBox │ │
│ │ (Zod) │ │ (transport) │ │ (schema) │ │
│ └──────────┘ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────┘
│ │
▼ ▼
Global/Project ┌──────────────┐
mcp.json files │ MCP Servers │
│ (stdio/http) │
└──────────────┘- Config is loaded from global and project files (project overrides global by server name)
- Eager servers connect at session start; lazy servers wait for
/mcp:start - Tools are discovered via paginated
tools/listcalls (cursor-based, up to 100 pages) - JSON Schema → TypeBox conversion registers tools with Pi-compatible parameter schemas
- Pi tools are registered as
<prefix>_<server>_<tool>(sanitized, max 64 chars with hash suffix) - Tools activate/deactivate automatically as servers connect/disconnect
- AbortSignal is wired through to
notifications/cancelledfor clean cancellation - Reconnection uses a fixed delay schedule with configurable max retries
list_changednotifications trigger re-discovery, deactivating stale tools automatically- Session shutdown cleanly stops all servers and deactivates all tools
MCP Spec Compliance
Implements the MCP 2025-03-26 specification for tool clients:
| Feature | Status |
|---|---|
| Protocol version 2025-03-26 (+ 2024-11-05 fallback) | ✅ |
| stdio transport | ✅ |
| streamable-http transport | ✅ |
| sse transport (legacy backwards compat) | ✅ |
| Cursor-based tools/list pagination | ✅ |
| tools/call with parameters | ✅ |
| roots/list capability (workspace root) | ✅ |
| notifications/tools/list_changed (live refresh) | ✅ |
| notifications/cancelled (AbortSignal) | ✅ |
| notifications/message (structured logging) | ✅ |
| isError: true distinction (protocol vs tool errors) | ✅ |
| Tool annotations (readOnlyHint, destructiveHint, etc.) | ✅ |
| Resources bridge | ⏳ v2 |
| Prompts bridge | ⏳ v2 |
| Sampling | ⏳ v2 |
Development
# Install dependencies
npm install
# Type check (strict mode)
npm run typecheck
# Run all tests (47 tests)
npm test
# Run integration tests only (real stdio server)
npm run test:integrationTesting
The test suite includes:
- Config validation — Zod schema, global/project merge, defaults, error cases
- Server lifecycle — Connect, retry, shutdown, health check, race conditions
- Tool bridge — JSON Schema → TypeBox conversion, name sanitization, activate/deactivate
- End-to-end integration — Real mock MCP server over stdio with tool discovery and execution
License
MIT
