ZuploZuplo
LoginStart for Free
  • Documentation
  • API Reference
Getting Started
Concepts
API Management
AI Gateway
MCP Gateway
    Overview
    Getting Started
      How it works
      Connect MCP clients
      Authentication
      Cross App Access
      Configuration
      Policies
      Observability
      ReferenceServer RegistryTroubleshooting
    MCP Server
    Developer Portal
    Development
    Deploying & Source Control
    Analytics
    Observability
    Networking & Infrastructure
    Account Management
    Programming API
    Build with AI
    Zuplo CLI
    Migration Guides
    Platform LimitsVersion Support PolicySecuritySupportTrust & ComplianceChangelog
    powered by Zuplo
    MCP Gateway

    MCP Server Registry

    The MCP Gateway serves a read-only MCP Server Registry API (v0.1 freeze) that advertises every MCP route on the gateway. MCP clients and mirroring subregistries can discover the gateway's registered servers without authentication, per the registry specification.

    The registry is enabled by default and mounted at /__zuplo/mcp-registry (with the default basePath). Configure or disable it through the registry option on McpGatewayPlugin.

    What gets listed

    The registry projects one entry per MCP-serving route — both:

    • Gateway virtual servers — routes that carry MCP gateway policies (mcp-oauth-inbound / mcp-token-exchange-inbound) and use McpProxyHandler to proxy to an upstream MCP server.
    • Standalone MCP servers — routes that use the built-in mcpServerHandler or a bare McpProxyHandler without gateway policies.

    Each entry includes:

    FieldSource
    name<reverse-DNS of request host>/<operationId> (for example, com.example.gateway/linear-mcp-server)
    remotesThe gateway route URL, using the streamable-http transport.
    descriptionOpenAPI operation description or summary, clamped to 100 code points per the spec.
    titlemcpServerHandler options or the OpenAPI operation summary.
    versionmcpServerHandler options or upstream connection config. Range-like values (^1.2.3, 1.x) project as 0.0.0.
    websiteUrlUpstream connection config, canonicalized to a valid URI.
    iconsUpstream connection config. Only HTTPS URLs are included; src is clamped to 255 characters.

    Server names are derived from the request host — the same posture as the OAuth issuer and Protected Resource Metadata. Names vary with the hostname the gateway is reached on, so a custom domain produces different names than the default *.zuplo.dev origin.

    The projection never throws. Every spec constraint is enforced by sanitizing or omitting: names longer than 200 characters are truncated with a hash suffix, descriptions are clamped, non-HTTPS icons are dropped, and version ranges are replaced with 0.0.0. One malformed route can't take down discovery for the rest.

    Parameterized routes (for example, /mcp/{server}) are omitted from the directory — a templated path is not a concretely connectable remote.

    Endpoints

    All paths are relative to the registry mount (default: /__zuplo/mcp-registry). Discovery GETs are unauthenticated and CORS-permissive (Access-Control-Allow-Origin: *).

    GET {path}/v0.1/servers

    Lists all MCP servers registered on the gateway.

    Query parameterTypeDefaultDescription
    cursorstring—Opaque pagination cursor from a previous response.
    limitinteger30Maximum servers to return. Clamped to 100.
    searchstring—Case-insensitive substring filter on server name.
    versionstring—Filter to servers matching a specific version.
    updated_sincestring—RFC 3339 date-time. Validated but never filters — every entry conservatively counts as changed.

    Response:

    Code
    { "servers": [ { "name": "com.example.gateway/linear-mcp-server", "description": "Linear MCP proxy", "title": "Linear", "version": "1.0.0", "remotes": [ { "type": "streamable-http", "url": "https://gateway.example.com/mcp/linear-v1" } ], "websiteUrl": "https://linear.app", "icons": [] } ], "metadata": { "count": 1 } }

    When cursor is present in the response, more results are available. Pass it back as the cursor query parameter on the next request.

    GET {path}/v0.1/servers/{serverName}/versions

    Lists versions for a single server. With the current read-only projection, every server has exactly one version entry.

    {serverName} is URL-encoded — the slash in the reverse-DNS name is sent as %2F (for example, com.example.gateway%2Flinear-mcp-server).

    GET {path}/v0.1/servers/{serverName}/versions/{version}

    Returns a single server version. The special alias latest resolves to the server's current version.

    Write endpoints (refused)

    The registry is read-only. Write endpoints are refused per the spec:

    EndpointMethodStatusReason
    {path}/v0.1/publishPOST501Spec marks publishing optional and documents 501.
    {path}/v0.1/servers/{serverName}/versions/{version}PUT501Spec marks version update optional.
    {path}/v0.1/servers/{serverName}/versions/{version}DELETE501Spec marks version deletion optional.
    {path}/v0.1/servers/{serverName}/versions/{version}/statusPATCH403Spec defines no 501 for status operations; returns 403 with a permissions error message.
    {path}/v0.1/servers/{serverName}/statusPATCH403Same as above.

    All error bodies use the spec's {"error": "..."} shape — not RFC 7807 problem details — so off-the-shelf registry clients can parse them. A catch-all under the mount ensures even unrecognized requests get the spec-shaped 404.

    Configuration

    The registry is configured through the McpGatewayPlugin constructor. See the registry option for the full options reference.

    Code
    import { RuntimeExtensions } from "@zuplo/runtime"; import { McpGatewayPlugin } from "@zuplo/runtime/mcp-gateway"; export function runtimeInit(runtime: RuntimeExtensions) { runtime.addPlugin( new McpGatewayPlugin({ registry: { enabled: true, // default path: "/mcp-registry", // default: "{basePath}/mcp-registry" }, }), ); }

    Limitations

    • No publishing. The registry is a read-only projection of the gateway's live route configuration. There is no write path, no namespace-ownership model, and no stored publishedAt or updatedAt timestamps.
    • updated_since validates but never filters. Because the registry is derived from route config with no stored timestamps, every entry conservatively counts as changed. This keeps mirroring subregistries correct at the cost of re-reading everything.
    • No deployment-pinned server identity. Server names are derived from the request host, not from a stable deployment-level identifier.

    Related

    • McpGatewayPlugin reference — the full plugin options, including basePath and registry.
    • Gateway reference — the full URL catalog, including the registry mount.
    • How the MCP Gateway works — architecture and request lifecycle.
    • MCP Server Registry specification — the v0.1 freeze the gateway implements.
    Edit this page
    Last modified on August 20, 2026
    ReferenceTroubleshooting
    On this page
    • What gets listed
    • Endpoints
      • GET {path}/v0.1/servers
      • GET {path}/v0.1/servers/{serverName}/versions
      • GET {path}/v0.1/servers/{serverName}/versions/{version}
      • Write endpoints (refused)
    • Configuration
    • Limitations
    • Related
    JSON
    TypeScript