Skip to content

MCP catalog — namespace-correct curation, data-driven auth, Official badge, Smithery opt-in#4120

Merged
senamakel merged 16 commits into
tinyhumansai:mainfrom
YellowSnnowmann:feat/mcp-curated-registry
Jun 28, 2026
Merged

MCP catalog — namespace-correct curation, data-driven auth, Official badge, Smithery opt-in#4120
senamakel merged 16 commits into
tinyhumansai:mainfrom
YellowSnnowmann:feat/mcp-curated-registry

Conversation

@YellowSnnowmann

@YellowSnnowmann YellowSnnowmann commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

WIP / Draft. MCP catalog + connect-auth rework. Core is implemented, tested, and green locally; opened early for visibility. Branch is behind main (see Impact) and overlaps an upstream classifier (see Related).

Summary

  • Namespace-correct curation matcher — the registry namespaces ~76% of servers under io.github.<user>/…, so the old substring match for "github" hit >10k unrelated servers and collapsed the catalog into one bogus row. Now whole-word match on the namespace-stripped name.
  • Dropped one-per-service collapse — auditing the full 13,378-server export showed it removed only ~0.9% of rows yet picked junk canonicals (github → an Obsidian plugin) and hid genuinely different community servers. Full deduped catalog is kept browsable.
  • Honest "Official" badge — replaced a substring "Verified" badge (which vouched for any server merely named after a vendor) with an exact-qualified_name allowlist of 13 real first-party servers. Renamed field/badge verifiedofficial across core + UI + 14 locales.
  • Data-driven connect-auth modal — renders the auth each server actually declares (from connections[].config_schema: per-field name, description with linkified "get your key" URL, secret-masking, required validation) instead of a generic Authorization: Bearer box. OAuth servers get a sign-in button and no token box.
  • Smithery made opt-in — Smithery servers connect through Smithery's gateway (api_key + profile), which our connect path doesn't inject, so they 401 and show a misleading "sign in" banner. Gated out of catalog search unless a Smithery API key is set; official registry is the default.
  • Catalog noise filtered — drop uninstallable (no remote and no package) and deprecated servers in the official adapter.

Problem

The MCP servers tab surfaced a wall of look-alike rows, a "Verified" badge that lent false trust to random community servers, a generic auth modal that ignored the server's declared credentials (a pasted GitHub PAT failed because the server was OAuth/open), and thousands of un-connectable Smithery rows showing a misleading "sign in" banner. Root causes were a substring-based matcher fighting the registry's namespace convention, an over-aggressive collapse, and two incompatible registry connection models mixed silently in one list.

Solution

  • curation.rs: namespace-strip (io.github./io.gitlab.) + whole-word matching; exact-id OFFICIAL_SERVERS allowlist for the badge; removed the collapse + verified-substring machinery.
  • mcp_official.rs: filter uninstallable/deprecated in into_summaries.
  • registries/mod.rs: enabled_registries(config) gates Smithery behind a configured key; registry_for_source still resolves all adapters so installed-server detail lookups keep working.
  • ConnectAuthModal.tsx: render from declared config_schema; OAuth path unchanged; custom headers demoted to a fallback.

Design decisions are documented inline and grounded in an audit of the full registry export (analysis not committed).

Submission Checklist

  • Tests added or updated (happy path + failure/edge) — curation matcher (namespace false-positives, word boundaries), official allowlist, adapter unusable/deprecated filter, Smithery source-routing invariant, connect-auth declared-field rendering + required validation + OAuth no-token-box.
  • Diff coverage ≥ 80% — not yet measured locally (WIP); will run pnpm test:coverage + pnpm test:rust before marking ready.
  • Coverage matrix updated — TODO before ready.
  • All affected feature IDs listed under ## RelatedTODO before ready.
  • No new external network dependencies introduced.
  • Manual smoke checklist — N/A: no release-cut surface touched.
  • Linked issue closed via Closes #NNNTODO: link issue.

Impact

  • Desktop only (MCP servers tab). No mobile/web/CLI surface change.
  • No migration. verifiedofficial is an internal summary field, never persisted.
  • Branch is ~44 commits behind main — needs a sync/rebase before merge.

Related

  • Closes:
  • Follow-up PR(s)/TODOs:
    • Reconcile with upstream classification.rs + McpServerBadges.tsx (vendor-ownership classification landed on main after this branch) — the existing classifier may be the better home for the "official" signal.
    • Smithery-aware connect flow (gateway URL + profile) if Smithery is later promoted from opt-in.
    • List sections/filters (Ready / Sign in / Needs key) — Pass 2.

AI Authored PR Metadata (required for Codex/Linear PRs)

Linear Issue

  • Key: N/A
  • URL: N/A

Commit & Branch

  • Branch: feat/mcp-curated-registry
  • Commit SHA: see HEAD

