pi-mcp-adapter 2.37.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/CHANGELOG.md +53 -1
  2. package/OAUTH.md +369 -0
  3. package/README.md +67 -52
  4. package/cli.js +9 -9
  5. package/commands.ts +21 -10
  6. package/config.ts +230 -43
  7. package/direct-tool-surface.ts +2 -2
  8. package/direct-tools.ts +7 -5
  9. package/dist/config.d.ts +13 -0
  10. package/dist/config.js +217 -41
  11. package/dist/config.js.map +1 -1
  12. package/dist/json-schema-validator.js +15 -2
  13. package/dist/json-schema-validator.js.map +1 -1
  14. package/dist/mcp-auth.d.ts +2 -0
  15. package/dist/mcp-auth.js +27 -2
  16. package/dist/mcp-auth.js.map +1 -1
  17. package/dist/metadata-cache.js +1 -1
  18. package/dist/metadata-cache.js.map +1 -1
  19. package/dist/package-mcp-loader.d.ts +9 -1
  20. package/dist/package-mcp-loader.js +8 -4
  21. package/dist/package-mcp-loader.js.map +1 -1
  22. package/dist/server-manager.js +6 -4
  23. package/dist/server-manager.js.map +1 -1
  24. package/dist/state.d.ts +5 -1
  25. package/dist/types.d.ts +14 -4
  26. package/dist/types.js.map +1 -1
  27. package/dist/utils.d.ts +5 -0
  28. package/dist/utils.js +17 -3
  29. package/dist/utils.js.map +1 -1
  30. package/index.ts +105 -37
  31. package/init.ts +28 -19
  32. package/json-schema-validator.ts +16 -2
  33. package/mcp-auth.ts +27 -2
  34. package/mcp-code.ts +55 -28
  35. package/mcp-panel.ts +6 -5
  36. package/mcp-script-wasm.ts +24 -0
  37. package/mcp-script-worker.mjs +228 -116
  38. package/mcp-setup-panel.ts +9 -10
  39. package/mcp-status.ts +8 -1
  40. package/metadata-cache.ts +1 -1
  41. package/namespace-tools.ts +5 -1
  42. package/package-mcp-loader.ts +21 -6
  43. package/package.json +6 -2
  44. package/project-server-trust.ts +199 -0
  45. package/prompts.ts +5 -5
  46. package/proxy-modes.ts +36 -30
  47. package/semantic-search.ts +1 -1
  48. package/server-manager.ts +6 -3
  49. package/state.ts +5 -1
  50. package/tool-result-renderer.ts +99 -6
  51. package/types.ts +14 -3
  52. package/ui-session.ts +60 -27
  53. package/utils.ts +22 -3
package/README.md CHANGED
@@ -32,11 +32,11 @@ The adapter reads standard MCP files automatically. No extra setup needed if you
32
32
 
33
33
  | You already have... | What happens |
34
34
  |---------------------|--------------|
35
- | `.mcp.json` or `~/.config/mcp/mcp.json` | Pi uses it immediately. Use `.mcp.json` for project/team sharing and `~/.config/mcp/mcp.json` for all projects. 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. |
36
- | 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. |
37
- | Nothing configured yet | Run `/mcp setup`, choose project `.mcp.json` or global `~/.config/mcp/mcp.json`, then scaffold a minimal config, add a curated known server, quick-add RepoPrompt, or inspect what the adapter discovered on your machine. |
35
+ | `.mcp.json` or `~/.config/mcp/mcp.json` | Pi uses it immediately. Use `.mcp.json` for project/team sharing and `~/.config/mcp/mcp.json` for all projects. |
36
+ | Host-specific configs (Cursor, Claude Code, Codex, etc.) but no standard MCP files | Run `/mcp-adapter 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. |
37
+ | Nothing configured yet | Run `/mcp-adapter setup`, choose project `.mcp.json` or global `~/.config/mcp/mcp.json`, then scaffold a minimal config, add a curated known server, quick-add RepoPrompt, or inspect what the adapter discovered on your machine. |
38
38
 
39
- 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).
39
+ 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 adapter config (`~/.pi/agent/mcp-adapter.json` by default, or `$PI_CODING_AGENT_DIR/mcp-adapter.json` when set).
40
40
 
41
41
  ## Quick Start
42
42
 
@@ -55,27 +55,25 @@ Preferred project config: `.mcp.json`
55
55
 
56
56
  Preferred user-global shared config: `~/.config/mcp/mcp.json` (for all projects). Pi also reads the tool-agnostic global paths `~/.agents/mcp.json` and `~/.agents/mcp/mcp.json` as compatibility inputs.
57
57
 
58
- Pi-owned files are not additional normal setup choices. They hold Pi-specific settings, compatibility imports, and adapter-only overrides:
58
+ The adapter does not read Pi's `<Pi agent dir>/mcp.json` or `.pi/mcp.json` at all. If you previously used either file with this adapter, rename it to `mcp-adapter.json`; the format is unchanged, so a plain `mv` works (merge the files if the target already exists). This leaves `mcp.json` exclusively to Pi's built-in MCP support, so Pi and the adapter never start the same servers.
59
59
 
60
- - `<Pi agent dir>/mcp.json` — Pi global override (`~/.pi/agent/mcp.json` by default)
61
- - `.pi/mcp.json` — Pi project override
62
-
63
- Host-specific configs are detected and shown by `/mcp setup` and `pi-mcp-adapter init`, but they are compatibility inputs rather than normal setup paths and 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.
60
+ Host-specific configs are detected and shown by `/mcp-adapter setup` and `pi-mcp-adapter init`, but they are compatibility inputs rather than normal setup paths and are not loaded automatically. The normal `/mcp-adapter` 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 normal config source, and `/mcp-adapter 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.
64
61
 
65
62
  Precedence is (later entries win):
66
63
 
67
64
  1. `~/.config/mcp/mcp.json`
68
65
  2. `~/.agents/mcp.json`
69
66
  3. `~/.agents/mcp/mcp.json`
70
- 4. `<Pi agent dir>/mcp.json`
71
- 5. `.mcp.json`
72
- 6. `.pi/mcp.json`
67
+ 4. `<Pi agent dir>/mcp-adapter.json`
68
+ 5. opted-in ancestors, farthest first: `.mcp.json`, `.pi/mcp-adapter.json`
69
+ 6. `.mcp.json`
70
+ 7. `.pi/mcp-adapter.json`
73
71
 
