@0xkobold/pi-mcp
v0.4.0
Published
Model Context Protocol (MCP) integration for pi-coding-agent. Connect to any MCP server (stdio, SSE, StreamableHTTP, WebSocket) and use its tools, resources, and prompts natively.
Maintainers
Readme
@0xkobold/pi-mcp
Model Context Protocol (MCP) integration for pi-coding-agent
Connect to any MCP server and use its tools, resources, and prompts natively within your pi agent.
Features
- 🌐 Four Transport Types - stdio, SSE, StreamableHTTP, and WebSocket
- 🔧 Auto Tool Registration - MCP tools appear as native pi tools (with progressive dispatch for 50+ tool servers)
- 🔒 Tool Filtering - Allowlist/denylist to control which tools are registered
- 📦 Resource Access - Read MCP server resources directly (with TTL caching)
- 💬 Prompt Templates - Use MCP prompt templates
- 🌱 Roots Support - Servers can discover workspace roots
- 🔄 Auto-Reconnect - Reconnects on disconnect with exponential backoff
- 🔐 Env Interpolation -
${VAR}in config resolved from environment - 📥 Claude Desktop Import - Import servers from
~/.claude/mcp.json - 💊 Health Monitoring - Uptime, call counts, error tracking in
/mcp status - 🧪 Sampling Support - Handle MCP
sampling/createMessagerequests via configurable callback - 🗂️ Multi-Project Config -
.0xkobold/mcp.jsonmerges with global config - ⚙️ Hot Config - Add/remove servers without restart (commands)
Quick Start
1. Configure servers
Edit ~/.0xkobold/mcp.json:
{
"servers": [
{
"name": "filesystem",
"transport": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/home/user"]
},
"enabled": true,
"autoReconnect": true
}
],
"importClaudeDesktop": true
}2. Or use commands
/mcp add filesystem npx -y @modelcontextprotocol/server-filesystem /home/user
/mcp enable filesystem
/mcp connect filesystem3. Use tools
The agent will automatically discover and use MCP tools. You can also:
/mcp list # See all configured servers
/mcp status # See active connections
/mcp discover # Find available toolsCommands
| Command | Description |
|---------|-------------|
| /mcp | Show help |
| /mcp list | List all configured servers |
| /mcp connect <name> | Connect to a server |
| /mcp disconnect <name> | Disconnect from a server |
| /mcp enable <name> | Enable auto-connect for a server |
| /mcp disable <name> | Disable auto-connect for a server |
| /mcp add <name> <cmd> [args] | Add a stdio server |
| /mcp add-http <name> <url> | Add an HTTP server |
| /mcp add-ws <name> <url> | Add a WebSocket server |
| /mcp filter <name> allow <tools> | Only register listed tools for server |
| /mcp filter <name> deny <tools> | Register all except listed tools |
| /mcp filter <name> clear | Remove tool filters for server |
| /mcp remove <name> | Remove a server from config |
| /mcp refresh <name> | Re-discover tools/resources/prompts |
| /mcp import | Import servers from Claude Desktop config |
| /mcp status | Show active connections |
Tools
| Tool | Description |
|------|-------------|
| mcp_discover | List available MCP tools, resources, and prompts |
| mcp_call_tool | Call any MCP tool by server + tool name |
| mcp_<server>_<tool> | Individual tools (auto-registered per server) |
| mcp_<server>_read_resource | Read a resource from an MCP server |
| mcp_<server>_get_prompt | Get a prompt from an MCP server |
Transport Types
stdio
Spawns a local process and communicates via stdin/stdout:
{
"type": "stdio",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/path"],
"env": { "API_KEY": "..." },
"cwd": "/working/dir"
}StreamableHTTP
Modern HTTP transport (recommended for remote servers):
{
"type": "streamable-http",
"url": "https://example.com/mcp",
"headers": { "Authorization": "Bearer ..." }
}SSE (legacy)
Server-Sent Events transport:
{
"type": "sse",
"url": "https://example.com/sse"
}WebSocket
Real-time bidirectional transport:
{
"type": "websocket",
"url": "ws://localhost:8080/mcp"
}Tool Filtering
Control which tools are registered per server using allowlist or denylist:
// Only register specific tools (allowlist)
{
"name": "filesystem",
"allowedTools": ["read_file", "list_directory"],
...
}
// Register all except (denylist)
{
"name": "github",
"deniedTools": ["delete_repository", "create_issue"],
...
}Or via commands:
/mcp filter github allow search_repositories,get_file_contents
/mcp filter filesystem deny write_file,delete_file
/mcp filter github clearEnvironment Variable Interpolation
Use ${ENV_VAR} patterns in config values to avoid hardcoding secrets:
{
"name": "github",
"transport": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": {
"GITHUB_TOKEN": "${GITHUB_TOKEN}"
}
}
}HTTP headers also support interpolation:
{
"transport": {
"type": "streamable-http",
"url": "https://api.example.com/mcp",
"headers": {
"Authorization": "Bearer ${API_TOKEN}"
}
}
}As a Library
You can use @0xkobold/pi-mcp as a standalone library, without pi-coding-agent:
// Main entry — extension + all re-exports
import mcpExtension, {
MCPConnectionManager,
ResourceCache,
interpolateEnv,
loadConfig,
saveConfig,
createDefaultConfig,
isToolAllowed,
} from "@0xkobold/pi-mcp";
// Client subpath — connection management only
import { MCPConnectionManager, type MCPServerConfig } from "@0xkobold/pi-mcp/client";
// Config subpath — config loading/saving only
import { loadConfig, upsertServer, type MCPConfig } from "@0xkobold/pi-mcp/config";
// Tools subpath — tool registration utilities only
import { isToolAllowed, DEFAULT_MAX_TOOLS } from "@0xkobold/pi-mcp/tools";Quick start without pi-coding-agent:
import { MCPConnectionManager } from "@0xkobold/pi-mcp/client";
const manager = new MCPConnectionManager([process.cwd()]);
const serverConfig = {
name: "filesystem",
transport: { type: "stdio", command: "npx", args: ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"] },
enabled: true,
autoReconnect: true,
};
const info = await manager.connect(serverConfig);
console.log(`Connected: ${info.tools.length} tools`);
const result = await manager.callTool("filesystem", "read_file", { path: "/tmp/hello.txt" });
console.log(result);Architecture
src/
├── index.ts # Extension entry point (commands, tools, lifecycle)
├── client/
│ └── index.ts # MCPConnectionManager, ResourceCache, env interpolation
├── config/
│ └── index.ts # Config loading/saving, Claude Desktop import, project merge
└── tools/
└── index.ts # Tool bridge - MCP tools → pi tools (with filtering)Configuration
Config file: ~/.0xkobold/mcp.json
Full schema:
{
"servers": [
{
"name": "string (required)",
"transport": {
"type": "stdio | sse | streamable-http | websocket",
// stdio fields:
"command": "string",
"args": ["string"],
"env": {},
"cwd": "string",
// http/sse fields:
"url": "string",
"headers": {},
"sessionId": "string",
// websocket fields:
"url": "ws://..."
},
"enabled": false,
"autoReconnect": true,
"maxReconnectAttempts": 5,
"reconnectDelayMs": 1000,
"connectTimeoutMs": 30000,
"allowedTools": ["tool_name"],
"deniedTools": ["tool_name"],
"maxTools": 50
}
],
"importClaudeDesktop": true
}Claude Desktop Compatibility
Set "importClaudeDesktop": true to automatically discover servers from:
~/.claude/mcp.json~/.config/claude-code/mcp.json
Or run /mcp import to manually import.
Development
# Install dependencies
bun install
# Build
bun run build
# Development watch
bun run dev
# Test
bun test # 95 tests, 182 assertions
bun test test/unit.test.ts # Unit tests only
bun test test/integration.test.ts # Integration tests (requires npx)Sampling Support
MCP servers can request LLM sampling via sampling/createMessage. The extension registers a handler for this capability.
- Default handler: Logs the request and returns a placeholder response (pi extensions don't have direct LLM completion access)
- Custom handler: Pass a
SamplingHandlerfunction toMCPConnectionManagerconstructor:
import { MCPConnectionManager, type SamplingHandler } from "@0xkobold/pi-mcp/client";
const handler: SamplingHandler = async (params) => {
// Bridge to your LLM here
return {
role: "assistant",
content: { type: "text", text: "LLM response" },
model: "your-model",
stopReason: "endTurn",
};
};
const manager = new MCPConnectionManager(["/workspace"], 50, 300_000, handler);License
MIT
