[GH-ISSUE #7181] [Feature] Discover project-scoped MCP registrations in doctor and uninstall (pi, OpenCode) #4294

Open
opened 2026-10-31 00:48:37 +00:00 by bsakaguchi · 2 comments
Owner

Originally created by @jonidimo on GitHub (Oct 26, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/7181

Before submitting

  • I searched the open and closed issues and pull requests for a related proposal. Verified: #2187 (open), #2188 (closed, docs), #3246 (open).
  • I understand the contribution scope must be reviewed before integration; open questions are welcome here.
  • This request does not include credentials, private samples, or sensitive target data.

Area: MCP or agent integration. Expected interaction: reads configuration files; does not write them (primary proposal).

Current limitation

pi and OpenCode both define a project-level MCP file and give it precedence over the user-level one. REA reads only the user-level file, so a deliberate project-scoped registration is invisible to rea doctor and rea uninstall: doctor reports drift forever and its remediation writes the global registration the user was avoiding.

Observed on 6.8.0, Linux, Node 24, with REA registered by hand in pi's project file:

$ pi mcp list
rea: connected, 229 tools (codemode, project)

$ rea doctor --client pi
## healthy
false
## scope.clients
["pi"]
## scope_checks
| registration:pi | false | config_drift | /home/jon/.pi/agent/mcp.json | ... |
   remediation: Run rea setup to refresh this registration, then restart the client.

The registration works. The check reads ~/.pi/agent/mcp.json, finds no rea entry (state missing), and renders every non-unknown unhealthy state as config_drift (src/application/DoctorScope.ts:198). Running the printed remediation adds a user-level entry, which is precisely the outcome project scope avoids.

Vendor-documented project locations and precedence:

  • pi reads ~/.pi/agent/mcp.json and .pi/mcp.json; the project file is read after project trust. "A project entry replaces a user-level entry with the same name." Separately, "a project entry without command, url, or type overrides only enabled, exposure, and toolExposure of the user-level server with the same name and keeps the rest, including env, headers, and auth." (https://pi.dev/docs/latest/mcp, section "Configure servers".)
  • OpenCode V2 projects configure mcp.servers.<name> in opencode.json or .opencode/opencode.json; "OpenCode searches from the current directory to the filesystem root" and "a higher-precedence project config replaces the entire server object with the same name" (https://opencode.ai/v2/docs/config, https://opencode.ai/v2/docs/mcp-servers).

Why REA misses both:

  • src/application/SupportedClients.ts:657 declares pi with a single configPath resolving to piAgentDirectory(context)/mcp.json.
  • src/application/SupportedClients.ts:569 gives OpenCode configPaths: openCodeConfigurationPaths, defined at :399 as $XDG_CONFIG_HOME/opencode/{config.json,opencode.json,opencode.jsonc}, $OPENCODE_CONFIG, and the override directory. All user-level.
  • There is no configuration-only workaround. Alignment requires activation === "enabled" (src/application/ClientRegistrationStatus.ts:328), so a disabled user-level stub plus an enabled project entry reports stale, not aligned. rea setup has no scope option (--scope is an unknown flag).

Impact: an explicitly selected, working registration makes --client readiness fail closed, and rea uninstall cannot see or remove the entry either.

Use cases

  • Repository-scoped analysis. Keep REA available in one checkout and out of every unrelated project on the same workstation. This is the primary motivation; Code Mode already keeps the catalog out of the prompt.
  • Bounded tool budgets. When a client declares tools directly, catalog size matters. Measured on 6.8.0 with the compact profile: 229 tools, 281 KiB for name, title, description and input schema (tools/list, JSON bytes). The full JSON is 3.4 MB because 91% is outputSchema, which is not only transport: OpenCode 2.1.4 renders it as typed return signatures in its Code Mode catalog (observed: close_frida_session(...): Promise<{ target_state: "unknown" }>). REA_MCP_OUTPUT_SCHEMA_PROFILE=off (#2512) remains the lever for hosts that reject the frame, not a prompt-size optimization. Tool-family scoping is tracked in #3246.
  • Local-only wiring. A project file next to the checkout keeps machine-specific absolute paths out of global configuration.

Desired outcome and success criteria

Primary proposal, minimal and read-only:

  • rea doctor discovers a project-scoped registration for the current directory, reports which scope it found, and classifies an aligned project entry as healthy.
  • When a project entry shadows the user entry, doctor reports the effective registration, not a missing user entry.
  • rea uninstall removes REA-owned project entries with the same backup, readback and restore steps it uses today; it must not touch entries REA does not own.
  • The remediation text no longer says "run rea setup" when setup cannot produce the effective registration.

Secondary, only if maintainers accept writing project files:

  • rea setup --client pi --scope project (plus --project DIR) writes the vendor file and shows the exact path in the plan. Default stays user-level.

Target and scope details

Non-goals: committing configuration into repositories, changing the default scope, and touching clients without a vendor-defined project file. Related but distinct: #2187 (Claude Code --scope local, storage inside ~/.claude.json), #2188 (documentation route), #3246 (scoping advertised tools by family). Open questions worth deciding first: for pi, whether an aligned check must require a complete project entry or may merge a partial override with the user entry; and whether --project DIR should affect the trust requirement pi documents.

Verification available so far

Observed: the commands and outputs above, pi mcp list and opencode mcp list showing project-scoped connections, the source references, and the catalog measurement (229 tools; 3423 KiB total; outputSchema 3124 KiB, description 132 KiB, inputSchema 119 KiB, name/title/annotations 30 KiB). Not verified: Windows path resolution for both clients, and whether a project entry alone satisfies each client's trust gate in every configuration.

Originally created by @jonidimo on GitHub (Oct 26, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/7181 ## Before submitting - [x] I searched the open and closed issues and pull requests for a related proposal. Verified: #2187 (open), #2188 (closed, docs), #3246 (open). - [x] I understand the contribution scope must be reviewed before integration; open questions are welcome here. - [x] This request does not include credentials, private samples, or sensitive target data. Area: MCP or agent integration. Expected interaction: reads configuration files; does not write them (primary proposal). ## Current limitation pi and OpenCode both define a project-level MCP file and give it precedence over the user-level one. REA reads only the user-level file, so a deliberate project-scoped registration is invisible to `rea doctor` and `rea uninstall`: doctor reports drift forever and its remediation writes the global registration the user was avoiding. Observed on 6.8.0, Linux, Node 24, with REA registered by hand in pi's project file: ``` $ pi mcp list rea: connected, 229 tools (codemode, project) $ rea doctor --client pi ## healthy false ## scope.clients ["pi"] ## scope_checks | registration:pi | false | config_drift | /home/jon/.pi/agent/mcp.json | ... | remediation: Run rea setup to refresh this registration, then restart the client. ``` The registration works. The check reads `~/.pi/agent/mcp.json`, finds no `rea` entry (state `missing`), and renders every non-unknown unhealthy state as `config_drift` (`src/application/DoctorScope.ts:198`). Running the printed remediation adds a user-level entry, which is precisely the outcome project scope avoids. Vendor-documented project locations and precedence: - pi reads `~/.pi/agent/mcp.json` and `.pi/mcp.json`; the project file is read after project trust. "A project entry replaces a user-level entry with the same name." Separately, "a project entry without `command`, `url`, or `type` overrides only `enabled`, `exposure`, and `toolExposure` of the user-level server with the same name and keeps the rest, including `env`, `headers`, and `auth`." (<https://pi.dev/docs/latest/mcp>, section "Configure servers".) - OpenCode V2 projects configure `mcp.servers.<name>` in `opencode.json` or `.opencode/opencode.json`; "OpenCode searches from the current directory to the filesystem root" and "a higher-precedence project config replaces the entire server object with the same name" (<https://opencode.ai/v2/docs/config>, <https://opencode.ai/v2/docs/mcp-servers>). Why REA misses both: - `src/application/SupportedClients.ts:657` declares pi with a single `configPath` resolving to `piAgentDirectory(context)/mcp.json`. - `src/application/SupportedClients.ts:569` gives OpenCode `configPaths: openCodeConfigurationPaths`, defined at `:399` as `$XDG_CONFIG_HOME/opencode/{config.json,opencode.json,opencode.jsonc}`, `$OPENCODE_CONFIG`, and the override directory. All user-level. - There is no configuration-only workaround. Alignment requires `activation === "enabled"` (`src/application/ClientRegistrationStatus.ts:328`), so a disabled user-level stub plus an enabled project entry reports `stale`, not aligned. `rea setup` has no scope option (`--scope` is an unknown flag). Impact: an explicitly selected, working registration makes `--client` readiness fail closed, and `rea uninstall` cannot see or remove the entry either. ## Use cases - **Repository-scoped analysis.** Keep REA available in one checkout and out of every unrelated project on the same workstation. This is the primary motivation; Code Mode already keeps the catalog out of the prompt. - **Bounded tool budgets.** When a client declares tools directly, catalog size matters. Measured on 6.8.0 with the compact profile: 229 tools, 281 KiB for name, title, description and input schema (`tools/list`, JSON bytes). The full JSON is 3.4 MB because 91% is `outputSchema`, which is not only transport: OpenCode 2.1.4 renders it as typed return signatures in its Code Mode catalog (observed: `close_frida_session(...): Promise<{ target_state: "unknown" }>`). `REA_MCP_OUTPUT_SCHEMA_PROFILE=off` (#2512) remains the lever for hosts that reject the frame, not a prompt-size optimization. Tool-family scoping is tracked in #3246. - **Local-only wiring.** A project file next to the checkout keeps machine-specific absolute paths out of global configuration. ## Desired outcome and success criteria Primary proposal, minimal and read-only: - `rea doctor` discovers a project-scoped registration for the current directory, reports which scope it found, and classifies an aligned project entry as healthy. - When a project entry shadows the user entry, doctor reports the effective registration, not a `missing` user entry. - `rea uninstall` removes REA-owned project entries with the same backup, readback and restore steps it uses today; it must not touch entries REA does not own. - The remediation text no longer says "run rea setup" when setup cannot produce the effective registration. Secondary, only if maintainers accept writing project files: - `rea setup --client pi --scope project` (plus `--project DIR`) writes the vendor file and shows the exact path in the plan. Default stays user-level. ## Target and scope details Non-goals: committing configuration into repositories, changing the default scope, and touching clients without a vendor-defined project file. Related but distinct: #2187 (Claude Code `--scope local`, storage inside `~/.claude.json`), #2188 (documentation route), #3246 (scoping advertised tools by family). Open questions worth deciding first: for pi, whether an aligned check must require a complete project entry or may merge a partial override with the user entry; and whether `--project DIR` should affect the trust requirement pi documents. ## Verification available so far Observed: the commands and outputs above, `pi mcp list` and `opencode mcp list` showing project-scoped connections, the source references, and the catalog measurement (229 tools; 3423 KiB total; `outputSchema` 3124 KiB, `description` 132 KiB, `inputSchema` 119 KiB, name/title/annotations 30 KiB). Not verified: Windows path resolution for both clients, and whether a project entry alone satisfies each client's trust gate in every configuration.
Author
Owner

@DevyanshMalhotra commented on GitHub (Oct 26, 2026):

Hi @jonidimo, I’d like to work on this if it’s still available.

I went through the proposed scope and I’d start with the primary read-only path rather than the optional project-writing support: make project-scoped pi/OpenCode registrations discoverable to doctor, resolve them according to the clients’ documented precedence, and ensure the effective registration is reported instead of treating a missing user-level entry as drift.

I’d first trace the existing client registration discovery/status flow in SupportedClients, ClientRegistrationStatus, and DoctorScope, then add focused fixtures for user-only, project-only, and project-over-user precedence before changing the implementation.

For pi, I’d also keep the complete-entry vs partial project override behavior explicit rather than assuming merge semantics, since the issue calls that out as an open design decision.

If that initial scope matches the direction you want, I’d be happy to take it.

<!-- gh-comment-id:6405892594 --> @DevyanshMalhotra commented on GitHub (Oct 26, 2026): Hi @jonidimo, I’d like to work on this if it’s still available. I went through the proposed scope and I’d start with the primary read-only path rather than the optional project-writing support: make project-scoped pi/OpenCode registrations discoverable to `doctor`, resolve them according to the clients’ documented precedence, and ensure the effective registration is reported instead of treating a missing user-level entry as drift. I’d first trace the existing client registration discovery/status flow in `SupportedClients`, `ClientRegistrationStatus`, and `DoctorScope`, then add focused fixtures for user-only, project-only, and project-over-user precedence before changing the implementation. For pi, I’d also keep the complete-entry vs partial project override behavior explicit rather than assuming merge semantics, since the issue calls that out as an open design decision. If that initial scope matches the direction you want, I’d be happy to take it.
Author
Owner

@XinwangTao commented on GitHub (Oct 26, 2026):

支持 primary read-only 方案,特别是"报告 effective registration 而不是把项目级条目当成 drift"这一点,能让 doctor 的语义和用户意图对齐。针对 open question 里的 partial override 合并问题提一个建议:pi 文档定义了字段级合并(project entry 只覆盖 enabled/exposure/toolExposure,保留 env/headers/auth),所以 doctor 的 aligned 判定应当基于"effective merged registration"计算,而不是要求项目文件里有完整 server 对象——否则 partial override 会被误报为 drift,反而逼用户写成完整条目。实现上可以先在 doctor 输出里加一列 scope(user/project/merged)便于调试。uninstall 侧"只移除 REA-owned 条目"的约束也请保留,项目文件里可能还有其他工具的同名 server 配置。

<!-- gh-comment-id:6411290989 --> @XinwangTao commented on GitHub (Oct 26, 2026): 支持 primary read-only 方案,特别是"报告 effective registration 而不是把项目级条目当成 drift"这一点,能让 doctor 的语义和用户意图对齐。针对 open question 里的 partial override 合并问题提一个建议:pi 文档定义了字段级合并(project entry 只覆盖 enabled/exposure/toolExposure,保留 env/headers/auth),所以 doctor 的 aligned 判定应当基于"effective merged registration"计算,而不是要求项目文件里有完整 server 对象——否则 partial override 会被误报为 drift,反而逼用户写成完整条目。实现上可以先在 doctor 输出里加一列 scope(user/project/merged)便于调试。uninstall 侧"只移除 REA-owned 条目"的约束也请保留,项目文件里可能还有其他工具的同名 server 配置。
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#4294
No description provided.