refactor(mcp): move builtin server knowledge out of the MCP runtime - #18630
refactor(mcp): move builtin server knowledge out of the MCP runtime#18630DeJeune wants to merge 10 commits into
Conversation
`@cherry/flomo` and `@cherry/nowledge-mem` were stored as `inMemory` servers while actually talking to an HTTP endpoint, so the runtime had to special-case them by name. Declare the real connection in the preset catalog and migrate installed rows, matching legacy `@cherry/mcp-auto-install` rows to stdio too. The catalog moves to `@shared/data/presets` so the renderer and the seeder read one source. Only rows still stored as `inMemory` are rewritten: re-running is a no-op, user edits survive, and a builtin the user never installed stays absent. Signed-off-by: suyao <sy20010504@gmail.com>
…time
`getOrCreateClient` was 470 lines and 47 branches covering client reuse,
transport construction, package-manager resolution, OAuth and retry. Move
transport creation to `mcpTransport`, the npx/uvx/uv resolution to a runner
table in `mcpLaunch`, and the SDK loader plus transport policy to
`mcpClientSdk`; the service keeps caching, status and bookkeeping.
Also fixes the bun argument rewrite: `args.includes('x')` suppressed the
`x -y` prefix whenever a package argument happened to be `x` or `-y`, so
`bun -y pkg x` was launched instead of `bun x -y pkg x`.
Signed-off-by: suyao <sy20010504@gmail.com>
|
Code review complete. No high-confidence issues caused or made reachable by this PR were found. Verified areas:
CI, signatures, and merge readiness are outside the scope of this review. |
…ool-leak # Conflicts: # src/main/ai/mcp/McpRuntimeService.ts # src/main/ai/mcp/__tests__/McpRuntimeService.test.ts # src/main/ai/mcp/servers/factory.ts
…ool-leak # Conflicts: # src/main/ai/mcp/McpRuntimeService.ts # src/main/ai/mcp/__tests__/McpRuntimeService.test.ts # src/main/ai/mcp/servers/factory.ts # src/renderer/pages/settings/McpSettings/BuiltinMcpServerList.tsx # src/renderer/pages/settings/McpSettings/__tests__/builtinMcpServers.test.ts # src/shared/data/presets/mcpServers.ts
zhangjiadi225
left a comment
There was a problem hiding this comment.
The overall direction is sound: moving the preset catalog into shared data and separating transport/launch concerns removes static builtin endpoint knowledge from the runtime. However, the refactor currently introduces a first-connect single-flight race, leaves legacy builtin identity incomplete during seeding, and carries forward an unregistered main-process filesystem path. These should be addressed before merge.
kangfenmao
left a comment
There was a problem hiding this comment.
The transport and preset refactor is moving in a good direction, and the existing review already covers the first-connect single-flight race, legacy builtin identity, and path registration. Two additional correctness gaps remain: a fresh QVeris install has no UI path to provide the credential that activation still requires after the transport change, and case-sensitive Authorization detection can mix static credentials with the OAuth provider. Please address these before merge.
- Restore first-connect single-flight: registering the pending promise after an await let two concurrent callers open two clients and leak one (A7). - Keep the builtin identity of migrated rows: legacy builtins carry no installSource and were recognised by their `inMemory` type alone, so Settings would unlock their name and transport after the seeder (A1). - Merge HTTP headers case-insensitively: a user-entered `authorization` now replaces the app default instead of travelling beside it, and it suppresses the OAuth provider the same way `Authorization` does (A1). - Read the mcp-auto-install catalog through `feature.mcp.registry_file` instead of building a path off the bin directory and mkdir-ing it (C1/B3). - Render and persist `env` for hosted builtins on any transport, so a freshly installed QVeris can still be given its API key (A1).
…nto mcp-runtime-builtin-tool-leak
…ool-leak # Conflicts: # src/main/ai/mcp/McpRuntimeService.ts
…ool-leak # Conflicts: # src/main/ai/mcp/McpRuntimeService.ts
|
The review is complete. No findings to report — the PR correctly addresses all previous feedback and the refactoring is well-structured with comprehensive test coverage. |
zhangjiadi225
left a comment
There was a problem hiding this comment.
LGTM. The previously requested changes are addressed.
A manually added or protocol-installed server whose name collides with a builtin preset owns its own configuration; matching on name and `inMemory` type alone rewrote its transport. Restrict the update to rows whose installSource is builtin or absent (the legacy builtin shape). Also pins the preset endpoints and the seeder version contract in tests instead of accepting any HTTP URL or re-deriving the hash, freezes the shared preset catalog both sides read live, and attributes the breaking-change entry.
|
🤖 Generated with Claude Code Review SummaryI've completed a thorough review of this refactoring PR. The implementation is well-designed with correct handling of:
No findings to report. The test coverage is comprehensive and the architectural separation into |
What this PR does
Before this PR:
McpRuntimeService.getOrCreateClientwas 470 lines / 47 branch points and knew individual built-in servers by name:@cherry/flomoand@cherry/nowledge-memwere stored asinMemoryrows but hard-coded to HTTP URLs inside the transport switch,@cherry/mcp-auto-installwas excluded from the in-memory branch by name, and itsMCP_REGISTRY_PATHwas set inline in the npx branch.After this PR:
The built-in catalog moved to
@shared/data/presets/mcpServers.tsand declares those two servers asstreamableHttpwith their realbaseUrl; a newBuiltinMcpServerSeedermigrates already-installed rows (and legacyinMemorymcp-auto-installrows tostdio). With the data honest, the runtime needs no name knowledge at all, sogetOrCreateClientwas split intoreuseLiveClient/connectClient/connectWithFallback/finishOAuth, with transport construction inmcpTransport.ts, npx/uvx/uv resolution as a runner table inmcpLaunch.ts, and the SDK loader plus transport policy inmcpClientSdk.ts.Fixes # None
Why we need it and why it was done in this way
The following tradeoffs were made:
inMemory, so re-running is a no-op, later user edits survive, and a built-in the user never installed (or deleted) is never resurrected — at the cost of not reconciling anything else.baseUrlchanges its OAuth storage key (md5(baseUrl)), so affected users re-authorize once. Preserving the old token was rejected becausemd5('')is shared by every server without abaseUrl(flomo and nowledge-mem collide on it today), and a wrong token simply triggers the existing 401 → re-auth path.The following alternatives were considered:
run-on-changeseeder with an idempotent guard.Links to places where the discussion took place:
None
Breaking changes
In Settings → MCP,
@cherry/flomoand@cherry/nowledge-memnow show as Streamable HTTP with a URL instead of in-memory, and a user who had authorized flomo is asked to authorize once more on the next connection. Recorded inv2-refactor-temp/docs/breaking-changes/2026-08-15-builtin-mcp-servers-http-transport.md.Special notes for your reviewer
args.includes('x')previously launchedbun -y pkg xwhen a package argument happened to bexor-y).serverUrlHashandgetServerKeystill read the stored row, andresolveMcpConfigTransportTypeinMcpServerFields.tsxis now redundant but left alone.Checklist
This checklist is not enforcing, but it's a reminder of items that could be relevant to every PR.
Approvers are expected to review this list.
main/gh-pr-review,gh pr diff, or GitHub UI) before requesting review from othersRelease note