Registry JSON Schema
April 27, 2026 · View on GitHub
This document describes the JSON Schema for the ToolHive MCP server registry and how to use it for validation and development.
⚠️ Registry Migration Notice
The ToolHive registry has been migrated to a separate repository for better management and maintenance.
To contribute MCP servers, please visit: https://github.com/stacklok/toolhive-catalog
The registry data in this repository is now automatically synchronized from the external registry.
Migrating from the legacy format
The legacy ToolHive registry format is no longer accepted. Run
thv registry convert --in <file> --in-place to migrate any custom registry
JSON file to the upstream MCP format. The conversion is lossless: every
ToolHive-specific field maps to a publisher-provided extension on the
corresponding upstream server entry.
Schema files
ToolHive consumes registries in the upstream MCP registry format. The schemas
live in the toolhive-core module:
Upstream Registry Schema
- Schema ID:
https://raw.githubusercontent.com/stacklok/toolhive-core/main/registry/types/data/upstream-registry.schema.json - Purpose: Validates registries using the upstream MCP server format. References the official MCP server schema.
Publisher-Provided Extensions Schema
- Schema ID:
https://raw.githubusercontent.com/stacklok/toolhive-core/main/registry/types/data/publisher-provided.schema.json - Purpose: Defines the structure of ToolHive-specific metadata placed under
_meta["io.modelcontextprotocol.registry/publisher-provided"]in MCP server definitions
The publisher-provided extensions schema allows ToolHive and other publishers to add custom metadata to MCP server definitions in the upstream registry format. This metadata is stored in the _meta object under the key io.modelcontextprotocol.registry/publisher-provided.
Schema Structure
The extensions are organized by publisher namespace. ToolHive uses the io.github.stacklok namespace, with server-specific extensions keyed by their identifier:
- Container servers: Keyed by OCI image reference (e.g.,
ghcr.io/stacklok/mcp-server-example:latest) - Remote servers: Keyed by URL (e.g.,
https://api.example.com/mcp)
{
"_meta": {
"io.modelcontextprotocol.registry/publisher-provided": {
"io.github.stacklok": {
"ghcr.io/stacklok/mcp-server-example:latest": {
"status": "active",
"tier": "Official",
"tools": ["example-tool"],
"tags": ["example", "demo"],
"permissions": {
"network": {
"outbound": {
"allow_host": ["api.example.com"],
"allow_port": [443]
}
}
}
}
}
}
}
}
Common Fields
These fields are available for all MCP servers (both container-based and remote):
-
status(required): Current status of the server- Values:
"active","deprecated","Active","Deprecated" - Default:
"active"
- Values:
-
tier: Tier classification of the server- Values:
"Official","Community"
- Values:
-
tools: Array of tool names provided by this MCP server- Example:
["filesystem_read", "filesystem_write"]
- Example:
-
tags: Categorization tags for search and filtering- Pattern:
^[a-z0-9][a-z0-9_-]*[a-z0-9]$ - Example:
["filesystem", "productivity", "development"]
- Pattern:
-
metadata: Popularity, activity metrics, and Kubernetes-specific metadatastars: Number of repository starspulls: Number of container image pulls or usage countlast_updated: Timestamp in RFC3339 formatkubernetes: Kubernetes-specific metadata (nested object) - optional, only populated when:- The server is served from ToolHive Registry Server
- The server was auto-discovered from a Kubernetes deployment
- The Kubernetes resource has the required registry annotations (e.g.,
toolhive.stacklok.com/registry-description,toolhive.stacklok.com/registry-url) - Fields:
kind: Kubernetes resource kind (e.g., "MCPServer", "VirtualMCPServer", "MCPRemoteProxy")namespace: Kubernetes namespace where the resource is deployedname: Kubernetes resource nameuid: Kubernetes resource UIDimage: Container image used by the Kubernetes workload (applicable to MCPServer)transport: Transport type configured for the Kubernetes workload (applicable to MCPServer)
-
custom_metadata: Custom user-defined metadata (arbitrary key-value pairs)
Container Server Fields
These fields are specific to container-based MCP servers (keyed by OCI image reference):
-
permissions: Security permissions for the containername: Permission profile namenetwork.outbound: Outbound network accessallow_host: Array of allowed hostnames or domain patternsallow_port: Array of allowed port numbersinsecure_allow_all: Allow all outbound connections (use with caution)
read: Array of host filesystem paths for read-only accesswrite: Array of host filesystem paths for write accessprivileged: Whether to run in privileged mode
-
args: Default command-line arguments for the container -
provenance: Software supply chain provenance informationsigstore_url: Sigstore TUF repository hostrepository_uri: Repository URI for verificationrepository_ref: Repository reference for verificationsigner_identity: Identity of the signerrunner_environment: Build environment (e.g.,"github-hosted")cert_issuer: Certificate issuer URIattestation: Verified attestation with predicate type and data
-
docker_tags: Available Docker tags for the container image -
proxy_port: HTTP proxy port for the container (1-65535)
Remote Server Fields
These fields are specific to remote MCP servers (keyed by URL):
-
oauth_config: OAuth/OIDC configuration for authenticationissuer: OAuth/OIDC issuer URL (for OIDC discovery)authorize_url: OAuth authorization endpoint (for non-OIDC OAuth)token_url: OAuth token endpoint (for non-OIDC OAuth)client_id: OAuth client IDscopes: Array of OAuth scopes to requestuse_pkce: Whether to use PKCE (default:true)oauth_params: Additional OAuth parameterscallback_port: Specific port for OAuth callback serverresource: OAuth 2.0 resource indicator (RFC 8707)
-
env_vars: Environment variable definitions for client configurationname: Environment variable name (pattern:^[A-Za-z_][A-Za-z0-9_]*$)description: Human-readable explanationrequired: Whether the variable is requiredsecret: Whether the variable contains sensitive informationdefault: Default value if not provided
Example: Container Server
{
"ghcr.io/stacklok/mcp-filesystem:v1.0.0": {
"status": "active",
"tier": "Official",
"tools": ["read_file", "write_file", "list_directory"],
"tags": ["filesystem", "productivity"],
"permissions": {
"name": "filesystem-access",
"read": ["/home/user/documents"],
"write": ["/home/user/documents/output"]
},
"args": ["--log-level", "info"],
"docker_tags": ["v1.0.0", "v1.0", "v1", "latest"],
"metadata": {
"stars": 150,
"pulls": 5000,
"last_updated": "2025-02-04T10:00:00Z"
}
}
}
Example: Container Server with Kubernetes Metadata
When an MCP server is deployed in Kubernetes and served via the ToolHive Registry Server's auto-discovery feature, additional Kubernetes-specific metadata is included. This requires the Kubernetes resource to have the required registry annotations:
{
"https://mcp-server.example.com": {
"status": "active",
"tier": "Official",
"tools": ["read_file", "write_file", "list_directory"],
"tags": ["filesystem", "productivity"],
"metadata": {
"stars": 150,
"pulls": 5000,
"last_updated": "2025-02-04T10:00:00Z",
"kubernetes": {
"kind": "MCPServer",
"namespace": "mcp-servers",
"name": "filesystem-server",
"uid": "a1b2c3d4-e5f6-4a5b-8c9d-0e1f2a3b4c5d",
"image": "ghcr.io/stacklok/mcp-filesystem:v1.0.0",
"transport": "streamable-http"
}
}
}
}
Example: Remote Server
{
"https://api.example.com/mcp": {
"status": "active",
"tier": "Community",
"tools": ["query_api", "update_resource"],
"tags": ["api", "integration"],
"oauth_config": {
"issuer": "https://auth.example.com",
"client_id": "mcp-client",
"scopes": ["read", "write"],
"use_pkce": true
},
"env_vars": [
{
"name": "API_KEY",
"description": "API authentication key",
"required": true,
"secret": true
},
{
"name": "API_ENDPOINT",
"description": "API endpoint URL",
"required": false,
"default": "https://api.example.com"
}
]
}
}
Usage
Automated validation (Go tests)
The registry is automatically validated against the upstream schema during development and CI/CD through Go tests. This ensures that any changes to the registry data are immediately validated.
Schema validation is provided by
toolhive-core's
registry/types.ValidateUpstreamRegistryBytes and exercised locally in
pkg/registry/schema_validation_test.go.
Key tests:
TestEmbeddedRegistrySchemaValidation- Validates the embedded upstream registry against the upstream registry schemaTestValidateEmbeddedRegistryCanLoadData- Confirms the embedded upstream registry parses into the internal typesTestUpstreamRegistryParsing- Round-trips upstream registry data throughparseRegistryData
Running the validation:
# Run all schema validation tests
go test -v ./pkg/registry -run ".*Schema.*"
# Run just the embedded registry validation
go test -v ./pkg/registry -run TestEmbeddedRegistrySchemaValidation
# Run all registry tests (includes schema validation)
go test -v ./pkg/registry
This validation runs automatically as part of:
- Local development (
go test) - CI/CD pipeline (GitHub Actions)
- Pre-commit hooks (if configured)
Manual validation
Using check-jsonschema
Install check-jsonschema via Homebrew (macOS):
brew install check-jsonschema
Or via pipx (cross-platform):
pipx install check-jsonschema
Validate a custom registry file against the upstream schema:
check-jsonschema \
--schemafile https://raw.githubusercontent.com/stacklok/toolhive-core/main/registry/types/data/upstream-registry.schema.json \
path/to/registry.json
Using ajv-cli
npm install -g ajv-cli ajv-formats
ajv validate -c ajv-formats \
-s upstream-registry.schema.json \
-d path/to/registry.json
Using VS Code
VS Code automatically validates JSON files when a schema is specified. Add this to the top of any registry JSON file:
{
"$schema": "https://raw.githubusercontent.com/stacklok/toolhive-core/main/registry/types/data/upstream-registry.schema.json",
...
}
Methodology
The draft-07 version of JSON Schema is used to ensure the widest compatibility
with commonly used tools and libraries.
The schema is currently maintained manually, due to differences in how required
vs. optional sections are defined in the Go codebase (omitempty vs. nil/empty
conditional checks).
At some point, we may automate this process by generating the schema from the Go code using something like invopop/jsonschema, but for now, manual updates are necessary to ensure accuracy and completeness.
Contributing
For adding new MCP servers:
Please visit the toolhive-registry repository which now manages all MCP server definitions.
For schema improvements:
When modifying the registry schema in this repository:
- Validate locally before submitting PRs
- Follow naming conventions for consistency
- Include comprehensive descriptions for clarity
- Test with existing registry data to ensure compatibility
- Update documentation to reflect schema changes
Legacy server addition process (deprecated):
When adding new server entries:
Validate locally before submitting PRsFollow naming conventions for consistencyInclude comprehensive descriptions for claritySpecify minimal permissions for securityUse appropriate tags for discoverability