Discover, govern and control access to MCP servers and agent skills across your organization
27
stars
658
commits
Go
primary language
Sep 8, 2026
updated
Discover, govern, and control access to MCP servers, skills, and plugins across your organization
The ToolHive Registry Server aggregates MCP servers, skills, and plugins from Git repos, Kubernetes clusters, upstream registries, and internal APIs into named catalogs that your teams and AI clients can query. Each catalog has its own access control and audit trail, so you decide which entries are visible to which users -- and have a record of who accessed what.
It implements the official Model Context Protocol (MCP) Registry API specification. If you're not familiar with MCP: it's an open protocol that lets AI assistants connect to external tools and data sources. This server is the governance layer that sits between your MCP infrastructure and the teams consuming it.
Why ToolHive Registry Server? Most MCP setups start with a flat list of servers and no access control. As adoption grows, you need to govern who sees what, aggregate servers from multiple sources, and audit access -- without locking into a proprietary registry. The ToolHive Registry Server is open source, implements the official MCP Registry API spec, and plugs into your existing identity provider, combining multi-tenant claim-based authorization, multi-source aggregation, and SIEM-compliant audit logging in a single service.
Learn more about the ToolHive platform →
# Build the binary
task build
# Run with Git source
thv-registry-api serve --config examples/config-git.yaml
# Run with local file
thv-registry-api serve --config examples/config-file.yaml
The server starts on http://localhost:8080 by default.
# Using Task (recommended - ensures fresh state)
task docker-up
# Or detached mode
task docker-up-detached
# Access the API
curl http://localhost:8080/registry/default/v0.1/servers
# Stop and clean up
task docker-down
Note: The
task docker-upcommand ensures a fresh start by rebuilding the image and clearing all volumes (database + registry data). This prevents stale state issues.
Most organizations have MCP servers, skills, and plugins in more than one place -- a public catalog, an internal Git repo, a Kubernetes cluster running live instances. The Registry Server models this with two primitives: sources (where entries come from) and registries (what consumers query).
A source is a connection to where MCP server, skill, and plugin entries live. It tells the server "go look here for entries." Sources come in five types:
| Type | What it does | Example | Sync |
|---|---|---|---|
| API | Pulls from an upstream registry API | The official MCP Registry at registry.modelcontextprotocol.io | Auto |
| Git | Clones entries from a Git repo | A version-controlled internal catalog | Auto |
| File | Reads from the local filesystem | A curated registry.json on disk | Auto |
| Managed | Entries published via the Admin API | Dynamically registered internal servers | On-demand |
| Kubernetes | Discovers deployed MCP servers | Servers running in your K8s clusters | On-demand |
A registry is a named catalog that aggregates one or more sources into a single consumer-facing endpoint. Each registry can pull from different sources and enforce its own access control via JWT claims. Sources are listed in order -- when the same entry appears in multiple sources, the first source in the list wins.
Why they are separate: Sources and registries have a many-to-many relationship. One source can feed multiple registries, and one registry can pull from multiple sources. This lets you compose different catalogs for different audiences from the same underlying data:
Source: "official-catalog" ──┐
Source: "internal-tools" ──┼──> Registry: "production" (curated, vetted)
│
Source: "internal-tools" ──┼──> Registry: "dev-team" (everything)
Source: "k8s-deployed" ──┘
In this example, the "production" registry only exposes vetted entries from the official catalog and internal tools, while the "dev-team" registry includes everything plus live Kubernetes-discovered servers.
Configuration example:
sources:
- name: official-catalog
api:
endpoint: https://registry.modelcontextprotocol.io
syncPolicy:
interval: "1h"
- name: internal-tools
git:
repository: https://github.com/myorg/mcp-catalog.git
branch: main
path: registry.json
syncPolicy:
interval: "30m"
registries:
- name: production
sources:
- official-catalog
- internal-tools
- name: dev-team
sources:
- internal-tools
See Configuration Guide for complete details.
Fully compatible with the upstream MCP Registry API specification:
GET /registry/{registryName}/v0.1/servers - List servers from a specific registryGET /registry/{registryName}/v0.1/servers/{name}/versions - List all versions of a serverGET /registry/{registryName}/v0.1/servers/{name}/versions/{version} - Get a specific server versionNote: Git, API, File, and Kubernetes sources are read-only through the registry API.
ToolHive-specific endpoints for managing sources, registries, and entries:
Source management (requires manageSources role):
GET /v1/sources - List all configured sourcesGET /v1/sources/{name} - Get a source by namePUT /v1/sources/{name} - Create or update a sourceDELETE /v1/sources/{name} - Delete a sourceGET /v1/sources/{name}/entries - List entries for a sourceRegistry management (reads: authenticated; writes require manageRegistries role):
GET /v1/registries - List all configured registries with statusGET /v1/registries/{name} - Get registry details and sync statusGET /v1/registries/{name}/entries - List entries for a registry (requires manageRegistries role)PUT /v1/registries/{name} - Create or update a registryDELETE /v1/registries/{name} - Delete a registryEntry management (requires manageEntries role):
POST /v1/entries - Publish a server, skill, or plugin entryDELETE /v1/entries/{type}/{name}/versions/{version} - Delete a published entryPUT /v1/entries/{type}/{name}/claims - Update entry claimsRead-only endpoints for discovering skills within a registry:
GET /registry/{registryName}/v0.1/x/dev.toolhive/skills - List skills (paginated)GET /registry/{registryName}/v0.1/x/dev.toolhive/skills/{namespace}/{name} - Get latest version of a skillGET /registry/{registryName}/v0.1/x/dev.toolhive/skills/{namespace}/{name}/versions - List all versions of a skillGET /registry/{registryName}/v0.1/x/dev.toolhive/skills/{namespace}/{name}/versions/{version} - Get a specific skill versionRead-only endpoints for discovering plugins within a registry:
GET /registry/{registryName}/v0.1/x/dev.toolhive/plugins - List plugins (paginated)GET /registry/{registryName}/v0.1/x/dev.toolhive/plugins/{namespace}/{name} - Get latest version of a pluginGET /registry/{registryName}/v0.1/x/dev.toolhive/plugins/{namespace}/{name}/versions - List all versions of a pluginGET /registry/{registryName}/v0.1/x/dev.toolhive/plugins/{namespace}/{name}/versions/{version} - Get a specific plugin versionGET /health - Health checkGET /readiness - Readiness checkGET /version - Version informationGET /v1/me - Returns the caller's identity and rolesGET /.well-known/oauth-protected-resource - OAuth discovery (RFC 9728)See the MCP Registry API specification for full API details.
All configuration is done via YAML files. The server requires a --config flag.
sources:
- name: local
file:
path: /data/registry.json
registries:
- name: my-registry
sources:
- local
auth:
mode: anonymous # Use "oauth" for production
database:
host: localhost
port: 5432
user: registry
database: registry
The Registry Server can be deployed standalone or as part of the full ToolHive platform. Together, the platform components cover the full MCP lifecycle:
See the ToolHive documentation for the complete platform architecture.
We welcome contributions! See the Contributing guide to get started, including development setup, build commands, architecture overview, and project structure.
This project is licensed under the Apache 2.0 License.
Part of the ToolHive project - Simplify and secure MCP servers
Go
99.4%
Discover, govern and control access to MCP servers and agent skills across your organization
27
stars
658
commits
Go
primary language
Sep 8, 2026
updated
Discover, govern, and control access to MCP servers, skills, and plugins across your organization
The ToolHive Registry Server aggregates MCP servers, skills, and plugins from Git repos, Kubernetes clusters, upstream registries, and internal APIs into named catalogs that your teams and AI clients can query. Each catalog has its own access control and audit trail, so you decide which entries are visible to which users -- and have a record of who accessed what.
It implements the official Model Context Protocol (MCP) Registry API specification. If you're not familiar with MCP: it's an open protocol that lets AI assistants connect to external tools and data sources. This server is the governance layer that sits between your MCP infrastructure and the teams consuming it.
Why ToolHive Registry Server? Most MCP setups start with a flat list of servers and no access control. As adoption grows, you need to govern who sees what, aggregate servers from multiple sources, and audit access -- without locking into a proprietary registry. The ToolHive Registry Server is open source, implements the official MCP Registry API spec, and plugs into your existing identity provider, combining multi-tenant claim-based authorization, multi-source aggregation, and SIEM-compliant audit logging in a single service.
Learn more about the ToolHive platform →
# Build the binary
task build
# Run with Git source
thv-registry-api serve --config examples/config-git.yaml
# Run with local file
thv-registry-api serve --config examples/config-file.yaml
The server starts on http://localhost:8080 by default.
# Using Task (recommended - ensures fresh state)
task docker-up
# Or detached mode
task docker-up-detached
# Access the API
curl http://localhost:8080/registry/default/v0.1/servers
# Stop and clean up
task docker-down
Note: The
task docker-upcommand ensures a fresh start by rebuilding the image and clearing all volumes (database + registry data). This prevents stale state issues.
Most organizations have MCP servers, skills, and plugins in more than one place -- a public catalog, an internal Git repo, a Kubernetes cluster running live instances. The Registry Server models this with two primitives: sources (where entries come from) and registries (what consumers query).
A source is a connection to where MCP server, skill, and plugin entries live. It tells the server "go look here for entries." Sources come in five types:
| Type | What it does | Example | Sync |
|---|---|---|---|
| API | Pulls from an upstream registry API | The official MCP Registry at registry.modelcontextprotocol.io | Auto |
| Git | Clones entries from a Git repo | A version-controlled internal catalog | Auto |
| File | Reads from the local filesystem | A curated registry.json on disk | Auto |
| Managed | Entries published via the Admin API | Dynamically registered internal servers | On-demand |
| Kubernetes | Discovers deployed MCP servers | Servers running in your K8s clusters | On-demand |
A registry is a named catalog that aggregates one or more sources into a single consumer-facing endpoint. Each registry can pull from different sources and enforce its own access control via JWT claims. Sources are listed in order -- when the same entry appears in multiple sources, the first source in the list wins.
Why they are separate: Sources and registries have a many-to-many relationship. One source can feed multiple registries, and one registry can pull from multiple sources. This lets you compose different catalogs for different audiences from the same underlying data:
Source: "official-catalog" ──┐
Source: "internal-tools" ──┼──> Registry: "production" (curated, vetted)
│
Source: "internal-tools" ──┼──> Registry: "dev-team" (everything)
Source: "k8s-deployed" ──┘
In this example, the "production" registry only exposes vetted entries from the official catalog and internal tools, while the "dev-team" registry includes everything plus live Kubernetes-discovered servers.
Configuration example:
sources:
- name: official-catalog
api:
endpoint: https://registry.modelcontextprotocol.io
syncPolicy:
interval: "1h"
- name: internal-tools
git:
repository: https://github.com/myorg/mcp-catalog.git
branch: main
path: registry.json
syncPolicy:
interval: "30m"
registries:
- name: production
sources:
- official-catalog
- internal-tools
- name: dev-team
sources:
- internal-tools
See Configuration Guide for complete details.
Fully compatible with the upstream MCP Registry API specification:
GET /registry/{registryName}/v0.1/servers - List servers from a specific registryGET /registry/{registryName}/v0.1/servers/{name}/versions - List all versions of a serverGET /registry/{registryName}/v0.1/servers/{name}/versions/{version} - Get a specific server versionNote: Git, API, File, and Kubernetes sources are read-only through the registry API.
ToolHive-specific endpoints for managing sources, registries, and entries:
Source management (requires manageSources role):
GET /v1/sources - List all configured sourcesGET /v1/sources/{name} - Get a source by namePUT /v1/sources/{name} - Create or update a sourceDELETE /v1/sources/{name} - Delete a sourceGET /v1/sources/{name}/entries - List entries for a sourceRegistry management (reads: authenticated; writes require manageRegistries role):
GET /v1/registries - List all configured registries with statusGET /v1/registries/{name} - Get registry details and sync statusGET /v1/registries/{name}/entries - List entries for a registry (requires manageRegistries role)PUT /v1/registries/{name} - Create or update a registryDELETE /v1/registries/{name} - Delete a registryEntry management (requires manageEntries role):
POST /v1/entries - Publish a server, skill, or plugin entryDELETE /v1/entries/{type}/{name}/versions/{version} - Delete a published entryPUT /v1/entries/{type}/{name}/claims - Update entry claimsRead-only endpoints for discovering skills within a registry:
GET /registry/{registryName}/v0.1/x/dev.toolhive/skills - List skills (paginated)GET /registry/{registryName}/v0.1/x/dev.toolhive/skills/{namespace}/{name} - Get latest version of a skillGET /registry/{registryName}/v0.1/x/dev.toolhive/skills/{namespace}/{name}/versions - List all versions of a skillGET /registry/{registryName}/v0.1/x/dev.toolhive/skills/{namespace}/{name}/versions/{version} - Get a specific skill versionRead-only endpoints for discovering plugins within a registry:
GET /registry/{registryName}/v0.1/x/dev.toolhive/plugins - List plugins (paginated)GET /registry/{registryName}/v0.1/x/dev.toolhive/plugins/{namespace}/{name} - Get latest version of a pluginGET /registry/{registryName}/v0.1/x/dev.toolhive/plugins/{namespace}/{name}/versions - List all versions of a pluginGET /registry/{registryName}/v0.1/x/dev.toolhive/plugins/{namespace}/{name}/versions/{version} - Get a specific plugin versionGET /health - Health checkGET /readiness - Readiness checkGET /version - Version informationGET /v1/me - Returns the caller's identity and rolesGET /.well-known/oauth-protected-resource - OAuth discovery (RFC 9728)See the MCP Registry API specification for full API details.
All configuration is done via YAML files. The server requires a --config flag.
sources:
- name: local
file:
path: /data/registry.json
registries:
- name: my-registry
sources:
- local
auth:
mode: anonymous # Use "oauth" for production
database:
host: localhost
port: 5432
user: registry
database: registry
The Registry Server can be deployed standalone or as part of the full ToolHive platform. Together, the platform components cover the full MCP lifecycle:
See the ToolHive documentation for the complete platform architecture.
We welcome contributions! See the Contributing guide to get started, including development setup, build commands, architecture overview, and project structure.
This project is licensed under the Apache 2.0 License.
Part of the ToolHive project - Simplify and secure MCP servers
Go
99.4%