Skip to main content

MCP Registry

Otoroshi can publish your governed MCP virtual servers to the standard MCP registry format, so that registry-aware MCP clients in your organization discover the sanctioned servers automatically — and connect through the gateway (so OAuth and the Zero-Trust controls apply end to end).

It is the difference between "a pile of connection configs" and "a curated, approved, browsable, versioned catalogue of sanctioned MCP capabilities".

How it works

A registry is essentially a list of server.json documents, one per MCP server. In Otoroshi a registry-server maps 1:1 to a virtual server: the server.json is a projection of the virtual server. There is no separate entity — publication is a small block of metadata on the virtual server itself.

Publishing is a single switch on the virtual server, governed by Otoroshi's roles/RBAC: a server appears in the catalogue when you flip published, and you can mark it deprecated without removing it. That switch is your approval gate — nothing reaches consumers until you say so.

Run several registries, each a curated slice

A registry is just a route with the API plugin, so you can stand up as many as you like — each exposing a different, curated subset of your published servers. The Expose setting on the registry API (and the preset) decides what a given registry serves:

ModeServes
All published servers (default)every published server
Selected servers (by ref)only the virtual servers you pick
By tagevery published server carrying any of the chosen tags
Route's tenantevery published server in the route's tenant

So one route can be your org-wide catalogue, another a prod-only registry by tag, and a per-team registry falls out naturally from multi-tenancy — the same servers, behind different governed front doors. Selection always composes with publication: a server still has to be published to appear anywhere.

The registry block

Configured on the MCP Virtual Server entity (entity-level metadata, not a per-route override):

FieldTypeDefaultDescription
publishedbooleanfalseList this server in the registry endpoints. This is the approval gate.
namestringReverse-DNS namespaced name (e.g. io.acme/github). Defaults to a slug of the server name (io.cloud-apim/<slug>).
versionstring1.0.0Semantic version advertised in server.json.
titlestringHuman-readable title. Defaults to the server name.
urlstringPublic streamable-http URL exposed for this server (the server.json remote). The editor has a "Detect from route" assistant that scans the route(s) exposing this server, suggests the URL and shows the detected auth (OAuth / apikey / mTLS) — you confirm or override. If empty, no remote is published (clients still discover auth via the server's own .well-known).
deprecatedbooleanfalseMarks the registry status as deprecated while keeping the entry listed.

The server.json projection

A published server is projected to the official server.json format (schema 2025-12-11). The server.json itself has no status field — the registry layer adds it under the _meta envelope:

{
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
"name": "io.acme/github",
"description": "Hardened GitHub MCP via Otoroshi",
"title": "GitHub",
"version": "1.0.0",
"remotes": [{ "type": "streamable-http", "url": "https://gw.acme/mcp/github" }],
"_meta": {
"io.modelcontextprotocol.registry/official": { "status": "active", "isLatest": true },
"com.cloud-apim.otoroshi/governance": { "id": "mcp-virtual-server_xxx", "tags": ["platform"] }
}
}
  • name / version / title come from the registry block (with the slug / entity-name fallbacks).
  • remotes is emitted only when url is set; the type is always streamable-http.
  • status is active, or deprecated when registry.deprecated is on.
  • Governance metadata (entity id, tags) is added under our own reverse-DNS _meta key, which does not break the standard.

One-click setup — the registry preset

The simplest way to expose the registry is the Cloud APIM - MCP Registry preset. Add it to a route and it wires both plugins at once:

OptionDefaultWires
well_known_path/.well-known/mcp-registrythe discovery document
api_base_path/v0the registry API on /v0/.*
registry_urlbase URL advertised by the discovery doc (defaults to this host + base path)
schema_version2025-12-11the server.json schema version

So out of the box the discovery doc is served on /.well-known/mcp-registry and the API on /v0/servers. If you'd rather wire the plugins by hand, the two are described below.

Exposing the registry — two plugins

Two plugins serve the registry — mount them on a route on your gateway. The catalogue is governed end to end: only enabled, published servers are ever served, so your approval gate decides exactly what consumers can discover.

Cloud APIM - MCP Registry API

Serves the standard registry REST API. Put it on a route matching your registry base path (e.g. /v0/servers):

  • GET /v0/servers — the listing, cursor-paginated:
    {
    "servers": [ { "name": "io.acme/github", "version": "1.0.0", "...": "..." } ],
    "metadata": { "count": 1 }
    }
    Pages hold up to 200 servers by default — plenty for a curated catalogue, so most deployments get everything in one call. Pass ?limit= to change the page size. When more servers remain, the response carries a metadata.next_cursor; fetch the next page with ?cursor=<value>. It's standard cursor pagination, so registry-aware clients walk the whole catalogue automatically.
  • GET /v0/servers/{name} — a single server by its (possibly namespaced) name, e.g. GET /v0/servers/io.acme/github. Returns the server.json, or 404 if it is unknown or not published.

Cloud APIM - MCP Registry discovery (.well-known)

Serves a small discovery document pointing clients at the registry API. Put it on your well-known path.

{
"registry": "https://gw.acme/v0",
"servers_endpoint": "https://gw.acme/v0/servers",
"schema_version": "2025-12-11",
"server_json_schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json"
}
tip

The discovery path is configurable on the route, so you can serve it wherever your clients expect to find it.

End-to-end flow

An admin approves GitHub (a virtual server) by setting registry.published = true → the registry lists it as a server.json (io.acme/github, remote https://gw.acme/mcp/github) → any registry-aware MCP client in the company discovers it → connects through the gateway → governed + Zero-Trust-protected end to end.

The discovery endpoint funnels clients onto the governed path: instead of each team hand-configuring connections, a client just needs the registry URL and auto-discovers every sanctioned server (with its auth requirements).