From 82e8d88349a9448297aa60c5beeebe6a12c38885 Mon Sep 17 00:00:00 2001 From: Michelangelo Mori <328978+blkt@users.noreply.github.com> Date: Wed, 10 Dec 2025 11:17:26 +0100 Subject: [PATCH 1/2] Add docs about Registry deployment via Operator This change adds how to use the Operator to deploy a Registry Server instance. Specifically, documentation under `docs/toolhive/guides-registry` only mentions that you can use the Operator to deploy a Registry Server instance and links back to a page under `docs/toolhive/guides-k8s` containing all the documentation. Documentation about using Postgres password file is not there because we're working to make that transparent to the User. I left documentation using plain Kubernetes resources untouched in the `docs/toolhive/guides-registry` guide. --- docs/toolhive/guides-k8s/deploy-registry.mdx | 524 ++++++++++++++++++ .../guides-registry/authentication.mdx | 2 +- .../guides-registry/configuration.mdx | 6 +- docs/toolhive/guides-registry/deployment.mdx | 21 +- docs/toolhive/guides-registry/index.mdx | 4 +- sidebars.ts | 2 +- 6 files changed, 545 insertions(+), 14 deletions(-) create mode 100644 docs/toolhive/guides-k8s/deploy-registry.mdx diff --git a/docs/toolhive/guides-k8s/deploy-registry.mdx b/docs/toolhive/guides-k8s/deploy-registry.mdx new file mode 100644 index 00000000..34660d8f --- /dev/null +++ b/docs/toolhive/guides-k8s/deploy-registry.mdx @@ -0,0 +1,524 @@ +--- +title: Run the Registry Server +description: + How to deploy the ToolHive Registry Server in Kubernetes using the ToolHive + operator +--- + +## Prerequisites + +- A Kubernetes cluster (current and two previous minor versions are supported) +- Permissions to create resources in the cluster +- [`kubectl`](https://kubernetes.io/docs/tasks/tools/) configured to communicate + with your cluster +- The ToolHive operator installed in your cluster (see + [Deploy the operator using Helm](./deploy-operator-helm.mdx)) +- A PostgreSQL database (recommended for production deployments) + +## Overview + +The ToolHive operator deploys the Registry server in Kubernetes by creating +`MCPRegistry` resources. This is the recommended method for deploying the +ToolHive Registry Server in Kubernetes environments. + +### High-level architecture + +This diagram shows the basic relationship between components. The ToolHive +operator watches for `MCPRegistry` resources and automatically creates the +necessary infrastructure to run the Registry server. + +```mermaid +flowchart LR + subgraph K8s["Kubernetes Cluster"] + direction LR + subgraph NS["toolhive-system"] + Operator["ToolHive Operator"] + end + subgraph NS2["Registry
Namespace"] + Registry["Registry Server"] + DB[("PostgreSQL")] + end + subgraph Sources["Registry Sources"] + Git["Git Repository"] + CM["ConfigMap"] + PVC["PVC"] + API["Upstream API"] + end + end + + Operator -.->|creates| Registry + Sources -->|sync| Registry + Registry --> DB +``` + +## Create a registry + +You can create `MCPRegistry` resources in namespaces based on how the operator +was deployed. + +- **Cluster mode (default)**: Create MCPRegistry resources in any namespace +- **Namespace mode**: Create MCPRegistry resources only in allowed namespaces + +See [Deploy the operator](./deploy-operator-helm.mdx#operator-deployment-modes) +to learn about the different deployment modes. + +To create a registry, define an `MCPRegistry` resource and apply it to your +cluster. This minimal example creates a registry that syncs from the ToolHive +Git repository. + +```yaml title="my-registry.yaml" +apiVersion: toolhive.stacklok.dev/v1alpha1 +kind: MCPRegistry +metadata: + name: my-registry + namespace: my-namespace # Update with your namespace +spec: + displayName: My MCP Registry + registries: + - name: toolhive + format: toolhive + git: + repository: https://github.com/stacklok/toolhive.git + branch: main + path: pkg/registry/data/registry.json + syncPolicy: + interval: '30m' +``` + +Apply the resource: + +```bash +kubectl apply -f my-registry.yaml +``` + +:::info[What's happening?] + +When you apply an `MCPRegistry` resource, here's what happens: + +1. The ToolHive operator detects the new resource (if it's in an allowed + namespace) +2. The operator creates the necessary RBAC resources in the target namespace +3. The operator creates a Deployment containing the Registry server pod and + service +4. The Registry server syncs data from the configured sources +5. The Registry API becomes available at the service endpoint + +::: + +## Configuring source Registries + +The `MCPRegistry` resource supports multiple registry source types. You can +configure one or more of them. Each type is mutually exclusive within a single +registry configuration. + +### Git repository source + +Clone and sync from Git repositories. Ideal for version-controlled registries. + +```yaml {7-12} title="registry-git.yaml" +apiVersion: toolhive.stacklok.dev/v1alpha1 +kind: MCPRegistry +metadata: + name: git-registry +spec: + registries: + - name: toolhive + format: toolhive + git: + repository: https://github.com/stacklok/toolhive.git + branch: main + path: pkg/registry/data/registry.json + syncPolicy: + interval: '30m' +``` + +**Git source fields:** + +| Field | Required | Description | +| ------------ | -------- | ----------------------------------------------------- | +| `repository` | Yes | Git repository URL (HTTP/HTTPS/SSH) | +| `branch` | No | Branch name (mutually exclusive with `tag`, `commit`) | +| `tag` | No | Tag name (mutually exclusive with `branch`, `commit`) | +| `commit` | No | Commit SHA (mutually exclusive with `branch`, `tag`) | +| `path` | No | Path to registry file (default: `registry.json`) | + +:::tip + +You can use `branch`, `tag`, or `commit` to pin to a specific version. If +multiple are specified, `commit` takes precedence over `tag`, which takes +precedence over `branch`. + +::: + +### ConfigMap source + +Read from a Kubernetes ConfigMap. Ideal for registry data managed within the +cluster. + +```yaml {7-11} title="registry-configmap.yaml" +apiVersion: toolhive.stacklok.dev/v1alpha1 +kind: MCPRegistry +metadata: + name: configmap-registry +spec: + registries: + - name: local + format: upstream + configMapRef: + name: registry-data + key: registry.json + syncPolicy: + interval: '15m' +``` + +The ConfigMap must exist in the same namespace as the `MCPRegistry` resource. + +### PersistentVolumeClaim source + +Read from a PersistentVolumeClaim. Useful for large registry files or shared +storage scenarios. + +```yaml {7-10} title="registry-pvc.yaml" +apiVersion: toolhive.stacklok.dev/v1alpha1 +kind: MCPRegistry +metadata: + name: pvc-registry +spec: + registries: + - name: shared + format: upstream + pvcRef: + claimName: registry-data-pvc + path: registries/production.json + syncPolicy: + interval: '1h' +``` + +**PVC source fields:** + +| Field | Required | Description | +| ----------- | -------- | ----------------------------------------------------------- | +| `claimName` | Yes | Name of the PersistentVolumeClaim | +| `path` | No | Path to registry file within PVC (default: `registry.json`) | + +The PVC must exist in the same namespace as the `MCPRegistry` resource. + +### API source + +Sync from an upstream MCP Registry API. Supports federation and aggregation +scenarios. + +```yaml {7-10} title="registry-api.yaml" +apiVersion: toolhive.stacklok.dev/v1alpha1 +kind: MCPRegistry +metadata: + name: api-registry +spec: + registries: + - name: upstream + format: upstream + api: + endpoint: https://registry.example.com + syncPolicy: + interval: '1h' +``` + +The controller automatically appends the appropriate API paths to the endpoint +URL. + +### Configure synchronization + +Each registry source can have its own sync policy that controls automatic +synchronization. + +```yaml +syncPolicy: + interval: '30m' # Go duration format: "1h", "30m", "24h" +``` + +### Filter registry content + +You can filter which servers are exposed through the API using name and tag +patterns. + +```yaml {13-20} title="registry-filtered.yaml" +apiVersion: toolhive.stacklok.dev/v1alpha1 +kind: MCPRegistry +metadata: + name: filtered-registry +spec: + registries: + - name: toolhive + format: toolhive + git: + repository: https://github.com/stacklok/toolhive.git + branch: main + path: pkg/registry/data/registry.json + filter: + names: + include: + - 'official/*' + exclude: + - '*/deprecated' + tags: + include: + - production + exclude: + - experimental + syncPolicy: + interval: '30m' +``` + +## Configure database storage + +For production deployments, configure PostgreSQL database storage for +persistence across restarts. + +```yaml {6-15} title="registry-with-database.yaml" +apiVersion: toolhive.stacklok.dev/v1alpha1 +kind: MCPRegistry +metadata: + name: production-registry +spec: + databaseConfig: + host: postgres.database.svc.cluster.local + port: 5432 + user: db_app + migrationUser: db_migrator + database: registry + sslMode: verify-full + maxOpenConns: 25 + maxIdleConns: 5 + connMaxLifetime: '30m' + registries: + - name: toolhive + format: toolhive + git: + repository: https://github.com/stacklok/toolhive.git + branch: main + path: pkg/registry/data/registry.json + syncPolicy: + interval: '30m' +``` + +**Database configuration fields:** + +| Field | Default | Description | +| ----------------- | ------------- | ------------------------------------------------- | +| `host` | `postgres` | Database server hostname | +| `port` | `5432` | Database server port | +| `user` | `db_app` | Application user (SELECT, INSERT, UPDATE, DELETE) | +| `migrationUser` | `db_migrator` | Migration user (CREATE, ALTER, DROP) | +| `database` | `registry` | Database name | +| `sslMode` | `prefer` | SSL mode (disable, prefer, require, verify-full) | +| `maxOpenConns` | `10` | Maximum open connections | +| `maxIdleConns` | `2` | Maximum idle connections | +| `connMaxLifetime` | `30m` | Maximum connection lifetime | + +:::tip + +Provide database passwords using a pgpass file mounted as a secret. See the +[Database configuration](../guides-registry/database.mdx) guide for details on +setting up password security. + +::: + +## Customize the Registry server pod + +You can customize the Registry server pod using the `podTemplateSpec` field. +This gives you full control over the pod specification. + +```yaml {6-15} title="registry-custom-pod.yaml" +apiVersion: toolhive.stacklok.dev/v1alpha1 +kind: MCPRegistry +metadata: + name: custom-registry +spec: + podTemplateSpec: + spec: + containers: + - name: registry-api # This name must be "registry-api" + resources: + limits: + cpu: '500m' + memory: '512Mi' + requests: + cpu: '100m' + memory: '128Mi' + registries: + - name: toolhive + format: toolhive + git: + repository: https://github.com/stacklok/toolhive.git + branch: main + path: pkg/registry/data/registry.json + syncPolicy: + interval: '30m' +``` + +:::info[Container name requirement] + +When customizing containers in `podTemplateSpec`, you must use +`name: registry-api` for the main container to ensure the operator can properly +manage the Registry server. + +::: + +## Check registry status + +To check the status of your registries in a specific namespace: + +```bash +kubectl -n get mcpregistries +``` + +To check registries across all namespaces: + +```bash +kubectl get mcpregistries --all-namespaces +``` + +The status displays the phase, message, and age of each registry. + +For more details about a specific registry: + +```bash +kubectl -n describe mcpregistry +``` + +### Registry phases + +| Phase | Description | +| ------------- | -------------------------------------- | +| `Pending` | The registry is being initialized | +| `Ready` | The registry is ready and operational | +| `Syncing` | The registry is currently syncing data | +| `Failed` | The registry has encountered an error | +| `Terminating` | The registry is being deleted | + +## Next steps + +Learn how to configure authentication for the Registry server in the +[Authentication configuration](../guides-registry/authentication.mdx) guide. + +Configure additional registry sources and filtering options in the +[Configuration](../guides-registry/configuration.mdx) guide. + +Discover your deployed MCP servers automatically using the +[Kubernetes registry](../guides-registry/configuration.mdx#kubernetes-registry) +feature. + +## Related information + +- [Kubernetes CRD reference](../reference/crd-spec.mdx) - Reference for the + `MCPRegistry` Custom Resource Definition (CRD) +- [Deploy the operator using Helm](./deploy-operator-helm.mdx) - Install the + ToolHive operator +- [Database configuration](../guides-registry/database.mdx) - Configure + PostgreSQL storage + +## Troubleshooting + +
+MCPRegistry resource not creating pods + +If your `MCPRegistry` resource is created but no pods appear: + +1. Ensure you created the `MCPRegistry` resource in an allowed namespace +1. Check the operator's configuration: + +```bash +helm get values toolhive-operator -n toolhive-system +``` + +1. Check the MCPRegistry status and operator logs: + +```bash +# Check MCPRegistry status +kubectl -n describe mcpregistry + +# Check operator logs +kubectl -n toolhive-system logs -l app.kubernetes.io/name=toolhive-operator + +# Verify the operator is running +kubectl -n toolhive-system get pods -l app.kubernetes.io/name=toolhive-operator +``` + +Common causes include: + +- **Operator not running**: Ensure the ToolHive operator is deployed and running +- **RBAC issues**: Check for cluster-level permission issues +- **Resource quotas**: Check if namespace resource quotas prevent pod creation + +
+ +
+Registry stuck in Pending or Syncing phase + +If the registry is stuck in `Pending` or `Syncing` phase: + +```bash +# Check registry status +kubectl -n describe mcpregistry + +# Check registry pod logs +kubectl -n logs -l app.kubernetes.io/instance= +``` + +Common causes include: + +- **Git repository inaccessible**: Verify the repository URL is correct and + accessible +- **ConfigMap/PVC doesn't exist**: Ensure referenced resources exist in the same + namespace +- **Network policies**: Check if network policies are blocking external access +- **Invalid registry file format**: Verify the registry JSON file is valid + +
+ +
+Database connection errors + +If you see database connection errors: + +```bash +# Check registry pod logs +kubectl -n logs -l app.kubernetes.io/instance= +``` + +Common causes include: + +- **Database not reachable**: Verify database host and port are correct +- **Invalid credentials**: Check that pgpass file is properly mounted +- **SSL configuration mismatch**: Verify `sslMode` matches your database + configuration +- **Permission issues**: Ensure database users have required privileges + +
+ +
+Sync failures + +If synchronization is failing: + +```bash +# Check sync status +kubectl -n get mcpregistry -o jsonpath='{.status.syncStatus}' + +# Trigger manual sync to see immediate errors +kubectl annotate mcpregistry \ + toolhive.stacklok.dev/sync-trigger="$(date +%s)" \ + --overwrite + +# Check logs +kubectl -n logs -l app.kubernetes.io/instance= +``` + +Common causes include: + +- **Source unavailable**: Git repository, API endpoint, or file is inaccessible +- **Invalid JSON format**: Registry file contains invalid JSON +- **Format mismatch**: The `format` field doesn't match the actual data format +- **Filter too restrictive**: Filters may be excluding all servers + +
diff --git a/docs/toolhive/guides-registry/authentication.mdx b/docs/toolhive/guides-registry/authentication.mdx index 74782286..bd6c8106 100644 --- a/docs/toolhive/guides-registry/authentication.mdx +++ b/docs/toolhive/guides-registry/authentication.mdx @@ -1,7 +1,7 @@ --- title: Authentication configuration description: - How to configure authentication for the ToolHive Registry server with + How to configure authentication for the ToolHive Registry Server with anonymous and OAuth modes --- diff --git a/docs/toolhive/guides-registry/configuration.mdx b/docs/toolhive/guides-registry/configuration.mdx index 2d27de6e..4fc94476 100644 --- a/docs/toolhive/guides-registry/configuration.mdx +++ b/docs/toolhive/guides-registry/configuration.mdx @@ -219,7 +219,7 @@ of workloads. The types being watched are [`MCPRemoteProxy`](../guides-k8s/remote-mcp-proxy.mdx), and [`VirtualMCPServer`](../guides-vmcp/configuration.mdx). -The Registry Server will receive events when a resource among those listed above +The Registry server will receive events when a resource among those listed above is annotated with the following annotations ```yaml @@ -243,7 +243,7 @@ spec: | `toolhive.stacklok.dev/registry-url` | Yes | The external endpoint URL for this server | | `toolhive.stacklok.dev/registry-description` | Yes | Override the description in registry | -This feature requires the Registry Server to be granted access to those +This feature requires the Registry server to be granted access to those resources via a Service Account, check the details in the [deployment section](./deployment.mdx#workload-discovery). @@ -252,7 +252,7 @@ resources via a Service Account, check the details in the **Use cases:** - Discover MCP servers deployed via ToolHive Operator -- Automatically expose running MCP servers to knowledge workers +- Automatically expose running MCP servers to end users - Separate MCP server development from user consumption ## Sync policy diff --git a/docs/toolhive/guides-registry/deployment.mdx b/docs/toolhive/guides-registry/deployment.mdx index b0f709ce..36e73f3f 100644 --- a/docs/toolhive/guides-registry/deployment.mdx +++ b/docs/toolhive/guides-registry/deployment.mdx @@ -1,6 +1,6 @@ --- title: Deployment in Kubernetes -description: How to deploy the ToolHive Registry server in Kubernetes +description: How to deploy the ToolHive Registry Server in Kubernetes --- The Registry server can be deployed in various environments, from local @@ -12,13 +12,20 @@ The Registry server is designed to run as an independent deployment, possibly alongside the ToolHive Operator. Although it is possible to run ToolHive Registry to use an in-memory store, it -is unreliable to run multiple replicas as they would not share state, and we -recommend running it with a proper Postgres database. +is unreliable to run multiple replicas as they would not share state, and you +should run it with a proper Postgres database. -### Deployment Example +### Deployment using the Operator -Below is an example Kubernetes Deployment configuring ToolHive Registry server -to expose a single static registry based on a Git repository. +The recommended way of deploying the Registry server is by using the ToolHive +Operator. See +[Deploy the Registry server in Kubernetes](../guides-k8s/deploy-registry.mdx) +for a complete guide. + +### Manual Deployment + +Below is an example Kubernetes Deployment configuring the ToolHive Registry +Server to expose a single static registry based on a Git repository. This example assumes that a Postgres database is available at `db.example.com` and the necessary users for migration and application execution are configured @@ -176,7 +183,7 @@ of workloads. The types being watched are [`MCPRemoteProxy`](../guides-k8s/remote-mcp-proxy.mdx), and [`VirtualMCPServer`](../guides-vmcp/configuration.mdx). -This feature requires the Registry Server to be granted access to those +This feature requires the Registry server to be granted access to those resources via a Service Account like the following ```yaml title="registry-service-account.yaml" diff --git a/docs/toolhive/guides-registry/index.mdx b/docs/toolhive/guides-registry/index.mdx index d5573f57..bec656ea 100644 --- a/docs/toolhive/guides-registry/index.mdx +++ b/docs/toolhive/guides-registry/index.mdx @@ -1,7 +1,7 @@ --- title: ToolHive Registry Server description: - How-to guides for using the ToolHive Registry server to discover and access + How-to guides for using the ToolHive Registry Server to discover and access MCP servers. --- @@ -10,7 +10,7 @@ import DocCardList from '@theme/DocCardList'; ## Introduction The ToolHive Registry server implements the official -[Model Context Protocol (MCP) Registry API specification](https://github.com/modelcontextprotocol/registry/blob/main/docs/reference/api/generic-registry-api.md). +[Model Context Protocol (MCP) Registry API specification](https://github.com/modelcontextprotocol/registry/blob/main/docs/reference/api/generic-registry-api.md) It provides a standardized REST API for discovering and accessing MCP servers from multiple backend sources, including Kubernetes clusters, Git repositories, API endpoints, and local files. diff --git a/sidebars.ts b/sidebars.ts index 932428b4..3af9d5a6 100644 --- a/sidebars.ts +++ b/sidebars.ts @@ -161,6 +161,7 @@ const sidebars: SidebarsConfig = { 'toolhive/guides-k8s/logging', 'toolhive/guides-k8s/auth-k8s', 'toolhive/guides-k8s/token-exchange-k8s', + 'toolhive/guides-k8s/deploy-registry', 'toolhive/reference/crd-spec', ], }, @@ -193,7 +194,6 @@ const sidebars: SidebarsConfig = { id: 'toolhive/guides-registry/index', }, items: [ - 'toolhive/guides-registry/intro', 'toolhive/guides-registry/configuration', 'toolhive/guides-registry/authentication', 'toolhive/guides-registry/database', From e95c212bcf945801b2f93d18a1c5fc3be9b02b99 Mon Sep 17 00:00:00 2001 From: Michelangelo Mori <328978+blkt@users.noreply.github.com> Date: Thu, 11 Dec 2025 14:52:24 +0100 Subject: [PATCH 2/2] Address PR comments --- docs/toolhive/guides-k8s/deploy-registry.mdx | 12 ++++++------ docs/toolhive/guides-registry/deployment.mdx | 5 ++--- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/docs/toolhive/guides-k8s/deploy-registry.mdx b/docs/toolhive/guides-k8s/deploy-registry.mdx index 34660d8f..93fdce90 100644 --- a/docs/toolhive/guides-k8s/deploy-registry.mdx +++ b/docs/toolhive/guides-k8s/deploy-registry.mdx @@ -53,11 +53,8 @@ flowchart LR ## Create a registry -You can create `MCPRegistry` resources in namespaces based on how the operator -was deployed. - -- **Cluster mode (default)**: Create MCPRegistry resources in any namespace -- **Namespace mode**: Create MCPRegistry resources only in allowed namespaces +You can create `MCPRegistry` resources in the namespaces where the ToolHive +Operator is deployed. See [Deploy the operator](./deploy-operator-helm.mdx#operator-deployment-modes) to learn about the different deployment modes. @@ -360,7 +357,10 @@ spec: When customizing containers in `podTemplateSpec`, you must use `name: registry-api` for the main container to ensure the operator can properly -manage the Registry server. +manage the Registry server. The container name is hardcoded to avoid conflict +issues with user provided containers. Mandating a container name on the Operator +side explicitly tells the Operator it is the main registry server container and +any other containers provided by the use are sidecars/init containers. ::: diff --git a/docs/toolhive/guides-registry/deployment.mdx b/docs/toolhive/guides-registry/deployment.mdx index 36e73f3f..9ae1e944 100644 --- a/docs/toolhive/guides-registry/deployment.mdx +++ b/docs/toolhive/guides-registry/deployment.mdx @@ -15,10 +15,9 @@ Although it is possible to run ToolHive Registry to use an in-memory store, it is unreliable to run multiple replicas as they would not share state, and you should run it with a proper Postgres database. -### Deployment using the Operator +### ToolHive Operator -The recommended way of deploying the Registry server is by using the ToolHive -Operator. See +ToolHive Operator supports deploying the Registry server. See [Deploy the Registry server in Kubernetes](../guides-k8s/deploy-registry.mdx) for a complete guide.