Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions .github/workflows/update-toolhive-reference.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,8 @@ jobs:
update-reference:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
with:
fetch-depth: 0
- name: Setup
uses: ./.github/actions/setup

- name: Set up Git
run: |
Expand Down
7 changes: 4 additions & 3 deletions docs/toolhive/guides-cli/registry.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -133,9 +133,10 @@ configure ToolHive to use a custom registry instead. This is useful for
organizations that want to maintain their own private registry of MCP servers.

The registry is a JSON file that follows the
[ToolHive registry schema](../reference/registry-schema.mdx). Once you configure
a custom registry, ToolHive uses it for all commands that interact with the
registry, such as `thv registry list`, `thv registry info`, and `thv run`.
[ToolHive registry schema](../reference/registry-schema-toolhive.mdx). Once you
configure a custom registry, ToolHive uses it for all commands that interact
with the registry, such as `thv registry list`, `thv registry info`, and
`thv run`.

Refer to the
[built-in registry file](https://github.com/stacklok/toolhive/blob/main/pkg/registry/data/registry.json)
Expand Down
13 changes: 12 additions & 1 deletion docs/toolhive/guides-registry/configuration.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ registryName: my-registry
# Registries configuration (required, can have multiple registries)
registries:
- name: toolhive
# Data format: upstream (MCP registry format) or toolhive (legacy)
# Data format: upstream or toolhive (see below)
format: upstream

# Git repository configuration
Expand Down Expand Up @@ -63,6 +63,17 @@ database:
| `--config` | Path to YAML configuration file | Yes | - |
| `--address` | Server listen address | No | `:8080` |

## Registry data formats

The `format` field specifies the JSON schema format for the registry data:

- **`upstream`**: The official
[upstream MCP registry format](../reference/registry-schema-upstream.mdx),
used by the MCP Registry API and recommended for new registries.
- **`toolhive`**: The
[ToolHive-native format](../reference/registry-schema-toolhive.mdx), used by
the built-in ToolHive registry.

## Registries

The server supports five registry types, each with its own configuration
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,19 @@ displayed_sidebar: toolhiveSidebar
import JSONSchemaViewer from '@theme/JSONSchemaViewer';
import Schema from '@site/static/api-specs/toolhive-legacy-registry.schema.json';

This is the JSON schema for the ToolHive registry. It defines the structure and
constraints for the registry entries, ensuring that all entries conform to a
consistent format.
This is the JSON schema for the ToolHive-native registry format. It defines the
structure and constraints for registry entries, ensuring that all entries
conform to a consistent format.

:::info

This format is considered legacy now that an
[official upstream registry format](registry-schema-upstream.mdx) exists.
ToolHive supports both formats, and the ToolHive-native format continues to work
for the built-in registry, custom file-based registries, and the ToolHive
Registry Server.

:::

To use this schema in your own custom registry file, add a `$schema` property at
the top of your JSON file:
Expand Down
44 changes: 44 additions & 0 deletions docs/toolhive/reference/registry-schema-upstream.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
---
title: Upstream registry JSON schema
description: The JSON schema for the official upstream MCP registry format.
displayed_sidebar: toolhiveSidebar
---

import JSONSchemaViewer from '@theme/JSONSchemaViewer';
import RegistrySchema from '@site/static/api-specs/upstream-registry.schema.json';
import McpServerSchema from '@site/static/api-specs/mcp-server.schema.json';

This is the JSON schema for the official upstream MCP registry format. It
defines the structure and constraints for registry entries, ensuring that all
entries conform to a consistent format. The registry wraps the official MCP
server schema, which is documented separately below.

:::info

ToolHive also supports the
[ToolHive-native registry format](./registry-schema-toolhive.mdx), which is used
by the built-in registry. Both formats work with custom file-based registries
and the ToolHive Registry Server.

:::

To use this schema in your own custom registry file, add a `$schema` property at
the top of your JSON file:

```json
{
"$schema": "https://raw.githubusercontent.com/stacklok/toolhive/main/pkg/registry/data/upstream-registry.schema.json",
...
}
```

## Registry schema

<JSONSchemaViewer schema={RegistrySchema} />

## MCP server object schema

The `servers` array in the registry contains objects that conform to the
official MCP server schema:

<JSONSchemaViewer schema={McpServerSchema} />
4 changes: 2 additions & 2 deletions docs/toolhive/tutorials/custom-registry.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -325,8 +325,8 @@ registries and private servers hosted within your organization.

## Next steps

- Explore the full [schema reference](../reference/registry-schema.mdx) to
understand all available configuration options
- Explore the full [schema reference](../reference/registry-schema-toolhive.mdx)
to understand all available configuration options
- Learn about [custom permissions](../guides-cli/custom-permissions.mdx) for
fine-grained security control
- Set up [secrets management](../guides-cli/secrets-management.mdx) for servers
Expand Down
6 changes: 5 additions & 1 deletion docusaurus.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,11 @@ const config: Config = {
},
{
label: 'ToolHive Registry schema',
to: 'toolhive/reference/registry-schema',
to: 'toolhive/reference/registry-schema-toolhive',
},
{
label: 'Upstream Registry schema',
to: 'toolhive/reference/registry-schema-upstream',
},
{
label: 'ToolHive Registry API',
Expand Down
35 changes: 26 additions & 9 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
"redocusaurus": "2.5.0"
},
"devDependencies": {
"@apidevtools/json-schema-ref-parser": "^15.2.1",
"@docusaurus/module-type-aliases": "3.9.2",
"@docusaurus/tsconfig": "3.9.2",
"@docusaurus/types": "3.9.2",
Expand Down
96 changes: 96 additions & 0 deletions scripts/bundle-upstream-schema.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
#!/usr/bin/env node
// SPDX-FileCopyrightText: Copyright 2025 Stacklok, Inc.
// SPDX-License-Identifier: Apache-2.0

/**
* This script dereferences the upstream registry schema, resolving all $ref
* references (including remote ones) into a single bundled schema file.
*
* It also fetches and dereferences the official MCP server schema separately
* for improved rendering on the documentation page. The MCP server schema URL
* is extracted from the $ref in the upstream registry schema.
*
* This is necessary because the upstream schema references the official MCP
* server schema, which contains internal $ref references that the JSON Schema
* Viewer plugin cannot resolve at runtime.
*/

import { readFileSync, writeFileSync } from 'fs';
import { dirname, join } from 'path';
import { fileURLToPath } from 'url';
import $RefParser from '@apidevtools/json-schema-ref-parser';

const __dirname = dirname(fileURLToPath(import.meta.url));
const STATIC_DIR = join(__dirname, '..', 'static', 'api-specs');

const REGISTRY_SCHEMA = join(STATIC_DIR, 'upstream-registry.schema.json');
const MCP_SERVER_SCHEMA = join(STATIC_DIR, 'mcp-server.schema.json');

/**
* Extract the MCP server schema URL from the upstream registry schema.
* Looks for $ref in data.properties.servers.items.
*/
function extractMcpServerUrl(registrySchemaPath) {
const schema = JSON.parse(readFileSync(registrySchemaPath, 'utf-8'));
const ref = schema?.properties?.data?.properties?.servers?.items?.$ref;

if (!ref || !ref.startsWith('http')) {
throw new Error(
'Could not find MCP server schema $ref in upstream registry schema'
);
}

return ref;
}

/**
* Replace the MCP server $ref in the registry with a placeholder that directs
* readers to the separate MCP server schema section.
*/
function simplifyRegistrySchema(schema, mcpServerUrl) {
const serverPlaceholder = {
type: 'object',
description: `MCP server object (see MCP server object schema section below). Source: ${mcpServerUrl}`,
};

// Replace servers.items $ref
if (schema?.properties?.data?.properties?.servers?.items) {
schema.properties.data.properties.servers.items = serverPlaceholder;
}

// Replace groups.items.properties.servers.items $ref if present
if (
schema?.properties?.data?.properties?.groups?.items?.properties?.servers
?.items
) {
schema.properties.data.properties.groups.items.properties.servers.items =
serverPlaceholder;
}

return schema;
}

async function main() {
try {
const mcpServerUrl = extractMcpServerUrl(REGISTRY_SCHEMA);

// Simplify registry schema by replacing $refs with placeholders
const registrySchema = JSON.parse(readFileSync(REGISTRY_SCHEMA, 'utf-8'));
const simplifiedSchema = simplifyRegistrySchema(
registrySchema,
mcpServerUrl
);
writeFileSync(REGISTRY_SCHEMA, JSON.stringify(simplifiedSchema, null, 2));
console.log('Upstream registry schema processed successfully');

// Fetch and dereference the MCP server schema
const mcpServerSchema = await $RefParser.dereference(mcpServerUrl);
writeFileSync(MCP_SERVER_SCHEMA, JSON.stringify(mcpServerSchema, null, 2));
console.log('MCP server schema fetched successfully');
} catch (error) {
console.error('Failed to process schemas:', error.message);
process.exit(1);
}
}

main();
18 changes: 17 additions & 1 deletion scripts/update-toolhive-reference.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ API_SPEC_DST="${STATIC_DIR}/api-specs/toolhive-api.yaml"

REGISTRY_SCHEMA_SRC="${IMPORT_DIR}/toolhive/pkg/registry/data/toolhive-legacy-registry.schema.json"
REGISTRY_SCHEMA_DST="${STATIC_DIR}/api-specs/toolhive-legacy-registry.schema.json"
UPSTREAM_REGISTRY_SCHEMA_SRC="${IMPORT_DIR}/toolhive/pkg/registry/data/upstream-registry.schema.json"
UPSTREAM_REGISTRY_SCHEMA_DST="${STATIC_DIR}/api-specs/upstream-registry.schema.json"


CRD_API_SRC="${IMPORT_DIR}/toolhive/docs/operator/crd-api.md"
CRD_API_DST="${STATIC_DIR}/api-specs/toolhive-crd-api.md"
Expand Down Expand Up @@ -112,7 +115,7 @@ if [[ "$RELEASE_VERSION" =~ ^v.* ]]; then
echo "Warning: API specification not found at ${API_SPEC_SRC}"
fi

## Registry schema
## Registry schemas
echo "Updating ToolHive registry JSON schema at ${REGISTRY_SCHEMA_DST}"

if [ -f "${REGISTRY_SCHEMA_SRC}" ]; then
Expand All @@ -122,6 +125,19 @@ if [[ "$RELEASE_VERSION" =~ ^v.* ]]; then
echo "Warning: Registry schema not found at ${REGISTRY_SCHEMA_SRC}"
fi

echo "Updating upstream registry JSON schema at ${UPSTREAM_REGISTRY_SCHEMA_DST}"

if [ -f "${UPSTREAM_REGISTRY_SCHEMA_SRC}" ]; then
cp ${UPSTREAM_REGISTRY_SCHEMA_SRC} ${UPSTREAM_REGISTRY_SCHEMA_DST}
echo "Upstream registry JSON schema updated successfully"

# Bundle the upstream schema to resolve remote $ref references
echo "Bundling upstream registry schema (resolving remote references)..."
node "${REPO_ROOT}/scripts/bundle-upstream-schema.mjs"
else
echo "Warning: Registry schema not found at ${UPSTREAM_REGISTRY_SCHEMA_SRC}"
fi

elif [[ "$RELEASE_VERSION" =~ ^toolhive-operator-crds-.* ]]; then
echo "Processing operator CRD release: $RELEASE_VERSION"

Expand Down
34 changes: 34 additions & 0 deletions src/css/custom.css
Original file line number Diff line number Diff line change
Expand Up @@ -340,3 +340,37 @@ details summary:hover {
[data-theme='light'] .navbar-sidebar .navbar__logo img {
content: url('/img/logos/stacklok-default-dark-green.svg');
}

/* JSON Schema Viewer overrides
* Reset the brand-colored alert styling for the docusaurus-json-schema-plugin
* since the nested details blocks are overwhelming with the green theme.
*/
.json-schema-viewer.alert,
.json-schema-viewer details.alert {
--docusaurus-details-decoration-color: var(--ifm-color-gray-500);
--ifm-alert-background-color: var(--ifm-background-surface-color);
--ifm-alert-border-color: var(--ifm-color-gray-300);
}

.json-schema-viewer details summary {
color: var(--ifm-color-content);
}

.json-schema-viewer details summary:hover {
color: var(--ifm-color-primary);
}

[data-theme='dark'] .json-schema-viewer.alert,
[data-theme='dark'] .json-schema-viewer details.alert {
--docusaurus-details-decoration-color: var(--ifm-color-gray-600);
--ifm-alert-background-color: var(--ifm-background-color);
--ifm-alert-border-color: var(--ifm-color-gray-700);
}

[data-theme='dark'] .json-schema-viewer details summary {
color: var(--ifm-color-content);
}

[data-theme='dark'] .json-schema-viewer details summary:hover {
color: var(--ifm-color-primary);
}
Loading
Loading