| name | mcpctl |
| description | Manage MCP server configurations — add, remove, list, inspect, troubleshoot. Use when asked to "add mcp server", "remove mcp", "list mcp servers", "mcp status", "configure mcp", "troubleshoot mcp", or any MCP server management task. |
mcpctl — MCP server management
Manage MCP server configurations for pi-mcp-adapter. Supports global and project scopes, stdio and HTTP server types.
Load order
pi-mcp-adapter merges configs in this order (later wins):
- Global —
~/.pi/agent/mcp.json
- Imports — configs from other tools (vscode, cursor, claude-code, codex, windsurf)
- Project —
.pi/mcp.json in project root
Project-level entries override global entries with the same name.
Imports
Project .pi/mcp.json can import servers from other tools:
{
"imports": ["vscode", "cursor", "claude-code"],
"mcpServers": {
"my-server": { ... }
}
}
Supported import sources: vscode, cursor, claude-code, codex, windsurf. Imported servers are merged between global and project configs.
Scope rules
| Scope | Config file | Managed by | How to edit |
|---|
| Global | ~/.pi/agent/mcp.json | Nix (home-manager) | Edit ~/.dotfiles/home/common/programs/pi-coding-agent/mcp.json, then just home |
| Project | .pi/mcp.json (project root) | Direct | Write file directly |
Global is nix-managed. The file at ~/.pi/agent/mcp.json is a symlink to the nix store. To change it:
- Edit the source:
~/.dotfiles/home/common/programs/pi-coding-agent/mcp.json
- Run
just home (or just rebuild) to apply
- Reload pi with
/reload
Project is direct. Write .pi/mcp.json in the project root. No rebuild needed — just /reload.
Server types
Stdio — runs a local command
{
"mcpServers": {
"server-name": {
"command": "npx",
"args": ["-y", "package-name@latest"],
"env": { "KEY": "value" },
"cwd": "/optional/working/dir"
}
}
}
HTTP — connects to a URL
{
"mcpServers": {
"server-name": {
"url": "http://localhost:8080/mcp",
"headers": { "Authorization": "Bearer token" }
}
}
}
Short form (URL only, type inferred):
{
"mcpServers": {
"server-name": {
"url": "https://example.com/mcp"
}
}
}
Config options (all optional)
| Field | Type | Description |
|---|
command | string | Executable to run (stdio) |
args | string[] | Command arguments (stdio) |
env | object | Environment variables (stdio) |
cwd | string | Working directory (stdio) |
url | string | Server URL (HTTP) |
headers | object | HTTP headers (HTTP) |
auth | "oauth" or "bearer" | Auth method (HTTP) |
bearerToken | string | Static bearer token |
bearerTokenEnv | string | Env var name for bearer token |
lifecycle | "lazy" / "eager" / "keep-alive" | Connection strategy (default: lazy) |
idleTimeout | number | Minutes before idle disconnect |
debug | boolean | Show server stderr |
Lifecycle modes:
- lazy (default) — connects on first tool call, disconnects after idle timeout
- eager — connects at session start, no auto-disconnect
- keep-alive — connects at start, auto-reconnects if dropped
Operations
Add
- Ask scope if not obvious (global for cross-project, project for local)
- Ask server type if not obvious (stdio or HTTP)
- Gather config (command/url, args, env, etc.)
- Read target config file (source file for global,
.pi/mcp.json for project)
- Warn if server name already exists — confirm before overwriting
- Merge new server into existing
mcpServers object
- Write updated JSON
- For global: edit nix source file, inform user
just home is needed, then /reload
- For project: write directly, then
/reload
- Verify:
mcp({ connect: "server-name" }) then mcp({ server: "server-name" })
Remove
- Determine which scope has the server (check project first, then global)
- Read the config file
- Remove the server entry from
mcpServers
- Write updated JSON
- For global: edit nix source, inform user
just home is needed
/reload to apply
List
- Read global config:
~/.dotfiles/home/common/programs/pi-coding-agent/mcp.json
- Read project config:
.pi/mcp.json in cwd (if exists)
- Show all servers with:
- Name
- Type (stdio/HTTP)
- Scope (global/project/imported)
- Connection info (command or URL)
- Use
mcp({}) to check which are currently connected and list their tools
Inspect
- Show full config for the named server
- Show which scope it comes from
- Use
mcp({ server: "server-name" }) to list available tools
- Use
mcp({ connect: "server-name" }) to test connection if not connected
Troubleshoot
When a server isn't working:
- Check config syntax — read and validate the JSON
- Check scope — is it in the right config file?
- Check connection —
mcp({ connect: "server-name" })
- For stdio: verify command exists (
which <command>), check env vars
- For HTTP: verify URL is reachable (
curl -s -o /dev/null -w "%{http_code}" <url>)
- Check for name conflicts — same name in global and project?
- Check lifecycle — eager/keep-alive servers should connect at start
- Report findings with specific fix suggestions