Skip to content

Install registry servers by name through the MCP API - #7

Merged
czpython merged 1 commit into
mainfrom
mcp-registry-3-install-api
Jul 14, 2026
Merged

Install registry servers by name through the MCP API#7
czpython merged 1 commit into
mainfrom
mcp-registry-3-install-api

Conversation

@czpython

Copy link
Copy Markdown
Owner

Stack 3/4 of the registry install feature (resolver → headers → install API → UI). Base: mcp-registry-2-headers.

What

  • GET /api/mcp-servers/registry?q= — resolved candidates for the picker. The route does all the fetching (registry search + trust pins); McpRegistryCandidateResponse / RegistryHeaderResponse are pure projections of the resolver's dicts, no I/O in schemas. Each candidate carries: druks name, registryName, description, url, the official badge, tokenSource, and the declared header inputs (name/description/placeholder/isRequired/isSecret/format) the form renders. An unreachable registry maps to 502, an unreadable pins file to a named 500 — never an empty list.
  • POST /api/mcp-servers grows the registry path beside the unchanged custom one: {name, registry, headers} is re-resolved server-side — url, auth shape, and per-header secrecy come from the registry, never the client. Required headers enforced (named 422), unknown headers rejected, values split into the row's plain/secret columns by the spec's isSecret.
  • Bearer classification (in the resolver, one computation site): a remote declaring a secret header authenticates through it → installs as none-source, ready and enabled. Anything else is assumed OAuth (the streamable-http default) → ships dark until Connect lands, exactly like the catalog's linear default. Known ceiling, commented in place: the registry schema declares no auth mode, so a no-auth public server reads as oauth and its Connect fails at discovery.
  • Connect covers rows: the lookup moved from the builtin registry to the resolved view, so an installed row reuses the existing mcp/oauth.py discovery + consent flow against its registry-supplied url. The linear builtin path is untouched (its tests pass unmodified).
  • Delete drops the grant: removing a connected row deletes its McpOauthGrant and evicts the cached access token — an orphan grant would revive as the name's credential on re-add.

Verify

HTTP tests on canned registry wire bytes (MockTransport under the real client + the packaged trusted.json): search route projects candidates (badge, tokenSource, header specs, pinned sentry url) · 502 mapping · add-from-registry writes the row with the secret stored encrypted and redacted in every response · oauth candidate ships dark and Connect uses the row's url · missing-required/unknown-header 422s · uninstallable entry 404 · delete drops the grant.

754 passed, 49 skipped (full backend suite)

🤖 Generated with Claude Code

@czpython
czpython force-pushed the mcp-registry-2-headers branch 3 times, most recently from 477a963 to f4cfca4 Compare July 13, 2026 20:14
@czpython
czpython force-pushed the mcp-registry-3-install-api branch from 7c3c64f to 5f4d4cf Compare July 13, 2026 20:26
@czpython
czpython force-pushed the mcp-registry-2-headers branch 2 times, most recently from d6980a2 to b10836d Compare July 14, 2026 06:20
Base automatically changed from mcp-registry-2-headers to main July 14, 2026 06:22
@czpython
czpython force-pushed the mcp-registry-3-install-api branch 5 times, most recently from 1d436d0 to 01adf65 Compare July 14, 2026 20:31
GET /api/mcp-servers/registry?q= surfaces the resolved candidates — the
route fetches (registry + pins) and the response models are pure
projections: druks name, registry name, description, url, the official
badge, the bearer classification, and each declared header input the
form renders. Registry failures surface as a 502, an unreadable pins
file as a named 500 — never an empty list that reads as "no such
server".

POST /api/mcp-servers grows the registry path beside the custom one: a
body naming a registry entry is re-resolved server-side, so the url,
the auth shape and each header's secrecy come from the registry — the
client supplies only the druks name and the filled values. Required
headers are enforced, unknown ones rejected, and the values split into
the row's plain/secret columns by the spec's isSecret flags. A remote
that authenticates through a secret header installs ready and enabled;
anything else is assumed OAuth and ships dark until its Connect lands,
exactly like the catalog's oauth default.

Connect now looks the server up in the resolved view, so an installed
registry row reuses the existing consent flow against its
registry-supplied url; deleting a row drops its grant with it — an
orphan grant would revive as the name's credential on re-add.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@czpython
czpython force-pushed the mcp-registry-3-install-api branch from 01adf65 to 579bf0c Compare July 14, 2026 20:41
@czpython
czpython merged commit bda3639 into main Jul 14, 2026
1 check passed
@czpython
czpython deleted the mcp-registry-3-install-api branch July 14, 2026 20:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant