SkillAgentSearch skills...

pi-mcp-adapter

Token-efficient MCP adapter for Pi coding agent

Install / Use

claude mcp add nicobailon -- npx -y github:nicobailon/pi-mcp-adapter

If the server publishes to npm under a different name, use that package instead — check the repo README.

About this skill
🔌

MCP Server

Model Context Protocol server

Quality Score

78/100

Supported Platforms

Claude Code
Claude Desktop

Tags

<p> <img src="banner.png" alt="pi-mcp-adapter" width="1100"> </p>

Pi MCP Adapter

Use MCP servers with Pi without burning your context window.

https://github.com/user-attachments/assets/4b7c66ff-e27e-4639-b195-22c3db406a5a

Why This Exists

Mario wrote about why you might not need MCP. The problem: tool definitions are verbose. A single MCP server can burn 10k+ tokens, and you're paying that cost whether you use those tools or not. Connect a few servers and you've burned half your context window before the conversation starts.

His take: skip MCP entirely, write simple CLI tools instead.

But the MCP ecosystem has useful stuff - databases, browsers, APIs. This adapter gives you access without the bloat. One proxy tool (~200 tokens) instead of hundreds. The agent discovers what it needs on-demand. Servers only start when you actually use them.

Install

pi install npm:pi-mcp-adapter

Restart Pi after installation.

What happens on first run

The adapter reads standard MCP files automatically. No extra setup needed if you already have them.

| You already have... | What happens | |---------------------|--------------| | .mcp.json or ~/.config/mcp/mcp.json | Pi uses it immediately. The first time you open /mcp, you'll see a short heads-up explaining which file Pi detected and that Pi only writes adapter-specific overrides to its own files. | | Host-specific configs (Cursor, Claude Code, Codex, etc.) but no standard MCP files | Run /mcp setup to adopt those host configs into Pi. The setup flow shows exactly what it found, lets you pick which ones to import, and previews the exact file changes before writing. | | Nothing configured yet | Run /mcp setup to scaffold a minimal .mcp.json, add a curated known server, quick-add RepoPrompt, or inspect what the adapter discovered on your machine. |

If you prefer the terminal, you can also run pi-mcp-adapter init after install to scan for host-specific configs and add missing compatibility imports to the Pi agent dir (~/.pi/agent/mcp.json by default, or $PI_CODING_AGENT_DIR/mcp.json when set).

Quick Start

Preferred project config: .mcp.json

{
  "mcpServers": {
    "chrome-devtools": {
      "command": "npx",
      "args": ["-y", "chrome-devtools-mcp@1.6.0"]
    }
  }
}

Preferred user-global shared config: ~/.config/mcp/mcp.json. Pi also reads the tool-agnostic global paths ~/.agents/mcp.json and ~/.agents/mcp/mcp.json.

Pi also reads Pi-owned override files for settings and host-specific compatibility:

  • <Pi agent dir>/mcp.json — Pi global override (~/.pi/agent/mcp.json by default)
  • .pi/mcp.json — Pi project override

Host-specific configs are detected and shown by /mcp setup and pi-mcp-adapter init, but they are not loaded automatically. The normal /mcp panel does not scan host-specific files when settings.hostConfigDiscovery is "off". To explicitly opt in to host-config fallback discovery, set settings.hostConfigDiscovery to "on" or run pi-mcp-adapter init --discover-host-configs. The default is "off"; "prompt" is available for integrations that want detection without activation. Host configs are lower precedence than every shared and Pi-owned source, and /mcp setup continues to offer explicit import adoption. Discovery reports source paths, provenance, and same-name conflicts; it never writes to external host files or silently launches commands from them.

Precedence is:

  1. ~/.config/mcp/mcp.json
  2. ~/.agents/mcp.json
  3. ~/.agents/mcp/mcp.json
  4. <Pi agent dir>/mcp.json
  5. .mcp.json
  6. .pi/mcp.json

/mcp disable <server> and /mcp enable <server> persist only the disabled field in the project-local .pi/mcp.json, which is the highest-precedence Pi layer. Enabling removes the project flag when lower layers are enabled, or writes false when needed to override a disabled lower source. This applies even when the effective server came from a shared global/project file, an imported host config, or configPath; the source file is never rewritten and credentials are never copied. Run /reload after changing the flag so registered tool surfaces are refreshed. The manual equivalent is to add { "disabled": true } to a server in any normal MCP config. Supplied in-memory createMcpAdapter({ config }) configurations are isolated and do not read or write this project override; the commands are unavailable in that mode.

Servers are lazy by default — they won't connect until you actually call one of their tools. The adapter caches tool metadata so search and describe work without live connections.

mcp({ search: "screenshot" })
chrome_devtools_take_screenshot
  Take a screenshot of the page or element.

  Parameters:
    format (enum: "png", "jpeg", "webp") [default: "png"]
    fullPage (boolean) - Full page instead of viewport
mcp({ tool: "chrome_devtools_take_screenshot", args: { format: "png" } })

args can be a JSON object or a JSON string. Prefer the object form when your model handles it reliably; the string form remains supported for providers that need simpler schemas.

Two calls instead of 26 tools cluttering the context.

Config

File Layout

Use the shared MCP files when you want one setup to work across hosts, and Pi-owned files when you need Pi-specific overrides or settings.

| File | Purpose | |------|---------| | ~/.config/mcp/mcp.json | User-global shared MCP config | | ~/.agents/mcp.json | User-global tool-agnostic MCP config | | ~/.agents/mcp/mcp.json | User-global tool-agnostic MCP config | | .mcp.json | Project-local shared MCP config | | <Pi agent dir>/mcp.json | Pi global override and compatibility imports (~/.pi/agent/mcp.json by default) | | .pi/mcp.json | Pi project override |

