Skip to content

Let a host add curated servers at runtime, never badged official - #178

Merged
M3gA-Mind merged 4 commits into
tinyhumansai:mainfrom
M3gA-Mind:feat/49-runtime-curated-servers
Nov 11, 2026
Merged

M3gA-Mind merged 4 commits into
tinyhumansai:mainfrom
M3gA-Mind:feat/49-runtime-curated-servers

Conversation

@M3gA-Mind

Copy link
Copy Markdown
Contributor

Summary

The curated first-party servers were a compiled-in const. Adding, correcting or removing one took a tinymcp release and a version bump in every host (#49).

A host can now supply extra curated servers at runtime in McpRegistryAuthConfig.curated_servers. They're merged with the built-in list for the local-index merge, the cache fallback and the detail fallback.

Why not the file the issue proposed: tinymcp reads no files at runtime, and hosts own storage, so the entries travel in the registry settings the host already sends. For OpenHuman that's [[mcp_client.registry_auth.curated_servers]] in config.toml. That already deserializes into this type and reaches the module through the client config, so adding a server is still a file edit and a restart, with no OpenHuman code change.

Runtime entries are never promoted. Only a built-in server nobody replaced is badged official, leads a first search page or ranks as curated. A configuration line must not be able to make an arbitrary endpoint look vetted. An entry naming a built-in replaces its endpoint (so a moved endpoint can be fixed without a release) and takes its badge away. That's logged at warn with both URLs.

Related issue

Closes #49. Spec: docs/specs/runtime-curated-servers.md.

API or behavior changes

Contract minor bump: tinymcp-bus → 1.31. It lands after #164 (1.29) and the OAuth endpoint guard (1.30). A host built on this bus requires a module at 1.31.

  • McpRegistryAuthConfig.curated_servers: Vec<CuratedServerEntry> (serde default, omitted when empty). New types CuratedServerEntry (unknown fields refused), CuratedEntryTransport and CuratedEntryAuth.
  • Validation, when the registry dispatcher takes the settings: https with a host and no credentials (remote and icon), non-blank names, no duplicates. A bad entry is dropped with a warning; the rest load.
  • CuratedCatalog, entry_summary, entry_detail, validated_runtime_entries and CuratedServer::to_entry. OFFICIAL_SERVERS, CURATED_SERVERS and tag_official keep their built-in-only meaning; no host reads them today.

Validation

On our Linux CI runner, at 838cd11:

  • cargo fmt --all -- --check: clean.
  • cargo clippy --all-targets --all-features -- -D warnings: 0 errors, same as main.
  • cargo build and RUSTDOCFLAGS="-D warnings" cargo doc: ok.
  • Focused runs:
    • -p tinymcp-bus config (10 passed) and version (7);
    • -p tinymcp registry::curation (34);
    • registry::sources::official (151).
    • All named tests pass.
  • cargo test --workspace --no-fail-fast, against main in a separate build: no failures unique to this branch. Two timeouts showed on this side only (registry::boot, tinybus_module::directories); both are known full-suite flakes and passed 3 of 3 isolated reruns on both sides.
  • Red controls, each restored afterwards:
    • letting a runtime entry keep its badge: a_runtime_entry_is_listed_but_never_badged_or_promoted fails;
    • accepting http: validation_drops_each_bad_entry_and_keeps_the_rest fails;
    • promoting every entry: a_runtime_curated_server_does_not_lead_a_page fails, with io.zebra/mcp leading the page.

Merge note: #173 also changes lead_with_curated. Whichever lands second needs a small rebase there.

Tests

  • Catalog tests:
    • a runtime entry is listed but never badged or promoted;
    • one naming a built-in replaces its endpoint and drops its badge;
    • validation drops http, credentials, missing hosts, bad icons, blank names and duplicates, and keeps the rest;
    • built-ins convert to the same rows either way.
  • Adapter tests: a runtime entry doesn't lead a page, a replaced built-in no longer leads, and a runtime entry is described when the registry can't be asked.
  • Wire form pinned; a misspelled key is refused.
  • Red controls: badging any catalog entry fails the badge test; accepting http fails the validation test.

Documentation

The spec, the tinymcp-bus README's contract note, and rustdoc.

Checklist

  • The change is focused on one logical change
  • No new #[allow(...)], #[ignore], or relaxed lints
  • No secrets, tokens, or .env contents in the diff or the description

Hosts supply extra curated servers in McpRegistryAuthConfig, merged with
the built-in list everywhere it is used today, validated at open, with a
runtime entry replacing a built-in of the same name.
The curated first-party servers were a compiled-in const, so adding or
correcting one took a tinymcp release and a bump in every host (tinyhumansai#49).

Hosts now supply extra entries in McpRegistryAuthConfig::curated_servers
(contract 1.31, CuratedServerEntry). For openhuman that is
[[mcp_client.registry_auth.curated_servers]] in config.toml, which
already reaches the module through the client config, so adding a server
is a config edit and a restart. The issue proposed a file the module
reads. tinymcp reads no files at runtime and hosts own storage, so the
entries travel in the settings instead.

The registry dispatcher validates them once when it takes the settings:
https with a host and no credentials, non-blank names, no duplicates. A
bad entry is dropped with a warning, and the rest load. CuratedCatalog
merges them over the built-in list for the local-index merge, the cache
fallback and the detail fallback.

Runtime entries are never promoted. Only a built-in server nobody
replaced is badged official, leads a first page or ranks as curated,
because a configuration line must not make an arbitrary endpoint look
vetted. An entry naming a built-in replaces its endpoint and takes the
badge away, logged at warn with both URLs.

Closes tinyhumansai#49
@coderabbitai

coderabbitai Bot commented Nov 11, 2026 •

Copy link
Copy Markdown

Important

  • Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

Run configuration

  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 748db47c-bf7e-4c49-be28-a4978bd98457
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

@tinysweeper

tinysweeper Bot commented Nov 11, 2026 •

Copy link
Copy Markdown

Tiny Sweeper review

Verdict: Incomplete · Priority: none
Coverage: Reviewed 14 of 21 files; not reviewed (large PR): crates/tinymcp-b…, crates/tinymcp-b…, and 5 additional unreviewed files.
Pull request purpose (title): Let a host add curat…

Diagnostics and supporting details

Full summary

Pull request purpose (title): Let a host add curated servers at runtime, never badged official. The pull request adds an optional `McpRegistryAuthConfig::curated_servers` list so a host can supply curated servers at runtime, merged with the compiled-in list, removing the need for a tinymcp release and host version bump to add, correct or remove a curated entry. Runtime entries are listed, searched and described like built-ins but are never badged official, never lead a first search page and never rank as curated; an entry naming a built-in replaces its endpoint and loses the badge. The bus contract takes an additive minor bump to 1.31. No findings were reported by any lane.

Unreviewed paths

  • crates/tinymcp-bus/README.md
  • crates/tinymcp-bus/src/lib.rs
  • crates/tinymcp-bus/src/version/mod_tests.rs
  • crates/tinymcp/src/registry/config_redaction.rs
  • crates/tinymcp/src/registry/config_tests.rs
  • crates/tinymcp/src/registry/ops/mod_tests.rs
  • crates/tinymcp/src/registry/ops/types.rs

Partial review reasons

  • critique: crates/tinymcp-bus/README.md — not selected by the large-review budget
  • critique: crates/tinymcp-bus/src/lib.rs — not selected by the large-review budget
  • security: crates/tinymcp-bus/src/lib.rs — not selected by the large-review budget
  • critique: crates/tinymcp-bus/src/version/mod_tests.rs — not selected by the large-review budget
  • security: crates/tinymcp-bus/src/version/mod_tests.rs — not selected by the large-review budget
  • critique: crates/tinymcp/src/registry/config_redaction.rs — not selected by the large-review budget
  • security: crates/tinymcp/src/registry/config_redaction.rs — not selected by the large-review budget
  • critique: crates/tinymcp/src/registry/config_tests.rs — not selected by the large-review budget
  • security: crates/tinymcp/src/registry/config_tests.rs — not selected by the large-review budget
  • critique: crates/tinymcp/src/registry/ops/mod_tests.rs — not selected by the large-review budget
  • security: crates/tinymcp/src/registry/ops/mod_tests.rs — not selected by the large-review budget
  • critique: crates/tinymcp/src/registry/ops/types.rs — not selected by the large-review budget
  • security: crates/tinymcp/src/registry/ops/types.rs — not selected by the large-review budget

Review snapshot

Change surface Files Review signal Count
Production 12 Active findings 0
Tests 7 Noted findings 0
Documentation 2 Resolved findings 0
Configuration 0 Pending checks/questions 20

Completeness: Incomplete
Test assessment: Test coverage is assessed from changed tests and lane evidence; execution is not claimed without trusted check data.

What changed

tinymcp-bus gains `CuratedServerEntry`, `CuratedEntryTransport` and `CuratedEntryAuth` plus the `curated_servers` field on `McpRegistryAuthConfig` (serde default, omitted when empty, unknown fields refused), re-exported from the crate and documented in the README, with `CONTRACT_VERSION` moved to 1.31. In tinymcp, a new `CuratedCatalog` merges built-ins with validated runtime entries, exposes summary/detail conversion, and centralizes official badging and promotion so only built-ins nobody replaced qualify. Runtime entries are validated once when the registry dispatcher takes the settings (`validated_runtime_entries`), and the merged list is threaded into local-index search, cache fallback, the curated lead on first pages, curated-first ranking and the detail fallback. `docs/specs/runtime-curated-servers.md` records the behaviour and contract. The latest-push delta is unavailable: the review state has the prior reviewed head and rendered evidence, but no trusted base-to-head diff comparison between `3a0898e7a26aab0ba2059289778b49827640a967` and `1f72f34835f1a033f7846999d439ad307bcdde17`.

Features

  • Added — Host-supplied curated servers in `McpRegistryAuthConfig::curated_servers`: A host can add curated servers as configuration rather than requiring a tinymcp release; the field is empty by default and left off the wire when empty. (crates/tinymcp-bus/src/config/types.rs pub struct McpRegistryAuthConfig {, crates/tinymcp-bus/src/config/mod.rs, crates/tinymcp-bus/src/lib.rs pub use audit::{)
  • Added — `CuratedCatalog` merging built-ins with runtime entries: Built-ins come first minus any replaced by a runtime entry, runtime entries follow; only built-ins nobody replaced are treated as promoted, so badge, lead and curated-rank behaviour cannot be claimed by a configuration line. (crates/tinymcp/src/registry/curation/catalog.rs, crates/tinymcp/src/registry/curation/mod.rs)
  • Added — Runtime entry validation (`validated_runtime_entries`): Each entry is checked for blank names, duplicates, and `https` remote/icon URLs with a host and no credentials; bad entries are dropped with a warning naming the entry and reason while the rest load, and an entry replacing a built-in is kept and logged with both URLs. (crates/tinymcp/src/registry/curation/catalog.rs)
  • Added — Entry-to-row conversion (`entry_summary`, `entry_detail`): Runtime entries produce unbadged summary rows with `api_key` auth kind for token auth, and a detail with a single hosted connection and a secret-marked config schema for token auth. (crates/tinymcp/src/registry/curation/catalog.rs, crates/tinymcp/src/registry/curation/catalog_tests.rs)
  • Modified — Local-index search and cache fallback include runtime entries: `index::search` and `fallback::serve_cached` merge catalog entries into matches, and promotion ranking uses `catalog.is_promoted` instead of a built-in lookup, so only unreplaced built-ins rank as curated. (crates/tinymcp/src/registry/sources/official/index.rs pub(super) fn search(, crates/tinymcp/src/registry/sources/official/fallback.rs fn local_matches(store: &Store, query: &str, limit: u32) -> Vec<RegistryServerSu, crates/tinymcp/src/registry/sources/official/fallback.rs fn stale_page()
  • Modified — Validation applied when the dispatcher takes settings: `Registries::with_official` runs `validated_runtime_entries` on the incoming auth, so invalid entries are dropped once at construction with warnings rather than failing open. (crates/tinymcp/src/registry/sources/types.rs impl Registries {)
  • Modified — Contract version bump to 1.31: Hosts built on this bus require a module at 1.31; the new field and payload types are additive. (crates/tinymcp-bus/src/version/mod.rs, crates/tinymcp-bus/src/version/mod_tests.rs use super::{CONTRACT_VERSION, binds, is_compatible};)
  • Added — Specification for runtime curated servers: Documents where entries come from, their shape, validation, the no-promotion rule, and where the merged list is used. (docs/specs/runtime-curated-servers.md, crates/tinymcp-bus/README.md and metadata addresses. The exception is a server whose URL has an origin the)

Tests

  • unit — Asserts the catalog with no runtime entries equals the built-in list, runtime entries are listed but not badged or promoted, a replacement of a built-in drops the badge while other built-ins keep theirs, and bad entries (http, credentials, missing host, bad icon, blank names, duplicates) are dropped while the rest are kept.: Pins the promotion and validation behaviour in `catalog.rs`; execution is not confirmed by trusted check evidence. (crates/tinymcp/src/registry/curation/catalog_tests.rs, crates/tinymcp/src/registry/curation/catalog.rs)
  • unit — Conversion checks for summary/detail of a runtime entry and equivalence of a built-in server's rows via `to_entry` vs `to_summary`/`to_detail`.: Pins that runtime and built-in entries render through the same conversion paths; execution not confirmed. (crates/tinymcp/src/registry/curation/catalog_tests.rs)
  • unit — Pins the shipped contract version to 1.31.: Covers the contract bump; execution not confirmed. (crates/tinymcp-bus/src/version/mod_tests.rs use super::{CONTRACT_VERSION, binds, is_compatible};)
  • unit — Pins the wire form of `curated_servers` (round-trip, absent by default, omitted when empty) and that a misspelled key is refused.: Pins the new bus field's serialization; execution not confirmed. (crates/tinymcp-bus/src/config/mod_tests.rs fn the_stdio_sandbox_defaults_to_net_subprocess_and_the_isolation_floor() {)

Findings

No active actionable findings.

Before merge

  • Complete the critique review for crates/tinymcp-bus/src/lib.rs, crates/tinymcp-bus/README.md, crates/tinymcp/src/registry/ops/types.rs, crates/tinymcp/src/registry/config_redaction.rs, crates/tinymcp-bus/src/version/mod_tests.rs, crates/tinymcp/src/registry/config_tests.rs, crates/tinymcp/src/registry/ops/mod_tests.rs.
  • Complete the security review for crates/tinymcp-bus/src/lib.rs, crates/tinymcp/src/registry/ops/types.rs, crates/tinymcp/src/registry/config_redaction.rs, crates/tinymcp-bus/src/version/mod_tests.rs, crates/tinymcp/src/registry/config_tests.rs, crates/tinymcp/src/registry/ops/mod_tests.rs.
  • Review uncovered paths: crates/tinymcp-bus/README.md, crates/tinymcp-bus/src/lib.rs, crates/tinymcp-bus/src/version/mod_tests.rs, crates/tinymcp/src/registry/config_redaction.rs, crates/tinymcp/src/registry/config_tests.rs, crates/tinymcp/src/registry/ops/mod_tests.rs, crates/tinymcp/src/registry/ops/types.rs.
Agent review details

critique

  • Conclusion: Neutral
  • Scope reviewed: incomplete; unanswered files: crates/tinymcp-bus/src/lib.rs, crates/tinymcp-bus/README.md, crates/tinymcp/src/registry/ops/types.rs, crates/tinymcp/src/registry/config_redaction.rs, crates/tinymcp-bus/src/version/mod_tests.rs, crates/tinymcp/src/registry/config_tests.rs, crates/tinymcp/src/registry/ops/mod_tests.rs
  • Lane summary: Reviewed 6 of 13 files — 7 not reviewed. Reviewed 6 files; 0 findings. 7 files were omitted: not selected by the large-review budget.

security

  • Conclusion: Neutral
  • Scope reviewed: incomplete; unanswered files: crates/tinymcp-bus/src/lib.rs, crates/tinymcp/src/registry/ops/types.rs, crates/tinymcp/src/registry/config_redaction.rs, crates/tinymcp-bus/src/version/mod_tests.rs, crates/tinymcp/src/registry/config_tests.rs, crates/tinymcp/src/registry/ops/mod_tests.rs
  • Lane summary: Reviewed 6 of 12 files — 6 not reviewed. Reviewed 6 files; 0 findings. 6 files were omitted: not selected by the large-review budget. 1 file was not security-reviewed: crates/tinymcp-bus/README.md (prose or tabular data).

tests

  • Conclusion: Success
  • Scope reviewed: all assigned evidence
  • Lane summary: The change wires host-supplied runtime curated servers into the search index merge, the cache fallback, the curated lead, the detail fallback and official badging, and pins the new wire type and contract version. The behaviour that carries the weight — a runtime entry never being promoted, a replacement stripping a built-in's badge, bad entries being dropped — is covered by new tests that fail if those invariants break, and the existing search/fallback tests were updated to pass an empty catalog so their assertions still hold. No reportable defect found; the one thing not visible here is whether openhuman's config file round-trips the new field, which is outside this repository.

commits

  • Conclusion: Success
  • Scope reviewed: all assigned evidence
  • Lane summary: No sensitive content in committed files.

description

  • Conclusion: Success
  • Scope reviewed: all assigned evidence
  • Lane summary: The added commits wire the runtime catalog through every consumer the description names — the re-exports, the version pin, redaction, the badge tagging, the index merge, the cache fallback and the detail fallback — with tests updated for the new parameter and new coverage for the runtime paths. I found no defect in these commits; the behaviour matches what the description claims.
Evidence and run details
  • Models: ladder/vectors-oai3, deepseek-v4.1-flash
  • Spend: $0.006595
  • Tokens: 778552 input · 9944 output · 290048 cached · 825 embedding
  • Updated: 2026-11-11T18:05:27Z
  • Continuity: summary cache chain restarted at the storage ceiling.
Head State Pass summary
838cd11ca7de incomplete 0 active finding(s), 0 resolved finding(s) (at 2026-11-11T13:21:20Z)
3a0898e7a26a incomplete 0 active finding(s), 0 resolved finding(s) (at 2026-11-11T15:29:55Z)
1f72f34835f1 incomplete 0 active finding(s), 0 resolved finding(s) (at 2026-11-11T18:05:27Z)

tinysweeper 0.1.2

@tinysweeper tinysweeper 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.

tinysweeper could not complete coverage (14 unanswered item(s)), so this is not an approval.

Diagnostics

Total spend: $0.0366

# Conflicts:
#	crates/tinymcp-bus/README.md
#	crates/tinymcp-bus/src/version/mod.rs
#	crates/tinymcp-bus/src/version/mod_tests.rs
#	crates/tinymcp/src/registry/sources/official/mod.rs
#	crates/tinymcp/src/registry/sources/official/mod_tests.rs
# Conflicts:
#	crates/tinymcp/src/registry/sources/types.rs
@M3gA-Mind
M3gA-Mind merged commit 4380347 into tinyhumansai:main Nov 11, 2026
20 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature: add curated servers at runtime without a release

1 participant