74
- Ancestor discovery is off by default. To opt in, set `settings.ancestorConfigRoots` in a user-global config above, or in the explicitly selected `--mcp-config`/`configPath` file, for example `"ancestorConfigRoots": ["~/work/team"]`. Each root must be an explicit absolute path or `~/...`, resolve to an existing directory under `$HOME`, and contain the canonical cwd. If several roots match, only the nearest (deepest) is used. Project `.mcp.json` and `.pi/mcp.json` files cannot enable discovery or extend the boundary.
72
+ Ancestor discovery is off by default. To opt in, set `settings.ancestorConfigRoots` in a user-global source (`~/.config/mcp/mcp.json`, either `~/.agents` MCP file, or the global `mcp-adapter.json`) or in the explicitly selected `--mcp-config`/`configPath` file, for example `"ancestorConfigRoots": ["~/work/team"]`. Each root must be an explicit absolute path or `~/...` and resolve to an existing directory under `$HOME`. Roots that do not contain the canonical cwd are ignored. If several roots match, only the nearest (deepest) is used. Project files cannot enable discovery or extend the boundary.
75
73
 
76
- Within the selected root, existing `.mcp.json` and `<configDir>/mcp.json` (normally `.pi/mcp.json`) files load between steps 4 and 5, from the root through parent(cwd), farthest first. Nearer directories override farther ones, Pi overrides shared config within each directory, and cwd files win over ancestors. Search never goes above the configured root or `$HOME`; the boundary limits discovery but is not a file-ownership or symlink-target sandbox. Only configure roots whose project files you trust. `/mcp setup` write targets and project-local `/mcp disable` and `/mcp enable` overrides are unchanged.
74
+ Within the selected root, `.mcp.json` and `<configDir>/mcp-adapter.json` load from the root through parent(cwd), farthest first. Nearer directories override farther ones, adapter config overrides shared config within each directory, and cwd files win over ancestors. Search never goes above the configured root or `$HOME`; the boundary limits discovery but is not a file-ownership or symlink-target sandbox. Only configure roots whose project files you trust.
77
75
 
78
- `/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.
76
+ `/mcp-adapter disable <server>` and `/mcp-adapter enable <server>` persist only the `disabled` field in the project-local `.pi/mcp-adapter.json`, the highest-precedence adapter layer. The source file is never rewritten and credentials are never copied. Run `/reload` after changing the flag so registered tool surfaces are refreshed. Supplied in-memory `createMcpAdapter({ config })` configurations are isolated and do not read or write this project override; the commands are unavailable in that mode.
79
77
 
80
78
  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.
81
79
 
@@ -102,7 +100,7 @@ Two calls instead of 26 tools cluttering the context.
102
100
 
103
101
  ### File Layout
104
102
 
105
- 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.
103
+ Use shared MCP files when you want one setup to work across hosts, and adapter-owned files for adapter-specific overrides or settings.
106
104
 
107
105
  | File | Purpose |
108
106
  |------|---------|
@@ -110,8 +108,17 @@ Use the shared MCP files when you want one setup to work across hosts, and Pi-ow
110
108
  | `~/.agents/mcp.json` | User-global tool-agnostic MCP config |
111
109
  | `~/.agents/mcp/mcp.json` | User-global tool-agnostic MCP config |
112
110
  | `.mcp.json` | Project-local shared MCP config |
113
- | `<Pi agent dir>/mcp.json` | Pi global override and compatibility imports (`~/.pi/agent/mcp.json` by default) |
114
- | `.pi/mcp.json` | Pi project override |
111
+ | `<Pi agent dir>/mcp.json` | Pi built-in MCP config; never read by this adapter |
112
+ | `<Pi agent dir>/mcp-adapter.json` | Global adapter settings, imports, and overrides (`~/.pi/agent/mcp-adapter.json` by default) |
113
+ | `.pi/mcp.json` | Project Pi built-in MCP config; never read by this adapter |
114
+ | `.pi/mcp-adapter.json` | Project adapter settings and overrides |
115
+
116
+ For local stdio servers, a leading `~/` is expanded to the current user's home
117
+ directory in `command`, `args`, and `cwd`. On Windows, the equivalent `~\\`
118
+ form is supported too; on POSIX, backslashes remain literal filename
119
+ characters. Bare commands such as
120
+ `node`, `bunx`, or `git` continue to resolve through `PATH`.
121
+ Built-in Agent Plugin arguments remain literal; this path expansion applies to native and shared MCP configuration.
115
122
 
116
123
  Pi-specific files are the write targets for imported or shared global servers when Pi needs to persist adapter-only settings such as `directTools`.
117
124
 
@@ -130,7 +137,7 @@ The adapter can load MCP servers from [Agent Plugins](https://agent-plugins.org/
130
137
 
131
138
  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.
132
139
 
133
- `inheritEnv` is an adapter-specific Pi field, not an Agent Plugins or OpenCode schema field. Do not add it to a plugin's strict `mcp.json`; to opt a plugin stdio server out of host-environment inheritance, set `inheritEnv: false` in a normal Pi override using the translated `<plugin>__<server>` name:
140
+ `inheritEnv` is an adapter-specific field, not an Agent Plugins or OpenCode schema field. Do not add it to a plugin's strict `mcp.json`; to opt a plugin stdio server out of host-environment inheritance, set `inheritEnv: false` in an `mcp-adapter.json` override using the translated `<plugin>__<server>` name:
134
141
 
135
142
  ```json
136
143
  {
@@ -140,7 +147,7 @@ Each directory must contain a valid Agent Plugins 1.0 `plugin.json`. If it also
140
147
  }
141
148
  ```
142
149
 
143
- Agent Plugins is a portable package format. Native Pi MCP config remains `.mcp.json`, `~/.config/mcp/mcp.json`, and Pi-owned overrides.
150
+ Agent Plugins is a portable package format. Native adapter config remains `.mcp.json`, `~/.config/mcp/mcp.json`, and `mcp-adapter.json` overrides.
144
151
 
145
152
  ### Local Claude plugin bundles
146
153
 
@@ -258,7 +265,7 @@ The public subpath exposes only token read/update helpers plus a status helper.
258
265
 
259
266
  ### Runtime status snapshots
260
267
 
261
- Extensions can subscribe to the adapter's versioned shared event-bus channel instead of parsing `/mcp` or `mcp({})` output:
268
+ Extensions can subscribe to the adapter's versioned shared event-bus channel instead of parsing `/mcp-adapter` or `mcp({})` output:
262
269
 
263
270
  ```ts
264
271
  import { MCP_STATUS_EVENT, type McpStatusSnapshot } from "pi-mcp-adapter";