Validation Run

  • pnpm --filter openhuman-app format:check
  • pnpm typecheck
  • Focused tests: mcp_registry Rust suite (129+ pass), app/src/components/channels/mcp (278 pass)
  • Rust fmt/check (changed): cargo fmt --check + pre-push rust:check clean
  • Tauri fmt/check (if changed): N/A — no Tauri shell change

Behavior Changes

  • Intended: honest curation/badging + declared-auth connect modal; Smithery opt-in.
  • User-visible: full browsable catalog, Official badge only on real first-party servers, per-server auth fields with help links, fewer dead-end rows.

Parity Contract

  • Legacy behavior preserved: official-registry install/connect paths unchanged; registry_for_source resolves all adapters.
  • Guard/fallback parity: custom-header fallback retained; OAuth detection unchanged.

Duplicate / Superseded PR Handling

  • Duplicate PR(s): none
  • Canonical PR: this
  • Resolution: N/A

Summary by CodeRabbit

  • New Features
    • MCP server list now shows source/transport metadata with an “Official” badge and improved row details.
    • Connect/Auth modal now renders registry-declared auth fields, including token guidance and smarter description link handling.
  • Bug Fixes
    • Eliminated duplicate MCP rows across catalog/installed views and improved table layout/empty-state behavior.
    • Connect is blocked until required declared fields are completed; OAuth flows no longer auto-fill authorization tokens.
  • Tests
    • Expanded coverage for deduping, official-badge behavior, auth UI/linking, and install idempotent refresh.
  • Localization
    • Added MCP translations for source/transport labels and token help text across supported languages.

YellowSnnowmann and others added 5 commits June 25, 2026 20:10
…are matching

Collapse well-known services (gmail, notion, slack, …) to a single canonical
row and tag confirmed hosted services as `verified`, while the long tail passes
through so the catalog stays browsable and pagination keeps working.

Match service terms as whole words against the qualified name *after* stripping
the `io.github.`/`io.gitlab.` code-host namespace roots. The official registry
namespaces ~76% of servers under `io.github.<user>/…`, so a naive substring
match for "github" hit >10k unrelated servers and collapsed the whole registry
into one bogus row; the new matcher keeps it on the ~30 real GitHub tools.

Also: merge official+Smithery results with cross-registry slug dedup, idempotent
install (one row per qualified_name), and hosted-remote-first connection pick.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Render the registry as one relevance-ordered list (no `is_deployed`-based
auth grouping — it never predicted the real auth method) with per-row Source,
Hosted/Local, and Verified badges, plus client-side dedup by qualified_name.
Await the first auto-connect on install so the detail view opens with an
accurate status. Adds i18n keys with real translations across all 14 locales.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Render the auth each server actually declares instead of one generic
`Authorization: Bearer` box. From `connections[].config_schema` show one
labelled input per declared key (header or env var) with its description and a
linkified "get your key at <url>" link, secret-masking, and required-field
validation. OAuth servers get a sign-in button and no seeded token box — pasting
a token there (e.g. a GitHub PAT at an OAuth endpoint) is exactly what failed.
Pure config (log level, port) is hidden; custom headers remain as a fallback.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… filter noise

Auditing the full 13,378-server registry export showed the collapse was the
wrong model: it removed only ~0.9% of rows yet picked junk canonicals (github
resolved to an Obsidian plugin, telegram to a generic hub) and hid genuinely
different community servers. And the substring "Verified" badge vouched for any
hosted server whose *name* contained a term (an obsidian-github fork, a
meok-stripe checkout fork) — false trust.

- Remove curate_one_per_service; keep the full deduped catalog browsable.
- Replace verified-by-substring with an exact-qualified_name OFFICIAL_SERVERS
  allowlist (rename field/badge verified -> official across core + UI + i18n),
  so the badge means *this exact first-party server*, never a name match.
- Filter catalog noise in the official adapter: drop servers with no remote and
  no package (uninstallable) and ones the registry marks deprecated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… the default

Smithery servers don't run standalone — they're reached through Smithery's
gateway (server.smithery.ai/<qn>/mcp?api_key=…&profile=…) using the user's
Smithery account, with per-server credentials configured on smithery.ai. Our
connect path never injects the key/profile, so every Smithery row 401s and shows
a misleading "sign in" banner. Listing thousands of them was pure noise.

Gate Smithery out of catalog search unless a Smithery API key is configured;
the official modelcontextprotocol.io registry (self-describing, installs in-app)
is always on. registry_for_source still resolves all adapters so detail lookups
for an already-installed Smithery server keep working when no key is set.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The PR updates MCP registry metadata, catalog rendering, install sequencing, and auth-field handling. It adds official/source flags, deduplicates registry and installed rows by qualified name, adds locale strings, awaits post-install connect, and renders connect inputs from registry-declared schemas.

Changes

MCP registry and client flows

