A standards-compliant MCP Registry API server for ToolHive
The ToolHive Registry API (thv-registry-api) implements the official Model Context Protocol (MCP) Registry API specification. It provides a standardized REST API for discovering and accessing MCP servers from multiple backend sources.
- Standards-compliant: Implements the official MCP Registry API specification
- Multiple data sources: Git repositories, API endpoints, and local files
- Automatic synchronization: Background sync with configurable intervals and retry logic
- Container-ready: Designed for deployment in Kubernetes clusters
- Flexible deployment: Works standalone or as part of ToolHive infrastructure
- Production-ready: Built-in health checks, graceful shutdown, and sync status persistence
- Go 1.23 or later
- Task for build automation
# Build the binary
task buildAll configuration is done via YAML configuration files. See the examples/ directory for sample configurations.
Quick start with Git source:
thv-registry-api serve --config examples/config-git.yamlWith local file:
thv-registry-api serve --config examples/config-file.yamlWith API endpoint:
thv-registry-api serve --config examples/config-api.yamlThe server starts on port 8080 by default. Use --address :PORT to customize.
What happens when the server starts:
- Loads configuration from the specified YAML file
- Immediately fetches registry data from the configured source
- Starts background sync coordinator for automatic updates
- Serves MCP Registry API endpoints on the configured address
For detailed configuration options and examples, see the examples/README.md.
The server implements the standard MCP Registry API:
GET /api/v0/servers- List all available MCP serversGET /api/v0/servers/{name}- Get details for a specific serverGET /api/v0/deployed- List deployed server instances (Kubernetes only)GET /api/v0/deployed/{name}- Get deployed instances of a specific server
See the MCP Registry API specification for full API details. Note: The current implementation is not strictly compliant with the standard. The deviations will be fixed in the next iterations.
All configuration is done via YAML files. The server requires a --config flag pointing to a YAML configuration file.
# Registry name/identifier (optional, defaults to "default")
registryName: my-registry
# Data source configuration (required)
source:
# Source type: git, api, or file
type: git
# Data format: toolhive (native) or upstream (MCP registry format)
format: toolhive
# Source-specific configuration
git:
repository: https://github.com/stacklok/toolhive.git
branch: main
path: pkg/registry/data/registry.json
# Automatic sync policy (required)
syncPolicy:
# Sync interval (e.g., "30m", "1h", "24h")
interval: "30m"
# Optional: Server filtering
filter:
names:
include: ["official/*"]
exclude: ["*/deprecated"]
tags:
include: ["production"]
exclude: ["experimental"]| Flag | Description | Required | Default |
|---|---|---|---|
--config |
Path to YAML configuration file | Yes | - |
--address |
Server listen address | No | :8080 |
The server supports three data source types:
-
Git Repository - Clone and sync from Git repositories
- Supports branch, tag, or commit pinning
- Ideal for version-controlled registries
- Example: config-git.yaml
-
API Endpoint - Sync from upstream MCP Registry APIs
- Supports federation and aggregation scenarios
- Format conversion from upstream to ToolHive format
- Example: config-api.yaml
-
Local File - Read from filesystem
- Ideal for local development and testing
- Supports mounted volumes in containers
- Example: config-file.yaml
For complete configuration examples and advanced options, see examples/README.md.
# Build the binary
task build
# Run linting
task lint
# Fix linting issues automatically
task lint-fix
# Run tests
task test
# Generate mocks
task gen
# Build container image
task build-imagecmd/thv-registry-api/
├── api/ # REST API implementation
│ └── v1/ # API v1 handlers and routes
├── app/ # CLI commands and application setup
├── internal/service/ # Legacy service layer (being refactored)
│ ├── file_provider.go # File-based registry provider
│ ├── k8s_provider.go # Kubernetes provider
│ └── service.go # Core service implementation
└── main.go # Application entry point
pkg/
├── config/ # Configuration loading and validation
├── sources/ # Data source handlers
│ ├── git.go # Git repository source
│ ├── api.go # API endpoint source
│ ├── file.go # File system source
│ ├── factory.go # Source handler factory
│ └── storage_manager.go # Storage abstraction
├── sync/ # Sync manager and coordination
│ └── manager.go # Background sync logic
└── status/ # Sync status tracking
└── persistence.go # Status file persistence
examples/ # Example configurations
The server follows a clean architecture pattern with the following layers:
- API Layer (
cmd/thv-registry-api/api): HTTP handlers implementing the MCP Registry API - Service Layer (
cmd/thv-registry-api/internal/service): Legacy business logic (being refactored) - Configuration Layer (
pkg/config): YAML configuration loading and validation - Source Handler Layer (
pkg/sources): Pluggable data source implementationsGitSourceHandler: Clones Git repositories and extracts registry filesAPISourceHandler: Fetches from upstream MCP Registry APIsFileSourceHandler: Reads from local filesystem
- Sync Manager (
pkg/sync): Coordinates automatic registry synchronization - Storage Layer (
pkg/sources): Persists registry data to local storage - Status Tracking (
pkg/status): Tracks and persists sync status
The project uses table-driven tests with mocks generated via go.uber.org/mock:
# Generate mocks before testing
task gen
# Run all tests
task testThe Registry API is designed to run as a sidecar container alongside the ToolHive Operator's MCPRegistry controller. Example deployment:
apiVersion: apps/v1
kind: Deployment
metadata:
name: registry-api
spec:
template:
spec:
containers:
- name: registry-api
image: ghcr.io/stacklok/toolhive/thv-registry-api:latest
args:
- serve
- --config=/etc/registry/config.yaml
ports:
- containerPort: 8080
volumeMounts:
- name: config
mountPath: /etc/registry
volumes:
- name: config
configMap:
name: registry-api-config
---
apiVersion: v1
kind: ConfigMap
metadata:
name: registry-api-config
data:
config.yaml: |
registryName: my-registry
source:
type: git
format: toolhive
git:
repository: https://github.com/stacklok/toolhive.git
branch: main
path: pkg/registry/data/registry.json
syncPolicy:
interval: "15m"# Build the image
task build-image
# Run with Git source
docker run -v $(pwd)/examples:/config \
ghcr.io/stacklok/toolhive/thv-registry-api:latest \
serve --config /config/config-git.yaml
# Run with file source (mount local registry file)
docker run -v $(pwd)/examples:/config \
-v /path/to/registry.json:/data/registry.json \
ghcr.io/stacklok/toolhive/thv-registry-api:latest \
serve --config /config/config-file.yamlThe Registry API server works seamlessly with the ToolHive ecosystem:
- ToolHive Operator: Automatically deployed as part of MCPRegistry resources
See the ToolHive documentation for more details.
We welcome contributions! Please see:
- Run
task lint-fixbefore committing - Ensure tests pass with
task test - Follow Go standard project layout
- Use mockgen for test mocks, not hand-written mocks
- See CLAUDE.md for AI assistant guidance
This project is licensed under the Apache 2.0 License.
Part of the ToolHive project - Simplify and secure MCP servers