[PR #7283] feat(setup): discover project-scoped MCP registrations in doctor and … #7806

Open
opened 2026-11-05 01:47:47 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/7283
Author: @HarsH-1877
Created: 10/26/2026
Status: 🔄 Open

Base: main ← Head: feat/project-scoped-mcp-registrations-7181


📝 Commits (10+)

  • 8963d97 feat(setup): discover project-scoped MCP registrations in doctor and uninstall
  • cb749c5 fix(setup): preserve OpenCode layer fields, user launcher provenance, and user fallback
  • de478af fix(setup): restore working directory in tests and refine replacement and launcher provenance
  • d5033e5 fix(setup): bound OpenCode discovery to worktree and enforce Pi project trust
  • 4c9a8ea fix(setup): preserve Pi project trust failures in doctor and prevent skipping project registrations in uninstall
  • e43ff7f fix(setup): defer cross-setting environment validation and decouple OpenCode launcher ownership
  • c29b8a3 fix(setup): separate OpenCode readiness schema from launcher ownership and fix cross-setting test
  • 1a6c4a5 fix(doctor): include project remediation when disabled project registration inherits outdated user launcher
  • bf6c505 fix(setup): scope status properties to project-scoped registrations
  • a0518c7 fix(setup): prevent activating unowned launchers during uninstall and align array normalization

📊 Changes

18 files changed (+3125 additions, -155 deletions)

View changed files

📝 docs/client-configuration.md (+17 -7)
📝 src/application/ClientConfigurationFiles.ts (+479 -28)
📝 src/application/ClientRegistration.ts (+27 -7)
📝 src/application/ClientRegistrationStatus.ts (+113 -17)
📝 src/application/Doctor.test.ts (+40 -0)
📝 src/application/Doctor.ts (+3 -0)
📝 src/application/DoctorScope.ts (+4 -0)
📝 src/application/SetupPlan.ts (+2 -0)
📝 src/application/SupportedClients.ts (+145 -21)
📝 src/application/Uninstall.ts (+191 -64)
📝 src/application/UpdateMaintenance.ts (+2 -0)
📝 src/setupEnvironment.test.ts (+5 -5)
📝 tests/boundary/android/androidJniLibraries.test.ts (+1 -1)
📝 tests/boundary/filesystem/claudeDesktopClientConfiguration.test.ts (+21 -0)
📝 tests/boundary/filesystem/clientConfigurationDialects.test.ts (+1127 -2)
📝 tests/boundary/filesystem/piClientConfiguration.test.ts (+903 -2)
📝 tests/boundary/filesystem/setupLauncherAlias.test.ts (+1 -1)
📝 tests/process-global/updateMaintenance.test.ts (+44 -0)

📄 Description

Summary

Fixes #7181

Discovers project-scoped MCP client registrations for Pi (<cwd>/.pi/mcp.json) and OpenCode (opencode.json, opencode.jsonc, .opencode/opencode.json, .opencode/opencode.jsonc from outermost ancestor down to process.cwd()) in rea doctor and rea uninstall.

Previously, rea doctor inspected only user-level configuration files. When a project configuration shadowed or overrode a user registration (or stood alone), doctor reported user-level state or marked REA missing, and provided remediation advising rea setup (which only writes user-level configs). Furthermore, rea uninstall only cleaned user-level configuration, leaving REA entries in project files. This change discovers project-scoped configurations according to each client's native precedence, preserves inherited layer fields and launcher provenance, reports scope: "project" in doctor diagnostics, provides project-file-specific remediation without suggesting user-level setup (while preserving user setup advice when the launcher originates from user config or when project files omit REA), and removes REA-owned project registrations during rea uninstall with backup and readback verification.

Problem and expected behavior

  1. Pi Precedence & Partial Overrides: Pi loads .pi/mcp.json in the current working directory. A project server entry replaces the user entry if it defines a launcher or command, or partially overrides the user entry when specifying only flags such as enabled or exposure. rea doctor evaluates these semantics in process.cwd(), reports scope: "project", preserves user launcher provenance (launcher_scope: "user") when the command comes from user config, and points remediation to the project file when disabled or invalid while preserving user setup guidance for version drift on inherited user launchers.
  2. OpenCode Ancestor Precedence & Field Inheritance: OpenCode loads project configuration files from ancestor directories down to process.cwd(). All configuration layers from user down to process.cwd() are deep-merged in file precedence order, preserving inherited type, command, and environment variables across partial project overrides.
  3. Missing Registration Fallback: When project files exist but do not define rea (only sibling servers), doctor falls back to user scope and correctly advises running rea setup rather than advising edits to a non-existent project entry.
  4. Update Maintenance & Setup Plan: rea update inspects user-scoped registrations so active user launchers written by REA are refreshed even when invoked inside a project directory with project overrides. Bare rea setup includes clients whose active launcher originates from user scope in defaultClientIds.
  5. Uninstall Cleanup: rea uninstall inspects discovered project files for REA-owned server entries and removes them with .rea.backup and readback verification, while retaining non-owned entries and manual partial overrides.
  6. Scope Isolation: Bare rea setup and rea update continue writing exclusively to user-level configuration files and do not mutate project-scoped files.

Change and scope

  • Extended SetupClient and ClientDefinitionBase with projectConfigPaths.
  • Implemented directoryHierarchyFromRoot and openCodeProjectConfigurationPaths for ancestor-down-to-cwd resolution of OpenCode candidate files (opencode.json, opencode.jsonc, .opencode/opencode.json, .opencode/opencode.jsonc), bounded to Git worktree root.
  • Implemented piProjectConfigurationPaths resolving <cwd>/.pi/mcp.json.
  • Updated readEffectiveClientRegistrationConfiguration in ClientConfigurationFiles.ts to layer user and project sources through effectiveClientConfiguration, deferring cross-setting environment validation until layers are merged, and tracking launcherScope and launcherConfigPath.
  • Decoupled OpenCode command ownership checks (opencodeOwnershipLauncherSchema) from strict readiness checks (opencodeStrictLauncherSchema) in ClientRegistration.ts.
  • In ClientRegistrationStatus.ts, added scope?: "user" | "all" to ClientRegistrationReadOptions, added launcher_scope to ClientRegistrationStatus, and updated packageVersionRemediation to guide user setup when launcherScope === "user".
  • In UpdateMaintenance.ts, instructed maintenance scope discovery to inspect user-level registrations (scope: "user").
  • In SetupPlan.ts, included clients with launcher_scope === "user" in defaultClientIds.
  • Documented project-scoped discovery and uninstall semantics in docs/client-configuration.md.

Scope decision: Ordinary configuration discovery and maintenance within existing client boundaries. Preserves caller choices and ownership invariants without modifying unowned registrations or installing unrequested tools.

Targets and side effects

  • Read local files or metadata; do not write files or touch state.
  • Inspect existing targets or environments without modifying them.
  • Read or write existing files or captured data.
  • Launch or attach to a process.
  • Inject instrumentation or run scripts/code.
  • Change process memory, registers, files, or configuration.
  • Contact network services.
  • Recover protected code or work around protections.
  • Documentation or usability only; no target interaction.
  • Not sure yet; investigation or maintainer guidance needed.

Evidence and regression coverage

  • Tests added or updated:
    • tests/boundary/filesystem/piClientConfiguration.test.ts:
      • Pi project-scoped discovery and overrides: Tests project discovery, full replacement over user config, partial override over user config with project remediation, and standalone partial override error reporting.
      • Pi project-scoped launcher provenance and fallback: Tests that a flags-only project override over a stale user registration preserves launcher_scope: "user" and directs remediation to rea setup --client pi, and that a project with only sibling servers falls back to user-scoped missing status.
      • Pi project-scoped uninstall: Tests uninstall removal with .rea.backup and retention of non-owned entries/partial overrides.
    • tests/boundary/filesystem/clientConfigurationDialects.test.ts:
      • OpenCode project-scoped discovery: Tests project registration discovery and precedence over user registration.
      • OpenCode project-scoped precedence and drift: Tests ancestor hierarchy precedence (inner cwd over outer ancestor), and project-specific remediation for stale package versions and disabled: true.
      • OpenCode cross-setting environment merge and launcher uninstall: Tests cross-setting environment merge across layers and verifies that incomplete standalone entries missing type: "local" are reported invalid by doctor but removed by uninstall based on command ownership.
      • OpenCode project-scoped inheritance and fallback: Tests preservation of inherited type and command when a project layer specifies only { disabled: true }, and verifies fallback to user-scoped missing status when project files only contain sibling servers.
      • OpenCode project-scoped uninstall: Tests removal with backup and preservation of JSONC comments and sibling servers.
    • tests/process-global/updateMaintenance.test.ts:
      • Tests that existingMaintenanceScope selects owned user registrations for maintenance even when executed inside a project directory with project overrides.
    • src/application/Doctor.test.ts:
      • Tests scope: "project" reporting in identity.registrations and scope_checks check details.
  • User-visible CLI/MCP output:
    rea doctor displays registration:opencode / registration:pi with details: { scope: "project" } and file path pointing to the project config.

Validation performed

  • npm run check:fast — 0 errors (typecheck and lint clean)
  • npm run docs:check — 0 errors (all doc facts, metadata, licenses, and consistency tests passed)
  • npx vitest run tests/boundary/filesystem/piClientConfiguration.test.ts: 55 passed (100%)
  • npx vitest run tests/boundary/filesystem/clientConfigurationDialects.test.ts: 15 project-scoped tests passed (100%)
  • npx vitest run src/application/Doctor.test.ts src/application/ClientRegistration.test.ts src/application/Setup.planning.test.ts src/application/Setup.configuration.test.ts: 151 passed (100%)
  • Greptile Review: Confidence score 5/5, 0 findings.

Author readiness

Human owner: @HarsH-1877

  • I reviewed the final diff and relevant existing code, understand the change and its edge cases, and take responsibility for the complete PR, including AI-assisted work.
  • I checked the evidence above, confirmed it supports the current change, and recorded meaningful validation gaps.
  • I declare this PR ready for initial maintainer review.

Before merge

  • This PR addresses a concrete problem or an agreed enhancement.
  • Material scope and authority questions are resolved, and any required maintainer scope decision covers the final diff.
  • The PR has one focused outcome and the title follows type(scope): outcome.
  • Related issue is linked, or the reason for not linking one is stated above.
  • Tests cover changed observable behavior and meaningful failure paths.
  • Owning docs, contracts, and generated metadata are updated where needed.
  • User-visible CLI/MCP changes include representative output.
  • I checked the final diff for secrets, unrelated cleanup, and unsupported claims.

🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/morluto/rea/pull/7283 **Author:** [@HarsH-1877](https://github.com/HarsH-1877) **Created:** 10/26/2026 **Status:** 🔄 Open **Base:** `main` ← **Head:** `feat/project-scoped-mcp-registrations-7181` --- ### 📝 Commits (10+) - [`8963d97`](https://github.com/morluto/rea/commit/8963d97b91ff7d145fcc8a90753025f7a6ad8938) feat(setup): discover project-scoped MCP registrations in doctor and uninstall - [`cb749c5`](https://github.com/morluto/rea/commit/cb749c548270ee38a7d1b481ade7444109ca29db) fix(setup): preserve OpenCode layer fields, user launcher provenance, and user fallback - [`de478af`](https://github.com/morluto/rea/commit/de478afd46f79f348436185b65100b2ea123c15f) fix(setup): restore working directory in tests and refine replacement and launcher provenance - [`d5033e5`](https://github.com/morluto/rea/commit/d5033e557f229b48dac78da59dc6a91e0e35299c) fix(setup): bound OpenCode discovery to worktree and enforce Pi project trust - [`4c9a8ea`](https://github.com/morluto/rea/commit/4c9a8ead613c5c4bba03149f575aeebb423fd9db) fix(setup): preserve Pi project trust failures in doctor and prevent skipping project registrations in uninstall - [`e43ff7f`](https://github.com/morluto/rea/commit/e43ff7fb78eaaa5a5084b99adec80c10d2824ad0) fix(setup): defer cross-setting environment validation and decouple OpenCode launcher ownership - [`c29b8a3`](https://github.com/morluto/rea/commit/c29b8a3f088240d08d15fcda97d356a06d128834) fix(setup): separate OpenCode readiness schema from launcher ownership and fix cross-setting test - [`1a6c4a5`](https://github.com/morluto/rea/commit/1a6c4a58e6844b0564a12cde4129ab3284ddb0a0) fix(doctor): include project remediation when disabled project registration inherits outdated user launcher - [`bf6c505`](https://github.com/morluto/rea/commit/bf6c5055a168462d08555e6bcd14714bb0e26e56) fix(setup): scope status properties to project-scoped registrations - [`a0518c7`](https://github.com/morluto/rea/commit/a0518c7446f9f111f2186d2f27d280e070af15d6) fix(setup): prevent activating unowned launchers during uninstall and align array normalization ### 📊 Changes **18 files changed** (+3125 additions, -155 deletions) <details> <summary>View changed files</summary> 📝 `docs/client-configuration.md` (+17 -7) 📝 `src/application/ClientConfigurationFiles.ts` (+479 -28) 📝 `src/application/ClientRegistration.ts` (+27 -7) 📝 `src/application/ClientRegistrationStatus.ts` (+113 -17) 📝 `src/application/Doctor.test.ts` (+40 -0) 📝 `src/application/Doctor.ts` (+3 -0) 📝 `src/application/DoctorScope.ts` (+4 -0) 📝 `src/application/SetupPlan.ts` (+2 -0) 📝 `src/application/SupportedClients.ts` (+145 -21) 📝 `src/application/Uninstall.ts` (+191 -64) 📝 `src/application/UpdateMaintenance.ts` (+2 -0) 📝 `src/setupEnvironment.test.ts` (+5 -5) 📝 `tests/boundary/android/androidJniLibraries.test.ts` (+1 -1) 📝 `tests/boundary/filesystem/claudeDesktopClientConfiguration.test.ts` (+21 -0) 📝 `tests/boundary/filesystem/clientConfigurationDialects.test.ts` (+1127 -2) 📝 `tests/boundary/filesystem/piClientConfiguration.test.ts` (+903 -2) 📝 `tests/boundary/filesystem/setupLauncherAlias.test.ts` (+1 -1) 📝 `tests/process-global/updateMaintenance.test.ts` (+44 -0) </details> ### 📄 Description ## Summary Fixes #7181 Discovers project-scoped MCP client registrations for Pi (`<cwd>/.pi/mcp.json`) and OpenCode (`opencode.json`, `opencode.jsonc`, `.opencode/opencode.json`, `.opencode/opencode.jsonc` from outermost ancestor down to `process.cwd()`) in `rea doctor` and `rea uninstall`. Previously, `rea doctor` inspected only user-level configuration files. When a project configuration shadowed or overrode a user registration (or stood alone), `doctor` reported user-level state or marked REA missing, and provided remediation advising `rea setup` (which only writes user-level configs). Furthermore, `rea uninstall` only cleaned user-level configuration, leaving REA entries in project files. This change discovers project-scoped configurations according to each client's native precedence, preserves inherited layer fields and launcher provenance, reports `scope: "project"` in doctor diagnostics, provides project-file-specific remediation without suggesting user-level setup (while preserving user setup advice when the launcher originates from user config or when project files omit REA), and removes REA-owned project registrations during `rea uninstall` with backup and readback verification. ## Problem and expected behavior 1. **Pi Precedence & Partial Overrides**: Pi loads `.pi/mcp.json` in the current working directory. A project server entry replaces the user entry if it defines a launcher or command, or partially overrides the user entry when specifying only flags such as `enabled` or `exposure`. `rea doctor` evaluates these semantics in `process.cwd()`, reports `scope: "project"`, preserves user launcher provenance (`launcher_scope: "user"`) when the command comes from user config, and points remediation to the project file when disabled or invalid while preserving user setup guidance for version drift on inherited user launchers. 2. **OpenCode Ancestor Precedence & Field Inheritance**: OpenCode loads project configuration files from ancestor directories down to `process.cwd()`. All configuration layers from user down to `process.cwd()` are deep-merged in file precedence order, preserving inherited `type`, `command`, and environment variables across partial project overrides. 3. **Missing Registration Fallback**: When project files exist but do not define `rea` (only sibling servers), doctor falls back to user scope and correctly advises running `rea setup` rather than advising edits to a non-existent project entry. 4. **Update Maintenance & Setup Plan**: `rea update` inspects user-scoped registrations so active user launchers written by REA are refreshed even when invoked inside a project directory with project overrides. Bare `rea setup` includes clients whose active launcher originates from user scope in `defaultClientIds`. 5. **Uninstall Cleanup**: `rea uninstall` inspects discovered project files for REA-owned server entries and removes them with `.rea.backup` and readback verification, while retaining non-owned entries and manual partial overrides. 6. **Scope Isolation**: Bare `rea setup` and `rea update` continue writing exclusively to user-level configuration files and do not mutate project-scoped files. ## Change and scope - Extended `SetupClient` and `ClientDefinitionBase` with `projectConfigPaths`. - Implemented `directoryHierarchyFromRoot` and `openCodeProjectConfigurationPaths` for ancestor-down-to-cwd resolution of OpenCode candidate files (`opencode.json`, `opencode.jsonc`, `.opencode/opencode.json`, `.opencode/opencode.jsonc`), bounded to Git worktree root. - Implemented `piProjectConfigurationPaths` resolving `<cwd>/.pi/mcp.json`. - Updated `readEffectiveClientRegistrationConfiguration` in `ClientConfigurationFiles.ts` to layer user and project sources through `effectiveClientConfiguration`, deferring cross-setting environment validation until layers are merged, and tracking `launcherScope` and `launcherConfigPath`. - Decoupled OpenCode command ownership checks (`opencodeOwnershipLauncherSchema`) from strict readiness checks (`opencodeStrictLauncherSchema`) in `ClientRegistration.ts`. - In `ClientRegistrationStatus.ts`, added `scope?: "user" | "all"` to `ClientRegistrationReadOptions`, added `launcher_scope` to `ClientRegistrationStatus`, and updated `packageVersionRemediation` to guide user setup when `launcherScope === "user"`. - In `UpdateMaintenance.ts`, instructed maintenance scope discovery to inspect user-level registrations (`scope: "user"`). - In `SetupPlan.ts`, included clients with `launcher_scope === "user"` in `defaultClientIds`. - Documented project-scoped discovery and uninstall semantics in `docs/client-configuration.md`. Scope decision: Ordinary configuration discovery and maintenance within existing client boundaries. Preserves caller choices and ownership invariants without modifying unowned registrations or installing unrequested tools. ## Targets and side effects - [x] Read local files or metadata; do not write files or touch state. - [ ] Inspect existing targets or environments without modifying them. - [ ] Read or write existing files or captured data. - [ ] Launch or attach to a process. - [ ] Inject instrumentation or run scripts/code. - [x] Change process memory, registers, files, or configuration. - [ ] Contact network services. - [ ] Recover protected code or work around protections. - [ ] Documentation or usability only; no target interaction. - [ ] Not sure yet; investigation or maintainer guidance needed. ## Evidence and regression coverage - Tests added or updated: - `tests/boundary/filesystem/piClientConfiguration.test.ts`: - `Pi project-scoped discovery and overrides`: Tests project discovery, full replacement over user config, partial override over user config with project remediation, and standalone partial override error reporting. - `Pi project-scoped launcher provenance and fallback`: Tests that a flags-only project override over a stale user registration preserves `launcher_scope: "user"` and directs remediation to `rea setup --client pi`, and that a project with only sibling servers falls back to user-scoped missing status. - `Pi project-scoped uninstall`: Tests uninstall removal with `.rea.backup` and retention of non-owned entries/partial overrides. - `tests/boundary/filesystem/clientConfigurationDialects.test.ts`: - `OpenCode project-scoped discovery`: Tests project registration discovery and precedence over user registration. - `OpenCode project-scoped precedence and drift`: Tests ancestor hierarchy precedence (inner cwd over outer ancestor), and project-specific remediation for stale package versions and `disabled: true`. - `OpenCode cross-setting environment merge and launcher uninstall`: Tests cross-setting environment merge across layers and verifies that incomplete standalone entries missing `type: "local"` are reported invalid by doctor but removed by uninstall based on command ownership. - `OpenCode project-scoped inheritance and fallback`: Tests preservation of inherited `type` and `command` when a project layer specifies only `{ disabled: true }`, and verifies fallback to user-scoped missing status when project files only contain sibling servers. - `OpenCode project-scoped uninstall`: Tests removal with backup and preservation of JSONC comments and sibling servers. - `tests/process-global/updateMaintenance.test.ts`: - Tests that `existingMaintenanceScope` selects owned user registrations for maintenance even when executed inside a project directory with project overrides. - `src/application/Doctor.test.ts`: - Tests `scope: "project"` reporting in `identity.registrations` and `scope_checks` check details. - User-visible CLI/MCP output: `rea doctor` displays `registration:opencode` / `registration:pi` with `details: { scope: "project" }` and file path pointing to the project config. ## Validation performed - `npm run check:fast` — 0 errors (typecheck and lint clean) - `npm run docs:check` — 0 errors (all doc facts, metadata, licenses, and consistency tests passed) - `npx vitest run tests/boundary/filesystem/piClientConfiguration.test.ts`: 55 passed (100%) - `npx vitest run tests/boundary/filesystem/clientConfigurationDialects.test.ts`: 15 project-scoped tests passed (100%) - `npx vitest run src/application/Doctor.test.ts src/application/ClientRegistration.test.ts src/application/Setup.planning.test.ts src/application/Setup.configuration.test.ts`: 151 passed (100%) - Greptile Review: Confidence score **5/5**, 0 findings. ## Author readiness Human owner: @HarsH-1877 - [x] I reviewed the final diff and relevant existing code, understand the change and its edge cases, and take responsibility for the complete PR, including AI-assisted work. - [x] I checked the evidence above, confirmed it supports the current change, and recorded meaningful validation gaps. - [x] I declare this PR ready for initial maintainer review. ## Before merge - [x] This PR addresses a concrete problem or an agreed enhancement. - [x] Material scope and authority questions are resolved, and any required maintainer scope decision covers the final diff. - [x] The PR has one focused outcome and the title follows `type(scope): outcome`. - [x] Related issue is linked, or the reason for not linking one is stated above. - [x] Tests cover changed observable behavior and meaningful failure paths. - [x] Owning docs, contracts, and generated metadata are updated where needed. - [x] User-visible CLI/MCP changes include representative output. - [x] I checked the final diff for secrets, unrelated cleanup, and unsupported claims. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
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#7806
No description provided.