Complete configuration reference for the ToolHive Registry API server.
- Overview
- Configuration File Structure
- Registry Configuration
- Data Sources
- Sync Policy
- Filtering
- Authentication
- Database
- Environment Variables
- Examples
All configuration is done via YAML files. The server requires a --config flag pointing to a configuration file.
thv-registry-api serve --config config.yaml| Flag | Description | Required | Default |
|---|---|---|---|
--config |
Path to YAML configuration file | Yes | - |
--address |
Server listen address | No | :8080 |
--auth-mode |
Override auth mode (anonymous or oauth) | No | - |
sources:
- name: default
file:
path: /data/registry.json
registries:
- name: default
sources: ["default"]
database:
host: localhost
port: 5432
user: registry
database: registry# Sources define where registry data comes from
sources:
- name: toolhive
git:
repository: https://github.com/stacklok/toolhive-catalog.git
branch: main
path: pkg/catalog/toolhive/data/registry-legacy.json
syncPolicy:
interval: "30m"
filter:
names:
include: ["official/*"]
exclude: ["*/deprecated"]
tags:
include: ["production"]
exclude: ["experimental"]
# Registries aggregate one or more sources into a named view (required)
registries:
- name: default
sources: ["toolhive"]
# Authentication configuration (required)
auth:
mode: oauth
oauth:
resourceUrl: https://registry.example.com
providers:
- name: my-idp
issuerUrl: https://idp.example.com
audience: api://registry
# Database configuration (required)
database:
host: localhost
port: 5432
user: registry
database: registry
sslMode: require
maxOpenConns: 25
maxIdleConns: 5
connMaxLifetime: "5m"Sources define where registry data comes from. Multiple sources can be configured, each with its own data provider, sync policy, and filters.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
sources |
array | Yes | - | List of data source configurations |
registries |
array | Yes | - | List of registry aggregations (at least one required) |
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | Yes | Unique name for this source |
git |
object | No* | Git repository configuration |
api |
object | No* | API endpoint configuration |
file |
object | No* | Local file configuration |
managed |
object | No* | Managed registry configuration |
kubernetes |
object | No* | Kubernetes resource configuration |
syncPolicy |
object | Yes† | Sync policy configuration |
filter |
object | No | Server filtering rules |
claims |
map | No | Key-value pairs for authorization purposes |
* Exactly one data source must be configured per source entry † Required for synced sources (git, api, file); not applicable for managed or kubernetes sources
The registries: block aggregates sources into named registry views. At least one registry must be configured.
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | Yes | Unique name for this registry |
sources |
array | Yes | Ordered list of source names that feed this registry |
claims |
map | No | Key-value pairs for authorization purposes |
Clone and sync from Git repositories. Ideal for version-controlled registries.
git:
repository: https://github.com/stacklok/toolhive-catalog.git
branch: main # Optional: defaults to default branch
tag: v1.0.0 # Optional: use specific tag
commit: abc123 # Optional: pin to specific commit
path: pkg/catalog/toolhive/data/registry-legacy.json
auth: # Optional: for private repos
username: user
passwordFile: /secrets/git-passwordFields:
| Field | Type | Required | Description |
|---|---|---|---|
repository |
string | Yes | Git repository URL (HTTPS or SSH) |
branch |
string | No | Branch name (default: default branch) |
tag |
string | No | Tag name (mutually exclusive with branch/commit) |
commit |
string | No | Commit SHA (mutually exclusive with branch/tag) |
path |
string | Yes | Path to registry JSON file within repo |
auth.username |
string | No | Git username for private repos |
auth.passwordFile |
string | No | Path to file containing Git password/token |
Supports:
- Automatic background synchronization
- Per-registry filtering
- Branch, tag, or commit pinning
Sync from upstream MCP Registry APIs. Ideal for federation scenarios.
api:
endpoint: https://registry.example.comFields:
| Field | Type | Required | Description |
|---|---|---|---|
endpoint |
string | Yes | Base API URL (without path); the server appends MCP Registry API v0.1 paths automatically |
Supports:
- Automatic background synchronization
- Per-registry filtering
Read from local filesystem. Ideal for development and testing.
file:
path: /data/registry.jsonFields:
| Field | Type | Required | Description |
|---|---|---|---|
path |
string | Yes | Absolute path to registry JSON file |
Supports:
- Automatic background synchronization (monitors file changes)
- Per-registry filtering
Directly managed via API. No external data source.
managed: {}Features:
- Create, update, and delete servers through API calls
- No background synchronization
- Requires database backend
- Ideal for custom, dynamically-managed registries
Does NOT support:
- Sync policy configuration
- Filtering configuration
Discover MCP servers from Kubernetes deployments.
kubernetes:
namespaces: # Optional: specific namespaces to watch
- defaultFields:
| Field | Type | Required | Description |
|---|---|---|---|
namespaces |
array | No | Kubernetes namespaces to watch (empty = uses THV_REGISTRY_WATCH_NAMESPACE env var) |
Per-entry claims: CRDs can carry per-entry authorization claims via the
toolhive.stacklok.dev/authz-claims JSON annotation. The annotation value uses the same
map[string]any format as source claims (strings or arrays of strings). Source claims are
not merged — entries get exactly the claims from the annotation. Entries without the
annotation have no claims and are invisible when authz is configured (default-deny).
# Example CRD annotation for per-entry claims:
metadata:
annotations:
toolhive.stacklok.dev/authz-claims: '{"team": "platform"}'Features:
- Queries running Kubernetes resources
- No background synchronization (on-demand only)
- Requires in-cluster service account or kubeconfig
Does NOT support:
- Sync policy configuration
- Filtering configuration
Controls automatic background synchronization for Git, API, and File registries.
syncPolicy:
interval: "30m" # Sync intervalFields:
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
interval |
string | Yes | - | Sync interval (e.g., "30m", "1h", "24h") |
Not applicable for:
- Managed registries (no sync)
- Kubernetes registries (no sync)
Filter which servers are exposed from a registry.
filter:
names:
include: ["official/*", "approved/*"]
exclude: ["*/deprecated", "*/test"]
tags:
include: ["production", "stable"]
exclude: ["experimental", "beta"]Fields:
| Field | Type | Description |
|---|---|---|
names.include |
array | Include servers matching these patterns (glob) |
names.exclude |
array | Exclude servers matching these patterns (glob) |
tags.include |
array | Include servers with these tags |
tags.exclude |
array | Exclude servers with these tags |
Behavior:
- If
includeis specified, only matching servers are included excludeis then applied to remove servers- Both name patterns and tags are evaluated
- Empty filter = no filtering (all servers included)
Pattern matching:
- Uses glob patterns (wildcards:
*,?,[...]) - Examples:
official/*,company/*/stable,*-prod
Not applicable for:
- Managed registries (controlled via API)
- Kubernetes registries (use labelSelector instead)
See detailed Authentication Guide.
auth:
mode: oauth # "oauth" (default) or "anonymous"
publicPaths: # Optional: additional public paths
- /metrics
oauth:
resourceUrl: https://registry.example.com
realm: mcp-registry # Optional
scopesSupported: # Optional
- mcp-registry:read
- mcp-registry:write
providers:
- name: my-idp
issuerUrl: https://idp.example.com
audience: api://registry
clientId: client-id # Optional
clientSecretFile: /secrets/secret # Optional
caCertPath: /certs/ca.crt # OptionalSee detailed Database Guide.
database:
host: localhost
port: 5432
user: registry_app
migrationUser: registry_migrator # Optional
database: toolhive_registry
sslMode: require # disable, require, verify-ca, verify-full
maxOpenConns: 25 # Optional
maxIdleConns: 5 # Optional
connMaxLifetime: "5m" # OptionalPassword management:
Passwords can be provided via THV_REGISTRY_DATABASE_PASSWORD / THV_REGISTRY_DATABASE_MIGRATIONPASSWORD environment variables, the password / migrationPassword config fields, or PostgreSQL's pgpass file (~/.pgpass or $PGPASSFILE). See Database Configuration for details.
Configuration values can be overridden using environment variables with the THV_REGISTRY_ prefix. For complete documentation, see Environment Variables Guide.
| Variable | Description |
|---|---|
THV_REGISTRY_DATABASE_HOST |
Override database host |
THV_REGISTRY_DATABASE_PORT |
Override database port |
THV_REGISTRY_DATABASE_USER |
Override database user |
THV_REGISTRY_AUTH_MODE |
Override authentication mode (anonymous or oauth) |
THV_REGISTRY_LOG_LEVEL |
Set log level (debug, info, warn, error) |
| Variable | Description |
|---|---|
THV_REGISTRY_DATABASE_PASSWORD |
Database password for the application user |
THV_REGISTRY_DATABASE_MIGRATIONPASSWORD |
Database password for the migration user |
PGPASSFILE |
Path to pgpass file (default: ~/.pgpass) — used as fallback when password env vars are not set |
See Database Configuration for password management details.
| Variable | Description |
|---|---|
CONFIG_FILE |
Override config file path |
THV_REGISTRY_INSECURE_URL |
Allow HTTP URLs for development (default: false) |
sources:
- name: local
file:
path: ./examples/registry-sample.json
auth:
mode: anonymous
database:
host: localhost
port: 5432
user: registry
database: registry
sslMode: disablesources:
- name: toolhive
git:
repository: https://github.com/stacklok/toolhive-catalog.git
branch: main
path: pkg/catalog/toolhive/data/registry-legacy.json
syncPolicy:
interval: "15m"
filter:
names:
include: ["official/*"]
tags:
exclude: ["experimental"]
registries:
- name: default
sources: ["toolhive"]
auth:
mode: oauth
oauth:
resourceUrl: https://registry.company.com
providers:
- name: company-sso
issuerUrl: https://auth.company.com
audience: api://toolhive-registry
database:
host: postgres.production.svc.cluster.local
port: 5432
user: registry_app
migrationUser: registry_migrator
database: toolhive_registry
sslMode: verify-full
maxOpenConns: 50
maxIdleConns: 10
connMaxLifetime: "1h"sources:
# Official ToolHive registry
- name: toolhive
git:
repository: https://github.com/stacklok/toolhive-catalog.git
branch: main
path: pkg/catalog/toolhive/data/registry-legacy.json
syncPolicy:
interval: "30m"
# Company internal registry
- name: internal
api:
endpoint: https://internal-registry.company.com
syncPolicy:
interval: "1h"
filter:
tags:
include: ["approved"]
# Managed registry for custom servers
- name: custom
managed: {}
# Kubernetes-deployed servers
- name: k8s-deployed
kubernetes:
namespaces:
- mcp-servers
registries:
- name: default
sources: ["toolhive", "internal", "custom", "k8s-deployed"]
auth:
mode: oauth
oauth:
resourceUrl: https://registry.company.com
providers:
- name: company-sso
issuerUrl: https://auth.company.com
audience: api://registry
- name: kubernetes
issuerUrl: https://kubernetes.default.svc
audience: https://kubernetes.default.svc
database:
host: postgres
port: 5432
user: registry
database: registryThe configuration is validated on startup. Common validation errors:
- Missing required fields: Ensure all required fields are present
- Invalid data source: Exactly one data source must be configured per registry
- Invalid duration format: Use format like "30m", "1h", "24h"
- Invalid auth mode: Must be "anonymous" or "oauth"
- Missing OAuth providers: At least one provider required when mode is "oauth"
- Invalid filter patterns: Check glob pattern syntax
- Database connection: Verify connection parameters
Run with --debug flag for detailed validation output:
thv-registry-api serve --config config.yaml --debug- Database Configuration - Detailed database setup
- Authentication - OAuth and security
- Kubernetes Deployment - Kubernetes configuration examples
- Docker Deployment - Docker configuration examples
- examples/ - Complete configuration examples