Configuration Reference
July 15, 2026 · View on GitHub
Complete configuration reference for the ToolHive Registry API server.
Table of Contents
- Overview
- Configuration File Structure
- Registry Configuration
- Data Sources
- Sync Policy
- Filtering
- Authentication
- Database
- Environment Variables
- Examples
Overview
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
Command-line Flags
| 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 | - |
Configuration File Structure
Minimal Configuration
sources:
- name: default
file:
path: /data/registry.json
registries:
- name: default
sources: ["default"]
database:
host: localhost
port: 5432
user: registry
database: registry
Complete Configuration
# 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-upstream.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"
Source Configuration
Sources define where registry data comes from. Multiple sources can be configured, each with its own data provider, sync policy, and filters.
Top-Level Fields
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
sources | array | Yes | - | List of data source configurations |
registries | array | Yes | - | List of registry aggregations (at least one required) |
Source Entry Fields
| 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
Registry Entry Fields
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 |
Data Sources
Git Repository
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-upstream.json
auth: # Optional: for private repos
username: user
passwordFile: /secrets/git-password
Fields:
| 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
API Endpoint
Sync from upstream MCP Registry APIs. Ideal for federation scenarios.
api:
endpoint: https://registry.example.com
timeout: 30s
Fields:
| Field | Type | Required | Description |
|---|---|---|---|
endpoint | string | Yes | Base API URL (without path); the server appends MCP Registry API v0.1 paths automatically |
timeout | string | No | Per-request HTTP timeout as a Go duration (e.g. 30s, 1m). Defaults to 10s; must be greater than 0 and at most 5m. Raise this for public or occasionally-slow upstreams where individual requests can take longer. |
Supports:
- Automatic background synchronization
- Per-registry filtering
Local File
Read from local filesystem. Ideal for development and testing.
file:
path: /data/registry.json
Fields:
| Field | Type | Required | Description |
|---|---|---|---|
path | string | Yes | Absolute path to registry JSON file |
Supports:
- Automatic background synchronization (monitors file changes)
- Per-registry filtering
Managed
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
Kubernetes
Discover MCP servers from Kubernetes deployments.
kubernetes:
namespaces: # Optional: specific namespaces to watch
- default
Fields:
| 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
Sync Policy
Controls automatic background synchronization for Git, API, and File registries.
syncPolicy:
interval: "30m" # Sync interval
Fields:
| 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)
Filtering
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)
Authentication
See detailed Authentication Guide.
Quick Reference
auth:
mode: oauth # "oauth" (default) or "anonymous"
publicPaths: # Optional: additional public paths
- /metrics
oauth:
resourceUrl: https://registry.example.com
realm: mcp-registry # Optional
providers:
- name: my-idp
issuerUrl: https://idp.example.com
audience: api://registry
clientId: client-id # Optional
clientSecretFile: /secrets/secret # Optional
caCertPath: /certs/ca.crt # Optional
Database
See detailed Database Guide.
Quick Reference
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" # Optional
Password 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.
Environment Variables
Configuration values can be overridden using environment variables with the THV_REGISTRY_ prefix. For complete documentation, see Environment Variables Guide.
Common Configuration Overrides
| 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) |
Database Passwords
| 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.
Other
| Variable | Description |
|---|---|
CONFIG_FILE | Override config file path |
THV_REGISTRY_INSECURE_URL | Allow HTTP URLs for development (default: false) |
Examples
Development (Local File)
sources:
- name: local
file:
path: ./examples/registry-sample.json
auth:
mode: anonymous
database:
host: localhost
port: 5432
user: registry
database: registry
sslMode: disable
Production (Git + Database + OAuth)
sources:
- name: toolhive
git:
repository: https://github.com/stacklok/toolhive-catalog.git
branch: main
path: pkg/catalog/toolhive/data/registry-upstream.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"
Multi-Registry Setup
sources:
# Official ToolHive registry
- name: toolhive
git:
repository: https://github.com/stacklok/toolhive-catalog.git
branch: main
path: pkg/catalog/toolhive/data/registry-upstream.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: registry
Validation
The 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
See Also
- Database Configuration - Detailed database setup
- Authentication - OAuth and security
- Kubernetes Deployment - Kubernetes configuration examples
- Docker Deployment - Docker configuration examples
- examples/ - Complete configuration examples