# pi-mcp-sidecar

`pi-mcp-sidecar` is a companion [Pi](https://pi.dev) extension for [`pi-mcp-adapter`](https://github.com/nicobailon/pi-mcp-adapter). It adds the `/mcpc` command without replacing `/mcp`, importing adapter internals, or modifying the adapter package.

It can fully block an MCP server so the adapter cannot connect to it or expose any of its tools, prompts, descriptions, panel entries, or status information. The original configuration can be restored later.

## Why

Setting `disabled: true` in `pi-mcp-adapter` prevents a connection, but the server can still appear in adapter descriptions, `/mcp`, and status output. MCPC instead archives every active configuration fragment for the selected server and removes those fragments from the adapter's configuration sources. After Pi reloads, the adapter no longer sees that server at all.

MCPC does not depend on private adapter APIs. It independently follows the adapter's public configuration layout so it can remain installed alongside adapter updates.

## Features

- Fully block an MCP server across all active configuration layers.
- Restore every archived fragment to its original location and value.
- Refuse to overwrite a same-name definition created after the server was blocked.
- Clean up stale archives after `/mcp setup` or a manual replacement.
- Stage multiple changes in an interactive TUI and apply them with one Pi reload.
- Preserve unrelated JSON/JSONC content, including comments and trailing commas.
- Use atomic writes, multi-file rollback, persistent recovery state, and a process lock.
- Register only `/mcpc`; `/mcp` remains owned by `pi-mcp-adapter`.

## Installation

Install both the adapter and this sidecar from npm:

```bash
pi install npm:pi-mcp-adapter
pi install npm:pi-mcp-sidecar
```

Run `/reload` once if Pi was already open. Later successful block and enable operations reload Pi automatically.

A Git checkout can also be installed directly:

```bash
pi install git:github.com/ClineMoretti/pi-mcp-sidecar
```

For local development:

```bash
pi install /absolute/path/to/pi-mcp-sidecar
```

Do not install the npm, Git, and local-path variants at the same time; they would register the same `/mcpc` command more than once.

## Commands

```text
/mcpc                       Open the interactive server list
/mcpc list                  Open the list, or print status outside TUI mode
/mcpc block <server>        Block a server and reload Pi
/mcpc enable <server>       Restore a blocked server and reload Pi
/mcpc cleanup <server>      Remove one stale archive with a same-name conflict
/mcpc cleanup --all         Remove all stale archives with conflicts
```

### Interactive controls

- `Up` / `Down`: Move the cursor. Pi's `tui.select.up/down` keybindings are respected.
- `Space`: Stage the selected server as enabled (`●`) or blocked (`○`) without leaving the panel.
- `Ctrl+S`, `Esc`, or `q`: Save all pending changes, close the panel, and reload Pi once.
- `Ctrl+C`: Discard pending changes and close the panel.

The panel marks pending rows with `*`. It reloads only when at least one saved change succeeds.

## Same-name conflicts

Suppose `demo` is blocked and `/mcp setup` later creates a new definition named `demo`:

1. MCPC reports a conflict on session reload and marks the item as `conflict`.
2. `/mcpc enable demo` refuses to restore the archive and does not overwrite the new definition.
3. After confirming that the new definition should be kept, run `/mcpc cleanup demo` to discard the stale archive.

Cleanup is allowed only for genuine conflicts. An authoritative archive cannot be deleted accidentally through the cleanup command.

## Configuration sources

MCPC follows the adapter's layered configuration and discovery behavior for:

- `~/.config/mcp/mcp.json`
- `~/.agents/mcp.json`
- `~/.agents/mcp/mcp.json`
- `~/.pi/agent/mcp.json`, including `PI_CODING_AGENT_DIR`
- `<project>/.mcp.json`
- `<project>/.pi/mcp.json`
- `--mcp-config <path>`
- Cursor, Claude Code, Claude Desktop, Codex, OpenCode, Windsurf, and VS Code imports
- `settings.hostConfigDiscovery: "on"`

For OpenCode, MCPC handles every global and project fragment that contributes to one merged server.

## State and file safety

Blocked definitions are archived in `~/.pi/agent/mcpc-state.json`, or the equivalent directory selected by `PI_CODING_AGENT_DIR`. The file is written with restrictive permissions where the platform supports them.

MCP definitions can contain headers, tokens, environment variables, and other secrets. Never publish, share, or commit `mcpc-state.json`.

Configuration updates use temporary files and atomic rename. A failed multi-file commit rolls back files already written. Block persists its archive before deleting source definitions; enable restores definitions before removing the archive. A short-lived exclusive lock prevents concurrent MCPC operations from corrupting state.

JSON and JSONC use targeted edits, preserving unrelated comments and trailing commas. TOML is parsed and serialized structurally, so its meaning is preserved but formatting and comments may change.

## Shared import warning

To make an imported server completely invisible to the adapter, MCPC must temporarily remove it from the active shared source. While blocked, other applications using the same Cursor, Codex, OpenCode, or similar configuration will also stop seeing that server. Enabling it restores the archived definition. Other server entries are not changed.

## Compatibility

The current release is integration-tested with:

- Pi `0.82.1`
- `pi-mcp-adapter` `2.15.0`
- Node.js `22.19.0` or newer

The extension is an independent package, so adapter updates do not overwrite its code or state.

## Development

```bash
npm install --legacy-peer-deps
npm run check
npm pack --dry-run
```

The test suite covers layered JSON/JSONC configuration, Codex TOML imports, merged OpenCode sources, same-name conflicts, staged TUI changes, cancellation, and single-reload batch application.

## License

MIT