@@ -315,7 +322,7 @@ In the configuration examples below, `30000` is illustrative only. If `requestTi
315
322
  | `oauth.authServerMetadataUrl` | HTTPS URL of an OAuth/OIDC authorization-server metadata document. When set, this document is authoritative instead of MCP protected-resource discovery; its issuer remains validated by default |
316
323
  | `oauth.skipIssuerMetadataValidation` | `true` disables the OAuth authorization-server metadata issuer check for this server. This weakens OAuth mix-up protection and should only be used for known-misconfigured internal servers while their metadata is being fixed. |
317
324
  | `bearerToken` / `bearerTokenEnv` | Token or env var name; `bearerToken` supports `${VAR}` and `$env:VAR` interpolation. A leading `!` in `bearerToken` runs a command when the HTTP server connects; use `!!` for a literal leading `!`. |
318
- | `bearerTokenStore` | Set to `true` to read a static bearer token from the adapter-owned OS credential store when `auth` is `"bearer"` and no `bearerToken` or `bearerTokenEnv` is configured. Stored records are keyed only by the server name, bind to the resolved server URL, and are never named by config. Store a token with `pi-mcp-adapter token set <server>`, which reads it from a masked prompt or stdin pipe and never from an argument. `/mcp token status <server>` and `/mcp token remove <server>` manage non-secret state inside Pi; `/mcp token set` stays disabled until Pi exposes masked secret input. |
325
+ | `bearerTokenStore` | Set to `true` to read a static bearer token from the adapter-owned OS credential store when `auth` is `"bearer"` and no `bearerToken` or `bearerTokenEnv` is configured. Stored records are keyed only by the server name, bind to the resolved server URL, and are never named by config. Store a token with `pi-mcp-adapter token set <server>`, which reads it from a masked prompt or stdin pipe and never from an argument. `/mcp-adapter token status <server>` and `/mcp-adapter token remove <server>` manage non-secret state inside Pi; `/mcp-adapter token set` stays disabled until Pi exposes masked secret input. |
319
326
  | `lifecycle` | `"lazy"` (default), `"eager"`, `"keep-alive"`, or `"lazy-keep-alive"` |
320
327
  | `idleTimeout` | Minutes before idle disconnect (overrides global) |
321
328
  | `requestTimeoutMs` | Request timeout in milliseconds for live MCP calls (overrides global; if omitted or `<= 0`, the MCP SDK default timeout is used) |
@@ -420,9 +427,9 @@ Install an MCP endpoint without editing configuration:
420
427
  mcp({ action: "install", url: "https://example.com/mcp" })
421
428
  ```
422
429
 
423
- Install validates and connects the endpoint. New entries use a name derived from the hostname and are saved to Pi's global MCP config; existing URL entries are reused without rewriting. Pass `server` to choose a name or `target: "project"` to save to the project's `.mcp.json`. Unsafe URLs, name collisions, and failed connections are not persisted.
430
+ Install validates and connects the endpoint. New entries use a name derived from the hostname and are saved to the global `mcp-adapter.json`; existing URL entries are reused without rewriting. Pass `server` to choose a name or `target: "project"` to save to the project's `.mcp.json`. Unsafe URLs, name collisions, and failed connections are not persisted.
424
431
 