Pi-specific files are the write targets for imported or shared global servers when Pi needs to persist adapter-only settings such as directTools.

Agent Plugins

The adapter can load MCP servers from Agent Plugins packages when you list plugin directories in settings.agentPluginPaths:

{
  "settings": {
    "agentPluginPaths": ["./plugins/acme-tools"]
  },
  "mcpServers": {}
}

Each directory must contain a valid Agent Plugins 1.0 plugin.json. If it also has a root mcp.json, the adapter loads its mcpServers entries and prefixes them as <plugin>__<server>. The loader uses the Agent Plugins transport declared by each server type and skips invalid entries without blocking other servers. For stdio plugin servers, ${PLUGIN_ROOT} and ${PLUGIN_DATA} are expanded only in args, env, and cwd; the adapter sets both variables for the child process and stores plugin data under the Pi agent directory.

Agent Plugins is a portable package format. Native Pi MCP config remains .mcp.json, ~/.config/mcp/mcp.json, and Pi-owned overrides.

SDK configuration

Use createMcpAdapter when an SDK or server integration already owns its MCP configuration:

import { createMcpAdapter } from "pi-mcp-adapter";

const extension = createMcpAdapter({
  config: {
    mcpServers: {
      docs: {
        url: "https://mcp.example.com/mcp",
        lifecycle: "eager",
      },
    },
  },
});

// Register `extension` with the host SDK.

The package ships TypeScript source for Pi's source-loader and SDK integrations. Use a TypeScript-capable loader/toolchain (for example node --import tsx) when importing the package from a standalone Node process; raw Node ESM does not execute the .ts entry directly.

A supplied config is a complete, isolated snapshot. It is not merged with files, imports, global config, project config, or --mcp-config, and it is never mutated. Each adapter factory and session receives its own clone, so separate integrations can use different servers and settings safely. In this mode, server status, reconnect, explicit /mcp-auth <server>, proxy calls, and direct tools continue to work; setup and no-argument auth/status panels report the limitation instead of discovering or writing ambient config.

With configPath and no config, the adapter keeps normal file merge behavior, and that path takes precedence over argv and --mcp-config. The default export keeps the normal file-based behavior. OAuth credentials are stored in the operating system credential store and keyed by the configured server name; URL binding prevents credentials from being accepted for a different server URL. settings.oauthDir and MCP_OAUTH_DIR are used only as legacy plaintext import locations for older tokens.json files, not as credential namespaces. CSRF state and PKCE verifiers are flow-local, so concurrent authorization flows do not share transient secrets.

Runtime status snapshots

Extensions can subscribe to the adapter's versioned shared event-bus channel instead of parsing /mcp or mcp({}) output:

import { MCP_STATUS_EVENT, type McpStatusSnapshot } from "pi-mcp-adapter";

pi.events.on(MCP_STATUS_EVENT, (snapshot) => {
  const status = snapshot as McpStatusSnapshot;
  // status.servers contains connected, cached, failed, needs-auth,
  // not-connected, or disabled entries.
});

The snapshot is read-only machine-readable data with copied per-server entries. It includes totalTools, totalResources, connectedCount, and disabledCount; each server includes name, status, toolCount, and disabled, with resourceCount when known and failedAgoSeconds only for an active failure. Reading status never connects a lazy server, starts authentication, or exposes SDK clients, transports, credentials, or server definitions. An initial snapshot is emitted after initialization, updates are emitted for status and metadata changes, and an empty snapshot is emitted when the session shuts down.

In the configuration examples below, 30000 is illustrative only. If requestTimeoutMs is omitted or set to <= 0, the MCP SDK default timeout is used.

Server Options

{
  "mcpServers": {
    "my-server": {
      "command": "npx",
      "args": ["-y", "some-mcp-server"],
      "lifecycle": "lazy",
      "idleTimeout": 10,
      "requestTimeoutMs": 30000
    }
  }
}

| Field | Description | |-------|-------------| | command | Executable for stdio transport; mutually exclusive with url and socket | | args | Command arguments | | socket | Explicit rmcp-mux Unix-domain socket path; supports ${VAR}, $env:VAR, and ~ expansion and is mutually exclusive with command and url | | env | Environment variables; supports ${VAR} and $env:VAR interpolation. A value beginning with ! runs a command when the stdio server connects; use !! for a literal leading !. | | cwd | Working directory; supports ${VAR}, $env:VAR, and ~ expansion | | url | HTTP endpoint (StreamableHTTP with SSE fallback); supports raw ${VAR} and $env:VAR interpolation, and missing URL variables fail before any request is sent | | headers | HTTP headers; supports ${VAR} and $env:VAR interpolation. A value beginning with ! runs a command when the HTTP server connects or OAuth authenticates; use !! for a literal leading !. | | auth | "bearer" or "oauth" | | oauth.grantType | "authorization_code" (default) or "client_credentials" for non-interactive machine auth | | oauth.clientId | Pre-registered OAuth client ID. MCP 2026 prefers pre-registered clients or Client ID Metadata Documents; this adapter falls back to Dynamic Client Registration when the ID is omitted and the server supports it. | | oauth.clientSecret | OAuth client secret for confidential clients; a value beginning with ! runs a command when OAuth authenticates, while !! escapes a literal leading ! | | oauth.scope | Requested OAuth scopes | | oauth.redirectUri | Exact localhost redirect

Truncated for display — read the full file on GitHub.

Related Skills

View on GitHub
GitHub Stars1.5k
CategoryAI
Updated7h ago
Forks361

Languages

TypeScript

Security Score

95/100

Audited on Sep 22, 2026

1 low