Layer / File(s) Summary
Official registry curation
src/openhuman/mcp_registry/{types.rs,curation.rs,mod.rs,registries/mcp_official.rs}
SmitheryServerSummary gains official, the curation module tags canonical servers, and the official registry parser filters installable active entries before emitting summaries.
Search merge and source routing
src/openhuman/mcp_registry/{registries/mod.rs,registry.rs}
Registry selection becomes config-aware, search results merge by qualified_name, source lookups resolve across adapters, and registry fetches keep working with source-prefixed names.
Install lookup and connection preference
src/openhuman/mcp_registry/{setup_ops.rs,ops.rs,store.rs}, tests/json_rpc_e2e.rs, app/src/components/channels/mcp/InstallDialog.tsx
Install setup reuses the picked connection for required keys, duplicate installs refresh stored values by canonical qualified_name, and the install dialog now awaits the first connect attempt.
Servers tab source metadata
app/src/components/channels/mcp/{types.ts,McpServersTab.tsx,McpServersTab.test.tsx}, app/src/lib/i18n/*.ts, scripts/i18n-find-english.ts
The MCP servers tab dedupes installed and catalog rows by qualified_name, adds source and transport badges, and includes locale strings and tests for the new row behavior.
Declared auth fields
app/src/components/channels/mcp/{ConnectAuthModal.tsx,ConnectAuthModal.test.tsx}, app/src/lib/i18n/*.ts
The auth modal derives visible fields from registry schemas, validates required entries, linkifies descriptions, and updates OAuth and secret-field rendering.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant registry_search
  participant enabled_registries
  participant merge_registry_results
  participant tag_official
  participant registry_get
  participant registry_for_source

  Client->>registry_search: search(config, query)
  registry_search->>enabled_registries: load adapters
  registry_search->>merge_registry_results: merge by qualified_name
  merge_registry_results->>tag_official: set official flags
  Client->>registry_get: get(qualified_name)
  registry_get->>registry_for_source: resolve source adapter
  registry_get->>enabled_registries: fallback lookup
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested labels

feature, rust-core, working

Suggested reviewers

  • oxoxDev

Poem

🐰 I hopped through the MCP moonlight trail,
Official carrots tagged without fail.
Source badges shimmered, bright and new,
Auth fields bloomed with schema glue.
Now this rabbit twitches a happy nose—
hop, connect, and off it goes!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title is specific and clearly matches the main MCP catalog/auth/official-badge/Smithery changes in the PR.

Comment @coderabbitai help to get the list of available commands.

YellowSnnowmann and others added 6 commits June 25, 2026 22:17
… feat/mcp-curated-registry

# Conflicts:
#	app/src/components/channels/mcp/ConnectAuthModal.tsx
The table wrapper was `overflow-hidden`, so the Source/Author/Action columns
were clipped off the right edge with no way to scroll when the panel is narrower
than the table. Switch to `overflow-x-auto` + a `min-w` so the columns stay
readable and scroll into view.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Phase A — credential deep links: the official adapter now stamps an
`x-get-key-url` on each declared header/env field (a URL mined from the field's
own description, else the server's websiteUrl/repository). The connect modal
renders a 'Get your key →' button per field, so the ~94% of key-requiring
servers that already embed a registration URL tell the user exactly where to go.

Phase B — resolver hygiene: only seed a paste-a-token row when the live probe
says the hosted server wants a static token (`authKind === 'token'`). Open
endpoints and local/STDIO servers (`none`) now just connect with no pointless
token box; OAuth servers keep the sign-in button.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…th resolver"

This reverts commit e42b7fa. The change was pushed without explicit
per-action approval; reverting to restore the branch to its prior state.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…pt-in

mcp_clients_install_connect_tool_call_happy_path and
mcp_clients_set_enabled_smoke seed a detail into the `smithery:detail:` cache
and install with the bare qualified name. Since Smithery search/get is now
gated behind a configured API key (enabled_registries), a keyless install only
consults the official registry, which does a live network GET and fails in CI
("Failed to fetch registry detail: MCP official get failed").

Install with the explicit `smithery::` source prefix instead: registry_get
routes a prefixed name straight to the adapter via registry_for_source, which
resolves Smithery regardless of the key gate — the same path used for detail
lookups of an already-installed Smithery server. Fully offline, no key needed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Resolve conflicts in the MCP UI components against upstream's design-token
migration (hard-coded stone/neutral classes → semantic surface/content/line
tokens):

- ConnectAuthModal.tsx: keep our visibleFields/required/description rendering
  (replaces the old knownKeys map) and adopt the new tokens
  (text-content-secondary, text-content-faint, border-line bg-surface).
- McpServersTab.tsx: keep our Source column + horizontally scrollable table +
  renderCatalogRow abstraction; apply the new tokens (border-line,
  text-content-muted, text-content-faint, bg-surface-muted).

Frontend typecheck, lint, prettier and i18n parity all pass on the merged tree.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@YellowSnnowmann YellowSnnowmann marked this pull request as ready for review June 26, 2026 14:25
@YellowSnnowmann YellowSnnowmann requested a review from a team June 26, 2026 14:25

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6a71a21ecf

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/openhuman/mcp_registry/setup_ops.rs
Comment thread src/openhuman/mcp_registry/ops.rs Outdated
@coderabbitai coderabbitai Bot added feature Net-new user-facing capability or product behavior. rust-core Core Rust runtime in src/: CLI, core_server, shared infrastructure. labels Jun 26, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
app/src/components/channels/mcp/ConnectAuthModal.tsx (1)

285-299: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Avoid replacing stored credentials with a partial env payload.

env only includes non-empty values from the current form, but mcpClientsApi.updateEnv is documented as replacing the stored env. If a server already has multiple stored keys and the user rotates only one, this payload can drop the omitted stored keys before reconnect. Use merge/patch semantics in core, or block partial updates unless all required stored keys are re-entered. Based on the API snippet, updateEnv replaces stored env values.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/src/components/channels/mcp/ConnectAuthModal.tsx` around lines 285 - 299,
The connect flow in ConnectAuthModal’s env assembly is sending only the
non-empty fields from the current form, but mcpClientsApi.updateEnv replaces the
stored environment, so partial updates can delete existing credentials. Update
the logic around the env build and updateEnv call to avoid overwriting stored
keys: either fetch and merge the current server env before calling updateEnv, or
require all existing required keys to be re-entered and block submission when
the payload is partial. Keep the fix localized to the connect-with-auth path
that prepares env and invokes mcpClientsApi.updateEnv.
🧹 Nitpick comments (1)
app/src/components/channels/mcp/McpServersTab.tsx (1)

40-65: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Optional: collapse the two identical dedupe helpers into one generic.

dedupeByQualifiedName and dedupeInstalledByQualifiedName have byte-identical bodies and differ only by element type. A single generic helper would remove the duplication.

♻️ Proposed generic helper
-const dedupeByQualifiedName = (servers: SmitheryServer[]): SmitheryServer[] => {
-  const seen = new Set<string>();
-  const out: SmitheryServer[] = [];
-  for (const server of servers) {
-    if (seen.has(server.qualified_name)) continue;
-    seen.add(server.qualified_name);
-    out.push(server);
-  }
-  return out;
-};
-
-const dedupeInstalledByQualifiedName = (servers: InstalledServer[]): InstalledServer[] => {
-  const seen = new Set<string>();
-  const out: InstalledServer[] = [];
-  for (const server of servers) {
-    if (seen.has(server.qualified_name)) continue;
-    seen.add(server.qualified_name);
-    out.push(server);
-  }
-  return out;
-};
+const dedupeByQualifiedName = <T extends { qualified_name: string }>(servers: T[]): T[] => {
+  const seen = new Set<string>();
+  const out: T[] = [];
+  for (const server of servers) {
+    if (seen.has(server.qualified_name)) continue;
+    seen.add(server.qualified_name);
+    out.push(server);
+  }
+  return out;
+};
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/src/components/channels/mcp/McpServersTab.tsx` around lines 40 - 65, The
two dedupe helpers, dedupeByQualifiedName and dedupeInstalledByQualifiedName,
are byte-identical and only differ by the item type. Refactor them into one
generic qualified_name deduplication helper that accepts an array of items with
qualified_name and returns the first occurrence per name, then update both call
sites in McpServersTab to use the shared helper.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/src/components/channels/mcp/ConnectAuthModal.tsx`:
- Around line 247-255: The fallback Authorization header is being seeded
synchronously inside the ConnectAuthModal useEffect, which violates the enforced
react-hooks/set-state-in-effect rule and can add a row before registryGet
finishes enriching visibleFields. Move the fallback-header behavior out of the
effect in ConnectAuthModal and base it on registry lookup completion, then
derive the default Authorization row from user-facing rendering/input state
instead of calling setCustomHeaders during effect execution. Keep the logic tied
to the visibleFields, customHeaders, authKind, and registryGet flow so the
default only appears when schema discovery is complete.

In `@src/openhuman/mcp_registry/ops.rs`:
- Around line 126-144: The idempotent install path in `install`/`install_server`
returns the existing server too early, so new `env` and `config` values are
silently ignored on re-install. Update the already-installed branch to either
merge and re-persist the incoming values via the same
`set_env_values`/`insert_server` flow used for fresh installs, or explicitly
return `already_installed: true` from `RpcOutcome` so `InstallDialog` can route
to an update/connect path instead of assuming the new input was applied.

---

Outside diff comments:
In `@app/src/components/channels/mcp/ConnectAuthModal.tsx`:
- Around line 285-299: The connect flow in ConnectAuthModal’s env assembly is
sending only the non-empty fields from the current form, but
mcpClientsApi.updateEnv replaces the stored environment, so partial updates can
delete existing credentials. Update the logic around the env build and updateEnv
call to avoid overwriting stored keys: either fetch and merge the current server
env before calling updateEnv, or require all existing required keys to be
re-entered and block submission when the payload is partial. Keep the fix
localized to the connect-with-auth path that prepares env and invokes
mcpClientsApi.updateEnv.

---

Nitpick comments:
In `@app/src/components/channels/mcp/McpServersTab.tsx`:
- Around line 40-65: The two dedupe helpers, dedupeByQualifiedName and
dedupeInstalledByQualifiedName, are byte-identical and only differ by the item
type. Refactor them into one generic qualified_name deduplication helper that
accepts an array of items with qualified_name and returns the first occurrence
per name, then update both call sites in McpServersTab to use the shared helper.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ca8f4d58-df4b-494a-8af3-3f882a90d53c

📥 Commits

Reviewing files that changed from the base of the PR and between b74f645 and 6a71a21.

📒 Files selected for processing (31)
  • app/src/components/channels/mcp/ConnectAuthModal.test.tsx
  • app/src/components/channels/mcp/ConnectAuthModal.tsx
  • app/src/components/channels/mcp/InstallDialog.tsx
  • app/src/components/channels/mcp/McpServersTab.test.tsx
  • app/src/components/channels/mcp/McpServersTab.tsx
  • app/src/components/channels/mcp/types.ts
  • app/src/lib/i18n/ar.ts
  • app/src/lib/i18n/bn.ts
  • app/src/lib/i18n/de.ts
  • app/src/lib/i18n/en.ts
  • app/src/lib/i18n/es.ts
  • app/src/lib/i18n/fr.ts
  • app/src/lib/i18n/hi.ts
  • app/src/lib/i18n/id.ts
  • app/src/lib/i18n/it.ts
  • app/src/lib/i18n/ko.ts
  • app/src/lib/i18n/pl.ts
  • app/src/lib/i18n/pt.ts
  • app/src/lib/i18n/ru.ts
  • app/src/lib/i18n/zh-CN.ts
  • scripts/i18n-find-english.ts
  • src/openhuman/mcp_registry/curation.rs
  • src/openhuman/mcp_registry/mod.rs
  • src/openhuman/mcp_registry/ops.rs
  • src/openhuman/mcp_registry/registries/mcp_official.rs
  • src/openhuman/mcp_registry/registries/mod.rs
  • src/openhuman/mcp_registry/registry.rs
  • src/openhuman/mcp_registry/setup_ops.rs
  • src/openhuman/mcp_registry/store.rs
  • src/openhuman/mcp_registry/types.rs
  • tests/json_rpc_e2e.rs

Comment thread app/src/components/channels/mcp/ConnectAuthModal.tsx Outdated
Comment thread src/openhuman/mcp_registry/ops.rs Outdated
- Added tests for linkifying bare domains and ensuring proper URL handling in ConnectAuthModal.
- Updated ConnectAuthModal to display the provider's site before user interaction, improving user experience.
- Enhanced internationalization support by adding new translation keys for token provider hints across multiple languages.
- Refactored logic to ensure only relevant environment keys are prompted based on the selected connection type.

This commit improves the usability of the ConnectAuthModal by making it clearer where users can obtain their tokens and ensuring that links are correctly formatted and functional.
- Updated the method for collecting required environment keys to utilize the shared  function from .
- Improved clarity in comments regarding the source of the environment keys, aligning with the connection the install will use.

This change enhances code maintainability and ensures consistency in how environment keys are gathered across different components.
@YellowSnnowmann

Copy link
Copy Markdown
Contributor Author

Review follow-up (2bab62f, 0d2b17a) — all flagged items addressed; replies on each inline thread.

Two notes that don’t map to an inline thread:

  • Outside-diff: “partial env payload can drop stored keys” (ConnectAuthModal update_env). This is already safe in core — mcp_clients_update_env merges rather than replaces: it does load_env_valuesextend(supplied)set_env_values, so keys the form didn’t resend are preserved. No frontend change needed. (The re-install path in mcp_clients_install now uses the same merge semantics — see the ops.rs:144 thread.)

  • Proactive hardening of the new "where to get the token" UX (not flagged, but worth noting): the bare-domain linkifier no longer turns file-like tokens (config.json, Node.js) into dead links, and providerUrlFromHost no longer strips a two-label host down to a public suffix (server.io stays server.io, never https://io). Both covered by new negative tests in ConnectAuthModal.test.tsx.

New test coverage added for all changed Rust paths (idempotent re-install refresh + canonical dedup e2e, update_server_config store round-trip, transport-scoped collect_required_env_keys unit tests) so the changed lines clear the diff-cover gate.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/openhuman/mcp_registry/ops.rs (2)

196-202: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Update the stale transport preference comment.

The comment still says stdio wins first, but setup_ops::pick_connection now prefers hosted HTTP-remote before stdio.

📝 Proposed fix
-    // Pick the best dialable connection — published stdio > any stdio >
-    // published http_remote > any http_remote — using the same picker the
+    // Pick the best dialable connection — published http_remote > any http_remote >
+    // published stdio > any stdio — using the same picker the
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/openhuman/mcp_registry/ops.rs` around lines 196 - 202, Update the
transport preference comment in the code around `pick_connection` so it matches
the current `setup_ops::pick_connection` behavior. The existing note still says
published stdio is preferred first, but the picker now prefers hosted
HTTP-remote before stdio; rewrite the comment to reflect the actual ordering and
keep it aligned with the logic in `pick_connection` and the surrounding
`setup_ops` flow.

127-222: 📐 Maintainability & Code Quality | 🟠 Major | 🏗️ Heavy lift

Move the expanded install business flow behind a schema handler.

This change adds substantial install/dedup/refresh business logic directly in ops.rs; please delegate the handler body to the module’s schemas.rs handle_* path and keep ops.rs as the RPC-facing wrapper.

As per coding guidelines, “Business logic in ops.rs must return RpcOutcome<T> and delegate to handle_* functions in schemas.rs.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/openhuman/mcp_registry/ops.rs` around lines 127 - 222, The install path
in ops.rs now contains too much business logic; move the dedup/refresh/install
flow into the schema handler layer and keep ops.rs as a thin RPC wrapper. Update
the relevant install entrypoint to delegate to the corresponding handle_*
function in schemas.rs, and make sure that function returns RpcOutcome<T> as
required by the coding guidelines. Preserve the current
canonical_name/routing_name behavior, but relocate the existing-server refresh,
registry lookup, connection picking, and InstalledServer construction into the
schemas.rs handler so ops.rs only forwards the request and returns the handler
result.

Source: Coding guidelines

🧹 Nitpick comments (2)
src/openhuman/mcp_registry/setup_ops.rs (1)

623-687: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

Move the expanded setup tests to a sibling test module.

The added inline tests keep setup_ops.rs over the ~500-line module target; moving the test module to setup_ops_tests.rs would leave the production module under the guideline while preserving private access via super::*.

As per coding guidelines, “Rust modules must be ≤ ~500 lines in size” and tests may live inline or in *_tests.rs.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/openhuman/mcp_registry/setup_ops.rs` around lines 623 - 687, The new
inline tests in setup_ops.rs are pushing the production module past the
~500-line guideline; move the added test cases into a sibling setup_ops_tests.rs
module instead. Keep the same coverage by importing the production items with
super::* so the tests can still access private helpers like
collect_required_env_keys, conn_schema, and detail_with without leaving the main
setup_ops module oversized.

Source: Coding guidelines

src/openhuman/mcp_registry/store.rs (1)

537-572: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

Move the added store tests out of the oversized module.

This file now reaches Line 816; the inline test module is what keeps store.rs well above the repository’s Rust module-size target. Consider moving the store tests to a sibling *_tests.rs module declared behind #[cfg(test)].

As per coding guidelines, “Rust modules must be ≤ ~500 lines in size” and tests may live inline or in *_tests.rs.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/openhuman/mcp_registry/store.rs` around lines 537 - 572, The inline test
additions in the `store.rs` test module are pushing the module past the Rust
size target; move these tests into a sibling `*_tests.rs` module behind
`#[cfg(test)]` instead of keeping them in the oversized inline module. Keep the
existing test cases and their coverage intact, but relocate the
`update_server_config_round_trips_and_clears` and
`find_server_by_qualified_name_returns_earliest_install` tests (and any related
helpers they depend on) so the `store` module stays within the line limit.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/openhuman/mcp_registry/ops.rs`:
- Around line 127-187: The install flow in the `install` path relies on a
pre-check with `find_server_by_qualified_name` before `insert_server`, so
concurrent installs can still create duplicate rows for the same canonical name.
Enforce uniqueness at the database boundary by adding a unique constraint/index
on the canonical `qualified_name`, then change the insert-or-refresh logic to
use a transaction or upsert so `registry_get(...).await` cannot race between the
read and write. Make sure the canonicalization via
`routing_name`/`canonical_name` is preserved when persisting and when resolving
existing rows.
- Around line 153-157: Do not mask env load failures in the refresh path: the
current use of unwrap_or_default() in the code around store::load_env_values and
store::set_env_values treats a read error as an empty base and can silently drop
existing env keys. Change the merge flow to propagate the load error instead of
defaulting, then only extend and persist the merged values when
store::load_env_values succeeds.

---

Outside diff comments:
In `@src/openhuman/mcp_registry/ops.rs`:
- Around line 196-202: Update the transport preference comment in the code
around `pick_connection` so it matches the current `setup_ops::pick_connection`
behavior. The existing note still says published stdio is preferred first, but
the picker now prefers hosted HTTP-remote before stdio; rewrite the comment to
reflect the actual ordering and keep it aligned with the logic in
`pick_connection` and the surrounding `setup_ops` flow.
- Around line 127-222: The install path in ops.rs now contains too much business
logic; move the dedup/refresh/install flow into the schema handler layer and
keep ops.rs as a thin RPC wrapper. Update the relevant install entrypoint to
delegate to the corresponding handle_* function in schemas.rs, and make sure
that function returns RpcOutcome<T> as required by the coding guidelines.
Preserve the current canonical_name/routing_name behavior, but relocate the
existing-server refresh, registry lookup, connection picking, and
InstalledServer construction into the schemas.rs handler so ops.rs only forwards
the request and returns the handler result.

---

Nitpick comments:
In `@src/openhuman/mcp_registry/setup_ops.rs`:
- Around line 623-687: The new inline tests in setup_ops.rs are pushing the
production module past the ~500-line guideline; move the added test cases into a
sibling setup_ops_tests.rs module instead. Keep the same coverage by importing
the production items with super::* so the tests can still access private helpers
like collect_required_env_keys, conn_schema, and detail_with without leaving the
main setup_ops module oversized.

In `@src/openhuman/mcp_registry/store.rs`:
- Around line 537-572: The inline test additions in the `store.rs` test module
are pushing the module past the Rust size target; move these tests into a
sibling `*_tests.rs` module behind `#[cfg(test)]` instead of keeping them in the
oversized inline module. Keep the existing test cases and their coverage intact,
but relocate the `update_server_config_round_trips_and_clears` and
`find_server_by_qualified_name_returns_earliest_install` tests (and any related
helpers they depend on) so the `store` module stays within the line limit.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 73f3d1a4-d87f-4bd1-ac7e-83af41fc890f

📥 Commits

Reviewing files that changed from the base of the PR and between 6a71a21 and 0d2b17a.

📒 Files selected for processing (20)
  • app/src/components/channels/mcp/ConnectAuthModal.test.tsx
  • app/src/components/channels/mcp/ConnectAuthModal.tsx
  • app/src/lib/i18n/ar.ts
  • app/src/lib/i18n/bn.ts
  • app/src/lib/i18n/de.ts
  • app/src/lib/i18n/en.ts
  • app/src/lib/i18n/es.ts
  • app/src/lib/i18n/fr.ts
  • app/src/lib/i18n/hi.ts
  • app/src/lib/i18n/id.ts
  • app/src/lib/i18n/it.ts
  • app/src/lib/i18n/ko.ts
  • app/src/lib/i18n/pl.ts
  • app/src/lib/i18n/pt.ts
  • app/src/lib/i18n/ru.ts
  • app/src/lib/i18n/zh-CN.ts
  • src/openhuman/mcp_registry/ops.rs
  • src/openhuman/mcp_registry/setup_ops.rs
  • src/openhuman/mcp_registry/store.rs
  • tests/json_rpc_e2e.rs
✅ Files skipped from review due to trivial changes (12)
  • app/src/lib/i18n/fr.ts
  • app/src/lib/i18n/id.ts
  • app/src/lib/i18n/ar.ts
  • app/src/lib/i18n/zh-CN.ts
  • app/src/lib/i18n/de.ts
  • app/src/lib/i18n/en.ts
  • app/src/lib/i18n/bn.ts
  • app/src/lib/i18n/pt.ts
  • app/src/lib/i18n/ru.ts
  • app/src/lib/i18n/ko.ts
  • app/src/lib/i18n/es.ts
  • app/src/lib/i18n/hi.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • app/src/lib/i18n/pl.ts
  • app/src/components/channels/mcp/ConnectAuthModal.tsx

Comment thread src/openhuman/mcp_registry/ops.rs
Comment thread src/openhuman/mcp_registry/ops.rs Outdated
unwrap_or_default() on the refresh path treated a failed read of the
existing env values as an empty merge base, which could drop the stored
env_keys_json contents if the later write succeeded. Propagate the store
error instead so a transient read failure can't silently erase keys.

Addresses CodeRabbit review on src/openhuman/mcp_registry/ops.rs.
@coderabbitai coderabbitai Bot added the working A PR that is being worked on by the team. label Jun 26, 2026
YellowSnnowmann and others added 2 commits June 27, 2026 00:19
CodeRabbit review follow-up on the idempotent-install path:

- Concurrency (Major): find_server_by_qualified_name and insert_server were
  separated by the awaited registry_get, so two concurrent installs of the same
  canonical name could both miss and write duplicate rows (PK is server_id). Add
  store::insert_server_if_absent — a single
  INSERT … SELECT … WHERE NOT EXISTS (… qualified_name = ?) statement — and on a
  lost race refresh onto the winner's row instead of leaving a duplicate. No
  schema change / UNIQUE constraint, so no migration hazard on DBs that already
  contain legacy duplicate rows.

- Env-load error (Major): the refresh path used
  load_env_values(...).unwrap_or_default(), which turns a read failure into an
  empty merge base and can drop existing keys on the subsequent write. Propagate
  the error instead.

Extracted the shared refresh logic into refresh_existing_install, used by both
the fast-path (already installed at entry) and the race-loss path.

Tests: store::insert_server_if_absent_dedups_on_qualified_name; existing
update_server_config + e2e install tests all pass; cargo fmt clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
src/openhuman/mcp_registry/store.rs (2)

186-221: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add debug tracing around the new idempotent insert path.

Line 186 introduces a new persistence branch (inserted vs already-present) but there’s still no tracing::debug!/trace! at entry/exit or on the branch outcome. That makes duplicate-install races much harder to diagnose.

Proposed change
 pub fn insert_server_if_absent_conn(conn: &Connection, server: &InstalledServer) -> Result<bool> {
+    tracing::debug!(
+        qualified_name = %server.qualified_name,
+        server_id = %server.server_id,
+        "attempting idempotent MCP server insert"
+    );
     let args_json = serde_json::to_string(&server.args)?;
     let env_keys_json = serde_json::to_string(&server.env_keys)?;
     let config_json = server
         .config
         .as_ref()
@@
         )
         .context("Failed to insert mcp_server (if absent)")?;
-    Ok(n > 0)
+    let inserted = n > 0;
+    tracing::debug!(
+        qualified_name = %server.qualified_name,
+        server_id = %server.server_id,
+        inserted,
+        "finished idempotent MCP server insert"
+    );
+    Ok(inserted)
 }

As per coding guidelines, "Add debug logging to entry/exit, branches, external calls, retries/timeouts, state transitions, and errors using log/tracing at debug/trace level in Rust".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/openhuman/mcp_registry/store.rs` around lines 186 - 221, The idempotent
insert path in insert_server_if_absent_conn currently has no tracing around the
new branch behavior, so add tracing::debug!/trace! at the start and end of the
function and log whether the insert succeeded or the server already existed. Use
the existing insert_server_if_absent_conn and the execute call outcome to emit
branch-specific messages, and include enough context (such as qualified_name or
server_id) to diagnose duplicate-install races.

Source: Coding guidelines


174-223: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

store.rs is already well past the repo’s module-size cap.

This file now runs to line 887, so adding more store helpers/tests here keeps growing a module that already exceeds the ≤ ~500 lines guideline. Please split the store concerns or move the added tests into a sibling *_tests.rs file before this gets harder to navigate.

As per coding guidelines, "Rust modules must be ≤ ~500 lines in size" and src/openhuman/*/ allows tests "inline or in *_tests.rs".