425
- Set `settings.allowInstall` to `false` in an MCP config file (`mcp.json` or `.mcp.json`, not Pi's `settings.json`) to block `mcp({ action: "install" })` for constrained or headless agents. Connect, search, tool calls, authentication, runtime registration, and interactive setup are unaffected.
432
+ Set `settings.allowInstall` to `false` in `mcp-adapter.json` or another adapter config source (not Pi's `mcp.json` or `settings.json`) to block `mcp({ action: "install" })` for constrained or headless agents. Connect, search, tool calls, authentication, runtime registration, and interactive setup are unaffected.
426
433
 
427
434
  In exclusive config mode, a project target must be the active config path; otherwise use the global target. URL install cannot promote runtime-registered servers: save their complete definitions manually so required headers and transport/auth settings are retained.
428
435
 
@@ -454,6 +461,12 @@ mcp({
454
461
 
455
462
  You can also pass only the `code` query parameter with `args: { code: "..." }`. Treat authorization URLs and codes as sensitive; they can grant access to the MCP server until the flow expires or completes.
456
463
 
464
+ ### Project server trust
465
+
466
+ Servers defined or changed by project-scoped MCP files (`.mcp.json`, `.pi/mcp-adapter.json`, and opted-in ancestor project files) do not run merely because a repository was opened. This includes servers brought in through project `imports`, `claudePlugins`, `settings.agentPluginPaths`, repo-local host config files (even when imports or discovery are enabled globally), or Pi packages listed in project `.pi/settings.json`. If Pi reports the project as untrusted, the adapter blocks them. In a trusted interactive session, the adapter shows the source file and command or URL and asks once before the first connection. The approval is stored under the Pi agent directory and is tied to the canonical project path, server name, and complete effective definition; changing the definition requires a new approval. Blocked servers are identified in the panel, while MCP status includes the required trust or approval action.
467
+
468
+ In print, JSON, and RPC sessions, an unapproved project server is skipped. To intentionally allow project servers in trusted headless sessions, set `"projectServers": "allow"` in the **user-global** `settings` object. The default is `"ask"`; project files cannot change this policy. Explicit config files, programmatic configuration, global/import/plugin servers, and runtime registrations retain their existing behavior. Project servers are always excluded from extension-load initialization and are admitted only after `session_start` supplies Pi's trust context.
469
+
457
470
  ### Lifecycle Modes
458
471
 
459
472
  - **`lazy`** (default) — Don't connect at startup. Connect on first tool call. Disconnect after idle timeout. Cached metadata keeps search/list working without connections.
@@ -482,6 +495,7 @@ When any enabled server uses `eager` or `keep-alive`, initialization also starts
482
495
  "notifyOnStartupConnect": true,
483
496
  "warnOnLargeDirectTools": true,
484
497
  "hostConfigDiscovery": "off",
498
+ "projectServers": "ask",
485
499
  "approveTools": ["github_delete_*", "notion_update_*"],
486
500
  "oauthDir": ".pi/mcp-oauth",
487
501
  "trace": {
@@ -503,12 +517,13 @@ When any enabled server uses `eager` or `keep-alive`, initialization also starts
503
517
  | `requestTimeoutMs` | Global request timeout in milliseconds for live MCP calls (if omitted or `<= 0`, the MCP SDK default timeout is used) |
504
518
  | `deferWithMissingMetadata` | Allow lazy startup to defer when persisted metadata is missing or invalid (default: `false`). See [Direct Tools](#direct-tools) for the startup tradeoff. |
505
519
  | `showStatusIcon` | Show the plug icon in MCP status and connection text (default: `true`). Set to `false` for plain `MCP: ...` text. |
506
- | `mcpFooterStatus` | MCP footer verbosity: `"full"` (default), `"compact"` for `MCP connected/enabled`, or `"off"` to clear the persistent footer status. `/mcp status` remains available. |
520
+ | `mcpFooterStatus` | MCP footer verbosity: `"full"` (default), `"compact"` for `MCP connected/enabled`, or `"off"` to clear the persistent footer status. `/mcp-adapter status` remains available. |
507
521
  | `toolResultRendering` | MCP tool result row style: `"compact"` (default) uses self-rendered rows, or `"boxed"` restores the legacy Pi boxed tool row. |
508
522
  | `collapsedResultLines` | Number of result text lines to show before expansion: `1`, `2`, or `3`. Defaults to `1` in compact mode and `3` in boxed mode. |
509
523
  | `notifyOnStartupConnect` | Show successful startup connection notices (default: `true`). Set to `false` to suppress routine `MCP: N servers connected (M tools)` notices. Connection errors and authentication warnings remain visible. |
510
524
  | `hostConfigDiscovery` | Host-specific config policy: `"off"` (default), `"prompt"` (detect/report only), or `"on"` (explicitly load detected host configs as the lowest-precedence fallback) |
511
- | `ancestorConfigRoots` | Trusted absolute or `~/...` roots for opt-in ancestor config discovery. Only user-global or explicitly selected config may set it; the deepest root containing cwd is used. |
525
+ | `projectServers` | Project-server admission policy for trusted headless sessions: `"ask"` (default, skip unapproved servers) or `"allow"`. Only user-global or explicitly selected config may set it; project files are ignored. |
526
+ | `ancestorConfigRoots` | Trusted absolute or `~/...` roots for opt-in ancestor config discovery. Only user-global or explicitly selected config may set it; roots outside cwd are ignored and the deepest matching root is used. |
512
527
  | `agentPluginPaths` | Agent Plugins package directories to load MCP servers from. Relative paths resolve from the active project cwd. |
513
528
  | `approveTools` | `true` to require approval before every MCP tool call, or an array of glob patterns such as `["github_delete_*", "notion_update_*"]`. Per-server `approveTools` overrides this. |
514
529
  | `oauthDir` | Legacy OAuth `tokens.json` import directory for this MCP config. Relative paths resolve from the active project cwd. `MCP_OAUTH_DIR` still wins when set. Persistent OAuth credentials are stored in the OS credential store, not this directory. |
@@ -522,8 +537,8 @@ When any enabled server uses `eager` or `keep-alive`, initialization also starts
522
537
  | `freezeDirectTools` | Keep direct-tool registration stable after the initial sync so metadata updates and explicit reconnects do not rebuild the system prompt. Proxy/search/cache metadata still refreshes. Default: false. |
523
538
  | `scriptMode` | Register the MCP-only `mcpScript` plain-JavaScript tool (default: true). Set to `false` to hide it. |
524
539
  | `exposeResources` | Expose MCP resources as tools (default: `true`). Set to `false` to disable globally across all servers. Per-server `exposeResources` overrides this. |
525
- | `jev` | Optional System One Jev settings. A valid System One key enables semantic search across every enabled MCP server by default; `semanticSearch: false` disables it. `scriptEvaluation` remains disabled by default and requires an `allowedServers` source allowlist when enabled. `jev: false` disables both. Run `/mcp jev setup` for guided configuration. |
526
- | `disableProxyTool` | Hide the `mcp` proxy tool once configured direct tools are fully available from cache. Ignored while any server uses `directTools: "search"`, whose tools are registered inactive and can only be activated through `mcp({ search })`. |
540
+ | `jev` | Optional System One Jev settings. A valid System One key enables semantic search across every enabled MCP server by default; `semanticSearch: false` disables it. `scriptEvaluation` remains disabled by default and requires an `allowedServers` source allowlist when enabled. `jev: false` disables both. Run `/mcp-adapter jev setup` for guided configuration. |
541
+ | `disableProxyTool` | Hide the `mcp` proxy tool once configured direct tools are fully available from cache. Ignored while any server uses `directTools: "search"`, whose tools are registered inactive and can only be activated through the gateway (`mcp({ search })` or a successful `mcp({ tool })` call). |
527
542
  | `autoAuth` | Auto-run OAuth on `connect`/tool calls when a server needs auth, then retry once (default: false). |
528
543
  | `sampling` | Allow MCP servers to sample through Pi models, honoring `modelPreferences.hints` before current/default fallback (default: true when UI approval is available). |
529
544
  | `samplingAutoApprove` | Skip sampling confirmation prompts. Required for sampling in non-UI sessions (default: false). |
@@ -621,7 +636,7 @@ The quickest desktop setup is:
621
636
  pi-mcp-adapter key set systemone
622
637
  ```
623
638
 
624
- That is enough to use semantic search across all enabled MCP tools. Run `/mcp jev setup` in Pi when you want to restrict which enabled servers may share semantic-search data. The command saves a project-scoped allowlist and reloads Pi automatically. Verify the stored credential at any time with `pi-mcp-adapter key status systemone`.
639
+ That is enough to use semantic search across all enabled MCP tools. Run `/mcp-adapter jev setup` in Pi when you want to restrict which enabled servers may share semantic-search data. The command saves a project-scoped allowlist and reloads Pi automatically. Verify the stored credential at any time with `pi-mcp-adapter key status systemone`.
625
640
 
626
641
  `SYSTEMONE_API_KEY` is for CI/headless use and overrides the keyring. Stdio MCP subprocesses inherit the host environment by default, so set `inheritEnv: false` where they must not receive it. The script worker receives no key, SDK, endpoint, headers, or environment.
627
642
 
@@ -698,7 +713,7 @@ The upstream tool executes before this check and may already have side effects.
698
713
 
699
714
  For a tool-restricted subagent, launch the child Pi with its tool allowlist set to `["mcpScript"]`. Have the parent discover MCP tool names with `mcp({ search: "..." })` and include the relevant prefixed names in the child's task; the child can then loop, filter, and chain those MCP calls without filesystem, shell, or edit tools. The adapter's ordinary lazy connection, authentication, abort handling, and approval gates still apply to every call.
700
715
 
701
- `mcpScript` is a trusted agent-authored MCP scripting layer, not an isolation boundary. If you need isolation, run Pi in an isolated environment. It is distinct from Pi's code-mode skill: Pi's skill batches general Pi tools, while `mcpScript` exposes MCP calls only and can be the child's sole tool.
716
+ `mcpScript` runs in an isolated QuickJS/WASM VM with a 64 MiB memory cap, a 16 MiB serialized output-block budget, and no Node.js, filesystem, network, timer, or process globals. Script error messages are capped at 64 KiB. MCP tool calls can still have external side effects and remain subject to the adapter's normal approval gates. It is distinct from Pi's code-mode skill: Pi's skill batches general Pi tools, while `mcpScript` exposes MCP calls only and can be the child's sole tool.
702
717
 
703
718
  ### MCP Prompts
704
719
 
@@ -707,7 +722,7 @@ MCP servers can advertise prompt templates alongside tools and resources. The ad
707
722
  ```text
708
723
  /mcp__agent_board__create_plan "harden retry policy"
709
724
  /mcp__agent_board__review_pipeline status=paused
710
- /mcp prompts
725
+ /mcp-adapter prompts
711
726
  ```
712
727
 
713
728
  Prompt results are flattened into one user message, preserving `[user]` and `[assistant]` role markers for multi-message results. Servers without the `prompts` capability are not probed.
@@ -784,7 +799,7 @@ Per-server `directTools` overrides the global setting. The example above registe
784
799
  }
785
800
  ```
786
801
 
787
- A successful `mcp({ search })` activates matching search-mode tools additively for the process lifetime and reports newly activated names in `addedToolNames`; no other operation activates them. A restart or resumed session starts with them inactive again. Selecting `directTools: true` activates held tools, while switching back to `"search"` holds them again. Search-mode tools do not count toward the 75-tool advisory.
802
+ A successful `mcp({ search })` activates matching search-mode tools additively for the rest of the session and reports newly activated names in `addedToolNames`. A successful `mcp({ tool })` call for a held search-mode tool activates it the same way, so the next call uses its real schema; a failed call (lookup, approval, or tool error) activates nothing. A restart or resumed session starts with them inactive again. Selecting `directTools: true` activates held tools, while switching back to `"search"` holds them again. Search-mode tools do not count toward the 75-tool advisory.
788
803
 
789
804
  To expose only a subset of a noisy server, add `includeTools` on the server. Values can be exact original names, generated resource names such as `read_<resource>`, prefixed names, or simple glob patterns:
790
805
 
@@ -814,11 +829,11 @@ To hide specific tools while still using `directTools: true`, add `excludeTools`
814
829
  }
815
830
  ```
816
831
 
817
- `includeTools` and `excludeTools` filter direct tools, proxy search/list/describe, and the `/mcp` panel view.
832
+ `includeTools` and `excludeTools` filter direct tools, proxy search/list/describe, and the `/mcp-adapter` panel view.
818
833
 
819
834
  Each direct tool costs ~150-300 tokens in the system prompt (name + description + schema). Good for targeted sets of 5-20 tools. For servers with 75+ tools, stick with the proxy or pick specific tools with a `string[]`. If 75+ direct tools resolve, the adapter prints an advisory but still registers the tools you configured. Set `settings.warnOnLargeDirectTools` to `false` to suppress this advisory.
820
835
 
821
- Direct tools register from the metadata cache in the Pi agent dir (`~/.pi/agent/mcp-cache.json` by default, or `$PI_CODING_AGENT_DIR/mcp-cache.json` when set), so no server connections are needed at startup. On the first session after adding `directTools` to a new server, the cache won't exist yet — tools fall back to proxy-only while the cache populates, then the extension hot-loads the refreshed direct tools into the current session. When `mcp({ connect: "<server>" })` is what discovers them, the connect result lists the new tools in `addedToolNames`, so Pi can load their definitions from that point in the transcript instead of rewriting the active tool list. Servers that advertise MCP list-change notifications refresh the current session when their tool or resource list changes. On Pi versions that expose `pi.unregisterTool()`, stale direct tools are removed from the registry during refresh; older Pi versions still deactivate them from the active tool set. To force a refresh: `/mcp reconnect <server>`.
836
+ Direct tools register from the metadata cache in the Pi agent dir (`~/.pi/agent/mcp-cache.json` by default, or `$PI_CODING_AGENT_DIR/mcp-cache.json` when set), so no server connections are needed at startup. On the first session after adding `directTools` to a new server, the cache won't exist yet — tools fall back to proxy-only while the cache populates, then the extension hot-loads the refreshed direct tools into the current session. When `mcp({ connect: "<server>" })` is what discovers them, the connect result lists the new tools in `addedToolNames`, so Pi can load their definitions from that point in the transcript instead of rewriting the active tool list. Servers that advertise MCP list-change notifications refresh the current session when their tool or resource list changes. On Pi versions that expose `pi.unregisterTool()`, stale direct tools are removed from the registry during refresh; older Pi versions still deactivate them from the active tool set. To force a refresh: `/mcp-adapter reconnect <server>`.
822
837
 
823
838
  For faster startup, set `settings.deferWithMissingMetadata` to `true`. Servers with missing or invalid metadata (expired, mismatched, or non-cacheable) then contribute no tools, prompts, resources, or search entries until the first MCP operation starts the runtime and loads live metadata; the `mcp` gateway stays available. Because Pi cannot unregister slash commands, cached prompt commands also wait for live metadata under this setting. `eager`/`keep-alive` servers and cold `MCP_DIRECT_TOOLS` selections still start immediately.
824
839
 
@@ -828,11 +843,11 @@ Set `settings.directToolResultDetails` to `"bounded"` when an extension needs st
828
843
 
829
844
  If prompt-cache stability matters more than direct-tool hot-loading, set `settings.freezeDirectTools` to `true`. The initial direct-tool sync still runs, but later metadata updates and explicit reconnects keep the registered tool surface unchanged while proxy/search/cache metadata refreshes normally.
830
845
 
831
- When you change direct-tool toggles in `/mcp`, the extension updates direct tool registration in the current session. Broader setup writes from `/mcp setup` still use Pi's normal reload flow because they can add or restructure MCP config files.
846
+ When you change direct-tool toggles in `/mcp-adapter`, the extension updates direct tool registration in the current session. Broader setup writes from `/mcp-adapter setup` still use Pi's normal reload flow because they can add or restructure MCP config files.
832
847
 
833
- **Interactive configuration:** Run `/mcp` to open an interactive panel showing all servers with connection status, tools, and direct/proxy toggles. You can reconnect servers, toggle tools between direct and proxy, and enable or disable servers (`ctrl+d`) from the same overlay. For OAuth, press Enter on a server that needs auth or `ctrl+a` on any OAuth server. The Save action defaults to `ctrl+s` and can be remapped with the `mcp.panel.save` keybinding.
848
+ **Interactive configuration:** Run `/mcp-adapter` to open an interactive panel showing all servers with connection status, tools, and direct/proxy toggles. `/mcp` is also available as an alias when Pi's built-in MCP extension is not installed. You can reconnect servers, toggle tools between direct and proxy, and enable or disable servers (`ctrl+d`) from the same overlay. For OAuth, press Enter on a server that needs auth or `ctrl+a` on any OAuth server. The Save action defaults to `ctrl+s` and can be remapped with the `mcp.panel.save` keybinding.
834
849
 
835
- **Guided first-run setup:** Run `/mcp setup` to choose the normal write target for new shared servers — project `.mcp.json` or global `~/.config/mcp/mcp.json` — inspect detected shared MCP files, adopt compatibility imports from other hosts, open discovered config paths, preview exact before/after file diffs for writes, scaffold a minimal selected config, add a curated known server (DeepWiki, Context7, Notion, GitHub, or Chrome DevTools), or quick-add RepoPrompt into a standard/shared MCP file.
850
+ **Guided first-run setup:** Run `/mcp-adapter setup` to choose the normal write target for new shared servers — project `.mcp.json` or global `~/.config/mcp/mcp.json` — inspect detected shared MCP files, adopt compatibility imports from other hosts, open discovered config paths, preview exact before/after file diffs for writes, scaffold a minimal selected config, add a curated known server (DeepWiki, Context7, Notion, GitHub, or Chrome DevTools), or quick-add RepoPrompt into a standard/shared MCP file.
836
851
 
837
852
  **Subagent integration:** If you use the subagent extension, agents can request direct MCP tools in their frontmatter with `mcp:server-name` syntax. See the subagent README for details.
838
853
 
@@ -847,7 +862,7 @@ MCP servers can ship interactive UIs via the [MCP UI](https://github.com/MCP-UI-
847
862
  3. pi-mcp-adapter fetches the UI HTML and opens it in an iframe
848
863
  4. The UI can call MCP tools and send messages back to the agent
849
864
 
850
- **Native rendering:** On macOS, if [Glimpse](https://github.com/hazat/glimpse) is installed (`pi install npm:glimpseui`), UIs open in a native WKWebView window instead of a browser tab. Set `MCP_UI_VIEWER=browser` to force the browser, `MCP_UI_VIEWER=glimpse` to require native rendering, or `MCP_UI_VIEWER=none` (also accepts `off` / `disabled`) to suppress the window entirely — the tool still runs and its inline result is returned to the agent, but no browser or native window opens. This is useful for headless setups, CI, or users who want the tool output delivered inline as text only. When suppressed, a one-line info notification shows the UI URL so it can still be opened manually if needed.
865
+ **Native rendering:** On macOS, if [Glimpse](https://github.com/hazat/glimpse) is installed (`pi install npm:glimpseui`), UIs open in a native WKWebView window instead of a browser tab. Set `MCP_UI_VIEWER=browser` to force the browser, `MCP_UI_VIEWER=glimpse` to require native rendering, `MCP_UI_VIEWER=orca` to open in the [Orca](https://github.com/orca) built-in browser (falls back to the system browser if Orca is unavailable), or `MCP_UI_VIEWER=none` (also accepts `off` / `disabled`) to suppress the window entirely — the tool still runs and its inline result is returned to the agent, but no browser or native window opens. This is useful for headless setups, CI, or users who want the tool output delivered inline as text only. When suppressed, a one-line info notification shows the UI URL so it can still be opened manually if needed.
851
866
 
852
867
  **Bidirectional communication:** The UI talks back. When it sends a prompt or intent, the message is stored and `triggerTurn()` wakes the agent. The agent retrieves messages via `mcp({ action: "ui-messages" })` and responds, enabling conversational UIs where the app and agent collaborate in real-time.
853
868
 
@@ -914,7 +929,7 @@ Supported compatibility imports: `cursor`, `claude-code`, `claude-desktop`, `ope
914
929
 
915
930
  ### Project Config
916
931
 
917
- Prefer `.mcp.json` for project-local shared MCP config and `~/.config/mcp/mcp.json` for user-global shared MCP config. Use `.pi/mcp.json` only when you need a Pi-specific project override. Project files override both user-global shared MCP config and Pi global overrides.
932
+ Prefer `.mcp.json` for project-local shared MCP config and `~/.config/mcp/mcp.json` for user-global shared MCP config. Use `.pi/mcp-adapter.json` for adapter-specific project overrides. Pi `mcp.json` files are not adapter inputs; project files override user-global sources.
918
933
 
919
934
  ## Usage
920
935
 
@@ -972,24 +987,24 @@ Servers that provide usage guidance via the MCP `instructions` field surface it
972
987
 
973
988
  | Command | What it does |
974
989
  |---------|--------------|
975
- | `/mcp` | Interactive panel and first-run onboarding surface |
976
- | `/pi-mcp` | Alias for `/mcp` when the host reserves `/mcp` |
977
- | `/mcp setup` | Guided setup for imports, a minimal `.mcp.json`, curated known servers, RepoPrompt quick-add, and config-path inspection |
978
- | `/mcp jev setup` | Restrict which servers may share semantic-search data, save the project policy, and reload Pi |
979
- | `/mcp edit [project\|global]` | Open `.mcp.json` (default) or `~/.config/mcp/mcp.json` in an editor; Ctrl+G opens `$EDITOR`; saves a valid JSONC object and reloads |
980
- | `/mcp tools` | List all tools |
981
- | `/mcp prompts` | List all MCP prompts registered as slash commands |
982
- | `/mcp reconnect` | Reconnect all servers |
983
- | `/mcp reconnect <server>` | Connect or reconnect a single server |
984
- | `/mcp disable <server>` | Disable a server in the project-local `.pi/mcp.json` (requires `/reload` to apply) |
985
- | `/mcp enable <server>` | Enable through the project-local override layer (requires `/reload` to apply) |
986
- | `/mcp logout <server>` | Clear stored OAuth credentials for a server and disconnect it |
990
+ | `/mcp-adapter` | Interactive panel and first-run onboarding surface |
991
+ | `/mcp` | Alias for `/mcp-adapter` only when Pi's built-in MCP extension is not installed |
992
+ | `/mcp-adapter setup` | Guided setup for imports, a minimal `.mcp.json`, curated known servers, RepoPrompt quick-add, and config-path inspection |
993
+ | `/mcp-adapter jev setup` | Restrict which servers may share semantic-search data, save the project policy, and reload Pi |
994
+ | `/mcp-adapter edit [project\|global]` | Open `.mcp.json` (default) or `~/.config/mcp/mcp.json` in an editor; Ctrl+G opens `$EDITOR`; saves a valid JSONC object and reloads |
995
+ | `/mcp-adapter tools` | List all tools |
996
+ | `/mcp-adapter prompts` | List all MCP prompts registered as slash commands |
997
+ | `/mcp-adapter reconnect` | Reconnect all servers |
998
+ | `/mcp-adapter reconnect <server>` | Connect or reconnect a single server |
999
+ | `/mcp-adapter disable <server>` | Disable a server in the project-local `.pi/mcp-adapter.json` (requires `/reload` to apply) |
1000
+ | `/mcp-adapter enable <server>` | Enable through the project-local override layer (requires `/reload` to apply) |
1001
+ | `/mcp-adapter logout <server>` | Clear stored OAuth credentials for a server and disconnect it |
987
1002
  | `/mcp-auth` | Open an OAuth server picker in interactive UI sessions |
988
1003
  | `/mcp-auth <server>` | OAuth setup for a specific server |
989
1004
 
990
1005
  If `settings.autoAuth` is `true`, `mcp({ connect: ... })`, `mcp({ tool: ... })`, and direct tool calls automatically run OAuth when needed and retry once.
991
1006
 
992
- In interactive sessions, you can also authenticate from `/mcp` with `ctrl+a` or Enter on a server that needs auth. `/mcp-auth` without a server only opens a picker in the interactive UI. For gateway authorization and manual callback completion, see [Remote/headless OAuth](#remoteheadless-oauth).
1007
+ In interactive sessions, you can also authenticate from `/mcp-adapter` with `ctrl+a` or Enter on a server that needs auth. `/mcp-auth` without a server only opens a picker in the interactive UI. For gateway authorization and manual callback completion, see [Remote/headless OAuth](#remoteheadless-oauth).
993
1008
 
994
1009
  ### MCP output schemas
995
1010
 
package/cli.js CHANGED
@@ -38,12 +38,12 @@ function getAgentDir() {
38
38
  }
39
39
 
40
40
  const AGENT_DIR = getAgentDir();
41
- const PI_CONFIG_PATH = path.join(AGENT_DIR, "mcp.json");
41
+ const PI_CONFIG_PATH = path.join(AGENT_DIR, "mcp-adapter.json");
42
42
  const GENERIC_GLOBAL_CONFIG_PATH = path.join(HOME, ".config", "mcp", "mcp.json");
43
43
  const AGENTS_GLOBAL_CONFIG_PATH = path.join(HOME, ".agents", "mcp.json");
44
44
  const AGENTS_NESTED_GLOBAL_CONFIG_PATH = path.join(HOME, ".agents", "mcp", "mcp.json");
45
45
  const PROJECT_CONFIG_PATH = path.resolve(process.cwd(), ".mcp.json");
46
- const PROJECT_PI_CONFIG_PATH = path.resolve(process.cwd(), getConfigDirName(), "mcp.json");
46
+ const PROJECT_PI_CONFIG_PATH = path.resolve(process.cwd(), getConfigDirName(), "mcp-adapter.json");
47
47
 
48
48
  const IMPORT_PATHS = {
49
49
  cursor: [path.join(HOME, ".cursor", "mcp.json")],
@@ -131,9 +131,9 @@ function printDiscovery(log, imports) {
131
131
  ["User-global standard MCP", GENERIC_GLOBAL_CONFIG_PATH],
132
132
  ["User-global .agents MCP", AGENTS_GLOBAL_CONFIG_PATH],
133
133
  ["User-global .agents nested MCP", AGENTS_NESTED_GLOBAL_CONFIG_PATH],
134
- ["Pi global override", PI_CONFIG_PATH],
134
+ ["MCP adapter global override", PI_CONFIG_PATH],
135
135
  ["Project standard MCP", PROJECT_CONFIG_PATH],
136
- ["Project Pi override", PROJECT_PI_CONFIG_PATH],
136
+ ["Project MCP adapter override", PROJECT_PI_CONFIG_PATH],
137
137
  ];
138
138
 
139
139
  for (const [label, filePath] of paths) {
@@ -171,8 +171,8 @@ async function runInit(argv, log = console.log) {
171
171
 
172
172
  const discoverySettingChanged = discoverHostConfigs && existingConfig.settings?.hostConfigDiscovery !== "on";
173
173
  if (importsToAdd.length === 0 && !discoverySettingChanged) {
174
- log("\nNo Pi config changes needed.");
175
- log("Standard MCP configs are discovered automatically, and host-specific imports are already configured or unavailable.");
174
+ log("\nNo MCP adapter config changes needed.");
175
+ log("Standard MCP configs are discovered automatically. Pi's mcp.json files are reserved for built-in MCP; adapter settings belong in mcp-adapter.json.");
176
176
  return 0;
177
177
  }
178
178
 
@@ -184,10 +184,10 @@ async function runInit(argv, log = console.log) {
184
184
  };
185
185
 
186
186
  if (importsToAdd.length > 0) {
187
- log(`\nDetected host configs to import into Pi: ${importsToAdd.join(", ")}`);
187
+ log(`\nDetected host configs to import into the MCP adapter: ${importsToAdd.join(", ")}`);
188
188
  }
189
189
  if (discoverySettingChanged) {
190
- log("Opting in to host-specific fallback discovery (standard and Pi-owned configs still take precedence).");
190
+ log("Opting in to host-specific fallback discovery (standard and adapter-owned configs still take precedence).");
191
191
  }
192
192
 
193
193
  if (dryRun) {
@@ -197,7 +197,7 @@ async function runInit(argv, log = console.log) {
197
197
 
198
198
  writePiConfig(nextConfig);
199
199
  log(`Updated ${PI_CONFIG_PATH}`);
200
- log("Pi will now keep reading standard MCP configs automatically, while these imports cover host-specific config formats.");
200
+ log("The adapter reads standard MCP configs automatically and stores adapter-specific imports in mcp-adapter.json; Pi's mcp.json is never read by the adapter.");
201
201
  if (discoverySettingChanged) {
202
202
  log("Host config discovery is explicit and does not write to or execute commands from external host files.");
203
203
  }
package/commands.ts CHANGED
@@ -32,6 +32,7 @@ import { loadOnboardingState, markSetupCompleted as persistSetupCompleted, markS
32
32
  import { formatTerminalError, openPath, resolveServerUrl, sanitizeTerminalText } from "./utils.ts";
33
33
  import { isAbortError } from "./runtime-owner.ts";
34
34
  import { resolveJevCredential } from "./jev-key-store.ts";
35
+ import { describeProjectServerBlock } from "./project-server-trust.ts";
35
36
 
36
37
  function terminalHyperlink(label: string, url: string): string {
37
38
  return `\u001B]8;;${sanitizeTerminalText(url)}\u001B\\${sanitizeTerminalText(label)}\u001B]8;;\u001B\\`;
@@ -75,7 +76,7 @@ export async function setupJevSemanticSearch(
75
76
  if (credential.status !== "present") {
76
77
  const detail = credential.status === "unavailable" ? ` ${credential.message}` : "";
77
78
  ctx.ui.notify(
78
- `Jev needs a System One API key.${detail}\nRun \`pi-mcp-adapter key set systemone\` in a terminal, then run \`/mcp jev setup\` again.`,
79
+ `Jev needs a System One API key.${detail}\nRun \`pi-mcp-adapter key set systemone\` in a terminal, then run \`/mcp-adapter jev setup\` again.`,
79
80
  "error",
80
81
  );
81
82
  return false;
@@ -141,18 +142,26 @@ export async function showStatus(state: McpExtensionState, ctx: ExtensionContext
141
142
  if (!ctx.hasUI) return;
142
143
 
143
144
  const lines: string[] = ["MCP Server Status:", ""];
145
+ if (state.migrationNotices?.length) {
146
+ lines.push(...state.migrationNotices.map((notice) => `⚠ ${notice}`), "");
147
+ }
144
148
  if (!state.programmaticConfig) {
145
149
  lines.push(
146
150
  "Shared MCP config: .mcp.json for this project/team or ~/.config/mcp/mcp.json for all projects.",
147
- "Pi-owned files hold compatibility imports and adapter-specific overrides.",
151
+ "mcp-adapter.json files hold compatibility imports and adapter-specific overrides; Pi's mcp.json files are reserved for Pi and ignored.",
148
152
  "",
149
153
  );
150
154
  }
151
155
 
152
156
  for (const name of Object.keys(state.config.mcpServers)) {
153
157
  const definition = state.config.mcpServers[name];
158
+ const block = state.blockedProjectServers?.get(name);
159
+ if (block) {
160
+ lines.push(`⊘ ${name}: ${describeProjectServerBlock(block.reason)}`);
161
+ continue;
162
+ }
154
163
  if (isServerDisabled(definition)) {
155
- lines.push(`⊘ ${name}: disabled (run /mcp enable ${name}, then /reload)`);
164
+ lines.push(`⊘ ${name}: disabled (run /mcp-adapter enable ${name}, then /reload)`);
156
165
  continue;
157
166
  }
158
167
  const connection = state.manager.getConnection(name);
@@ -198,7 +207,7 @@ export async function showStatus(state: McpExtensionState, ctx: ExtensionContext
198
207
 
199
208
  if (Object.keys(state.config.mcpServers).length === 0) {
200
209
  lines.push("No MCP servers configured");
201
- lines.push("Run /mcp setup to add a server to .mcp.json or ~/.config/mcp/mcp.json");
210
+ lines.push("Run /mcp-adapter setup to add a server to .mcp.json or ~/.config/mcp/mcp.json");
202
211
  }
203
212
 
204
213
  ctx.ui.notify(lines.join("\n"), "info");
@@ -280,7 +289,7 @@ export async function reconnectServer(
280
289
  return false;
281
290
  }
282
291
  if (isServerDisabled(definition)) {
283
- if (ui) ui.notify(`MCP: ${name} is disabled. Run /mcp enable ${name}, then /reload.`, "warning");
292
+ if (ui) ui.notify(`MCP: ${name} is disabled. Run /mcp-adapter enable ${name}, then /reload.`, "warning");
284
293
  return false;
285
294
  }
286
295
 
@@ -378,7 +387,7 @@ export async function authenticateServer(
378
387
  return { ok: false, message };
379
388
  }
380
389
  if (isServerDisabled(definition)) {
381
- const message = `Server "${serverName}" is disabled. Run /mcp enable ${serverName}, then /reload.`;
390
+ const message = `Server "${serverName}" is disabled. Run /mcp-adapter enable ${serverName}, then /reload.`;
382
391
  ui.notify(message, "warning");
383
392
  return { ok: false, message };
384
393
  }
@@ -492,7 +501,7 @@ function validateBearerTokenStoreServer(
492
501
  const safeName = sanitizeTerminalText(serverName);
493
502
  const definition = state.config.mcpServers[serverName];
494
503
  if (!definition) return { ok: false, message: `Server "${safeName}" not found in config`, type: "error" };
495
- if (isServerDisabled(definition)) return { ok: false, message: `Server "${safeName}" is disabled. Run /mcp enable ${safeName}, then /reload.`, type: "warning" };
504
+ if (isServerDisabled(definition)) return { ok: false, message: `Server "${safeName}" is disabled. Run /mcp-adapter enable ${safeName}, then /reload.`, type: "warning" };
496
505
  if (definition.auth !== "bearer" || definition.bearerTokenStore !== true) {
497
506
  return { ok: false, message: `Server "${safeName}" is not configured for bearerTokenStore.`, type: "error" };
498
507
  }
@@ -572,7 +581,7 @@ function buildSharedConfigNoticeLines(configOverridePath: string | undefined, cw
572
581
  return {
573
582
  lines: [
574
583
  `Using standard MCP config from ${sourceList}.`,
575
- "Use .mcp.json for project/team config or ~/.config/mcp/mcp.json for all projects. Pi only writes compatibility imports and adapter-specific overrides into Pi-owned files when needed.",
584
+ "Use .mcp.json for project/team config or ~/.config/mcp/mcp.json for all projects. The adapter writes compatibility imports and adapter-specific overrides into mcp-adapter.json files when needed.",
576
585
  ],
577
586
  fingerprint: discovery.fingerprint,
578
587
  };
@@ -588,7 +597,7 @@ export async function openMcpSetup(
588
597
  ): Promise<PanelFlowResult> {
589
598
  if (!ctx.hasUI) return { configChanged: false };
590
599
  if (!canRenderPanel(ctx)) {
591
- ctx.ui.notify(`The interactive MCP setup panel is only available in the terminal UI (current mode: ${ctx.mode}). Edit .mcp.json directly, or run /mcp status to review servers.`, "info");
600
+ ctx.ui.notify(`The interactive MCP setup panel is only available in the terminal UI (current mode: ${ctx.mode}). Edit .mcp.json directly, or run /mcp-adapter status to review servers.`, "info");
592
601
  return { configChanged: false };
593
602
  }
594
603
  if (state.programmaticConfig) {
@@ -685,6 +694,7 @@ function buildMcpPanelCallbacks(
685
694
  getConnectionStatus: (serverName: string) => {
686
695
  authStatusFailures.delete(serverName);
687
696
  const definition = config.mcpServers[serverName];
697
+ if (state.blockedProjectServers?.has(serverName)) return "blocked";
688
698
  if (isServerDisabled(definition)) return "disabled";
689
699
  const connection = state.manager.getConnection(serverName);
690
700
  let serverUrl: string | undefined;
@@ -713,7 +723,8 @@ function buildMcpPanelCallbacks(
713
723
  if (getFailureAgeSeconds(state, serverName) !== null) return "failed";
714
724
  return "idle";
715
725
  },
716
- getFailureMessage: (serverName: string) => authStatusFailures.get(serverName) ?? getFailureMessage(state, serverName),
726
+ getFailureMessage: (serverName: string) => state.blockedProjectServers?.get(serverName)?.reason
727
+ ?? authStatusFailures.get(serverName) ?? getFailureMessage(state, serverName),
717
728
  refreshCacheAfterReconnect: (serverName: string) => {
718
729
  const freshCache = loadMetadataCache();
719
730
  return freshCache?.servers?.[serverName] ?? null;