Skip to content

Federation & the aggregator

Federation turns the registry into your organization’s single MCP endpoint: the aggregator pulls records from every enabled connection and serves them next to your own publications, tagged with provenance.

A connection is an upstream registry: a base URL plus optional bearer/API-key credential. All connection routes require authentication; stored tokens are returned masked (***).

Terminal window
# Create
curl -X POST http://localhost:5001/v0/connections \
-H "Authorization: Bearer $REGISTRY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "Partner Registry", "url": "https://registry.partner.example",
"auth_type": "bearer", "auth_token": "pt-xxxx", "enabled": true}'
# Test reachability (existing or ad-hoc)
curl -X POST http://localhost:5001/v0/connections/{id}/test \
-H "Authorization: Bearer $REGISTRY_TOKEN"

Cross-registry search without importing: POST /v0/connections/search-all queries every enabled connection live and tags each result with its source registry.

Federation normally requires the upstream to speak the official registry API — with one built-in exception: Smithery (registry.smithery.ai, 11,000+ community servers) is supported through a hostname-detected adapter that translates its API into official server documents. A Smithery connection ships seeded but disabled; enabling it federates the full catalog under the synthetic ai.smithery/* namespace on the next sync. It works without credentials, but Smithery then serves only its top 500 servers — add a bearer API key from smithery.ai/console/api-keys to sync the full catalog. Smithery has no incremental protocol, so each sync is a full pass with tombstoning, and imported records keep Smithery’s createdAt as their created date.

With AGGREGATOR_ENABLED=true the scheduler runs every AGGREGATOR_INTERVAL_SECONDS (default 3600, first run ~15 s after boot); the CLI’s sync subcommand runs the same cycle on demand.

Per enabled connection the aggregator:

  1. Walks the upstream’s /v0.1/servers with cursor pagination, passing updated_since=<high-water mark> after the first full pass — so steady-state syncs transfer only what changed.
  2. Sanitizes each record (unknown package registry types or remote transports are dropped per item, never per server — an upstream vocabulary addition can’t knock out your catalog).
  3. Upserts under the connection’s provenance (source_connection_id), preserving locally-accrued state: download counters, verification, icons. The record’s created date is the upstream’s publication date (publishedAt; Smithery’s createdAt), not the moment the aggregator first saw it.
  4. On a full pass, tombstones local copies the upstream no longer serves — removals propagate, but only when the pass actually covered everything. Every imported record keeps its provenance: listings serve a source_registry field with the connection it was federated from, and the Console labels such servers via <registry>.
  5. Records the outcome on the connection (last_synced_at, high-water mark, error text on failure) — visible in the Console dashboard.

Everything the aggregator relies on is also what this registry serves, so other Brutor registries (or any spec-compliant consumer) can federate from you:

  • GET /v0.1/servers?updated_since=2026-08-01T00:00:00Z — incremental walk, ordered by update time. When updated_since is used, deleted servers are included automatically as tombstones (their official _meta carries status: "deleted"), so downstream mirrors converge.
  • include_deleted=true — explicit tombstone visibility on any listing.
  • Opaque cursors — metadata.nextCursor on every page.