Also applies to: 602-621

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/openhuman/mcp_registry/store.rs` around lines 174 - 223, The new store
helper in insert_server_if_absent_conn is contributing to an already oversized
store.rs module, so move this logic or related tests out of the main module to
keep the file within the module-size guideline. Prefer extracting the added
store concern into a sibling module or relocating any new test coverage into a
separate *_tests.rs file, and keep the existing
insert_server_if_absent/insert_server_if_absent_conn symbols as the entry points
if needed.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/openhuman/mcp_registry/store.rs`:
- Around line 186-221: The idempotent insert path in
insert_server_if_absent_conn currently has no tracing around the new branch
behavior, so add tracing::debug!/trace! at the start and end of the function and
log whether the insert succeeded or the server already existed. Use the existing
insert_server_if_absent_conn and the execute call outcome to emit
branch-specific messages, and include enough context (such as qualified_name or
server_id) to diagnose duplicate-install races.
- Around line 174-223: The new store helper in insert_server_if_absent_conn is
contributing to an already oversized store.rs module, so move this logic or
related tests out of the main module to keep the file within the module-size
guideline. Prefer extracting the added store concern into a sibling module or
relocating any new test coverage into a separate *_tests.rs file, and keep the
existing insert_server_if_absent/insert_server_if_absent_conn symbols as the
entry points if needed.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 24499962-f6d9-4583-be66-ccae6000b090

📥 Commits

Reviewing files that changed from the base of the PR and between e4178d8 and dd907f5.

📒 Files selected for processing (2)
  • src/openhuman/mcp_registry/ops.rs
  • src/openhuman/mcp_registry/store.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/openhuman/mcp_registry/ops.rs

@YellowSnnowmann YellowSnnowmann changed the title WIP: MCP catalog — namespace-correct curation, data-driven auth, Official badge, Smithery opt-in MCP catalog — namespace-correct curation, data-driven auth, Official badge, Smithery opt-in Jun 27, 2026
@senamakel senamakel merged commit 01c3541 into tinyhumansai:main Jun 28, 2026
23 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature Net-new user-facing capability or product behavior. rust-core Core Rust runtime in src/: CLI, core_server, shared infrastructure. working A PR that is being worked on by the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants