MCP server governance starts with discovery

When MCP adoption takes off inside an organization, the governance problems arrive fast.

They all trace back to the same gap: there’s no authoritative place to look up which MCP servers exist, who approved them, and who’s allowed to use them.

Here’s what you’ll learn in this post:

  • Why a shared list of MCP server URLs isn’t a governance model
  • How Stacklok’s Registry Server aggregates multiple source types behind a single endpoint
  • How claims-based authorization gives each user a personalized catalog from one registry
  • Why filtering at the API layer matters for agentic workflows

The Stacklok Registry Server addresses all of this. Platform teams get a single deployment, backed by one Postgres database and one Kubernetes resource, that aggregates MCP servers from multiple sources, exposes them through a standards-compliant API, and enforces per-user access control based on identity claims. Each user sees only the tools their role allows, and that filtering happens at the API layer so it applies to AI agents working on their behalf too, not just the UI.

We also recorded a demo that walks through all of this live. See the video at the end of this post.


The problem: MCP servers don’t govern themselves

MCP server discovery right now is mostly a manual, social process. You install a server someone recommended, or find it in a public catalog, or copy a URL out of a Slack thread. That’s fine for individual experimentation, but it breaks down the moment you have a platform team responsible for making sure people across the organization are using vetted, approved tools.

Three specific problems compound each other.

No canonical source of truth. When server URLs live in docs, wikis, or chat threads, there’s no way to know whether the list is current, which entries are officially sanctioned, or whether the same server appears under five different names in five different places.

One catalog fits nobody. A raw public catalog might have over a hundred MCP servers. A finance analyst needs Stripe and PayPal. A platform engineer needs Kubernetes management and infrastructure tooling. Neither needs the other’s tools, but a single shared list puts everything in front of everyone. That’s friction for users and a headache for security teams trying to reason about blast radius.

AI agents follow the same discovery paths users do. This is the problem that matters most in agentic workflows. If a tool is discoverable, an AI agent working on a user’s behalf can find and invoke it, even if the user would never have reached for it directly. Hiding tools from the UI isn’t enough; the access control has to live at the API.


The solution: a registry that knows who’s asking

The Stacklok Registry Server is a Kubernetes-native service that addresses all three problems with two mechanisms: multi-source aggregation and claims-based authorization.

Deploying the registry

On a Kubernetes cluster with the Stacklok operator installed, you deploy the Registry Server by creating an MCPRegistry resource. The operator provisions the API deployment, initializes the database, and runs the initial source sync.

The core of the configuration is a configYAML block embedded in the resource. Here’s the minimal form, using a Git repository as the catalog source:

configYAML: |
  sources:
    - name: toolhive
      format: upstream
      git:
        repository: https://github.com/stacklok/toolhive-catalog.git
        branch: main
        path: pkg/catalog/toolhive/data/registry-upstream.json
      syncPolicy:
        interval: "15m"

  registries:
    - name: demo-registry
      sources:
        - toolhive

  auth:
    mode: anonymous

Once applied, the registry syncs the catalog and starts serving the standard MCP Registry API. You’ve got a functional registry at that point, but every user sees the same full catalog. That’s a reasonable starting point, not a finished governance model.

Multi-source aggregation

The registry can pull from multiple source types at the same time. In the demo, we configure three alongside each other:

  • A Git source, pointing at the Stacklok-curated catalog repository. Git sources support branch, tag, or commit pinning and sync on a configurable interval.
  • An upstream API source, consuming the public community MCP registry at registry.modelcontextprotocol.io. The Registry Server implements the MCP Registry API spec, so it can act as both a source consumer and a source for a downstream registry, which is handy in layered or federated environments.
  • A Kubernetes discovery source, which watches the cluster for MCPServer, MCPRemoteProxy, and VirtualMCPServer resources that have opted in to registry exposure.

The filter field keeps things manageable. Rather than syncing every server from the upstream community registry, you include exactly the entries you want:

- name: community
  format: upstream
  api:
    endpoint: https://registry.modelcontextprotocol.io
  syncPolicy:
    interval: "1h"
  filter:
    names:
      include:
        - com.figma.mcp/mcp
        - com.gitlab/mcp
        - com.postman/postman-mcp-server

For Kubernetes-native servers, opt-in happens through annotations on the MCPServer resource. The registry-export annotation enables discovery; the others supply catalog metadata:

annotations:
  toolhive.stacklok.dev/registry-export: "true"
  toolhive.stacklok.dev/registry-url: https://$MCP_HOSTNAME/mkp/mcp
  toolhive.stacklok.dev/registry-title: "Kubernetes MCP Server"
  toolhive.stacklok.dev/registry-description: Manage this Kubernetes cluster.

As soon as the annotated resource is applied, it shows up in the registry with no manual registration step needed.

Claims-based authorization

This is where the real work happens for enterprise deployments.

When you switch the registry from anonymous to OAuth authentication, it starts validating user JWT tokens on every API request. Roles and source-level claims are checked against those tokens to determine what each caller can see.

A source with a claims block is only visible to users whose token satisfies those claims:

sources:

  # Shared tools — visible to all authenticated users
  - name: toolhive-shared
    format: upstream
    git:
      repository: https://github.com/stacklok/toolhive-catalog.git
      branch: main
      path: pkg/catalog/toolhive/data/registry-upstream.json
    filter:
      names:
        include:
          - io.github.stacklok/notion-remote
          - io.github.stacklok/time
    claims:
      groups: everyone

  # Engineering tools — restricted to the engineering group
  - name: toolhive-engineering
    ...
    filter:
      names:
        include:
          - io.github.stacklok/aws-documentation
          - io.github.stacklok/playwright
    claims:
      groups: engineering

  # Finance tools — restricted to the finance group
  - name: toolhive-finance
    ...
    filter:
      names:
        include:
          - io.github.stacklok/stripe-remote
          - io.github.stacklok/paypal
    claims:
      groups: finance

# A registry entry rolls up the aggregated sources
  registries:
    - name: authenticated-registry
      sources:
        - toolhive-shared
        - toolhive-engineering
        - toolhive-finance
      claims:
        groups: everyone

For Kubernetes-native servers, the same mechanism works through an annotation:

toolhive.stacklok.dev/authz-claims: '{"groups": "engineering"}'

The authorization section of the config connects the registry to your identity provider. We used Keycloak in the demo, but Okta, Entra ID, or any OIDC-compliant IdP works the same way:

auth:
  mode: oauth
  oauth:
    resourceUrl: https://registry.example.com
    providers:
      - name: keycloak
        issuerUrl: https://auth.example.com/realms/your-realm
        audience: toolhive-registry-server
  authz:
    roles:
      superAdmin:
        - preferred_username: admin

Three different users, three different catalog views, one registry. Alice in engineering sees Playwright, AWS docs, and the Kubernetes server she manages. Bob in finance sees Stripe and PayPal. Everyone sees the shared tools, and nobody can see tools outside their group, including AI agents working on their behalf. The filtering is applied at the API before any data leaves the server.


What this looks like in practice

The demo walks through all three stages of this setup live: deploying the registry from scratch, adding multiple sources, and then switching on claims-based auth to show how the catalog changes per user.

If you’re evaluating how to govern MCP server access at scale, the Registry Server is designed to plug into your existing Kubernetes infrastructure and identity provider without adding a separate system to maintain. The Registry Server quickstart is the fastest way to get a registry running.


Want to see what Stacklok can do for your organization? Book a demo or get started right away with ToolHive, our open source project. Join the conversation and engage directly with our team on Discord.

May 11, 2026

How-To

Dan Barr

Dan Barr

Senior Technical Marketing Engineer

Dan Barr is a Senior Technical Marketing Engineer and the primary architect of Stacklok's top-notch docs, tutorials, how-to guides and more that help customers and users navigate all things MCP.

More by Dan Barr