Skip to main content

Migrate from the operator to Helm

The MCPRegistry CRD and the operator-managed deployment method are deprecated in favor of the toolhive-registry-server Helm chart, which installs the Registry Server directly. This guide walks you through moving an existing operator-managed registry to the Helm chart.

The CRD remains fully functional for now, so you can migrate at your own pace. This guide uses a parallel cutover: you deploy the Helm release alongside your existing MCPRegistry, verify it, repoint clients, and only then remove the CRD-managed deployment.

Why migrate?

The Helm chart manages the Registry Server like any other Helm release, without requiring the ToolHive Operator. The MCPRegistry CRD will be removed in a future release. Migrating now avoids a forced cutover later.

Before you begin

  • A Kubernetes cluster with an existing operator-managed MCPRegistry resource
  • kubectl configured to communicate with your cluster
  • Helm v3.10 or later (v3.14+ is recommended)
  • Access to the same PostgreSQL database your MCPRegistry currently uses

Both deployment methods read the same Registry Server configuration and connect to the same PostgreSQL schema, so the Helm release can reuse your existing database without a data migration.

How configuration maps

The operator wraps the Registry Server's configuration in the MCPRegistry spec. The Helm chart exposes the same configuration directly in its values file. The table below maps each MCPRegistry field to its Helm equivalent.

MCPRegistry spec fieldHelm values field
spec.configYAMLconfig (as structured YAML, not a string)
spec.pgpassSecretRefpgpass Secret + init container (see below)
spec.podTemplateSpec.…resourcesresources
spec.volumesextraVolumes
spec.volumeMountsextraVolumeMounts
spec.displayNameNo equivalent (metadata only; omit)

The most important change is configYAML: in the CRD it's a YAML string, while in the Helm chart the same content goes under config as a structured block. The schema under both is identical.

Step 1: Capture your existing configuration

Export your current MCPRegistry resource so you can copy its configuration:

kubectl -n <NAMESPACE> get mcpregistry <NAME> -o yaml > mcpregistry-backup.yaml

Note the value of spec.configYAML. This is the configuration you'll move into the Helm values file. Also note the namespace and any database settings so the Helm release connects to the same PostgreSQL instance.

Step 2: Build the Helm values file

Create a values.yaml file and copy the contents of spec.configYAML under the config key. For example, an MCPRegistry with this spec:

mcpregistry-backup.yaml (excerpt)
spec:
displayName: My MCP Registry
configYAML: |
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'
registries:
- name: default
sources: ['toolhive']
auth:
mode: anonymous

becomes this Helm values file:

values.yaml
config:
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'
registries:
- name: default
sources: ['toolhive']
auth:
mode: anonymous

If your MCPRegistry used pgpassSecretRef for database credentials, the Helm chart provides the same credentials through a pgpass Secret and an init container that prepares the file. See Provide database credentials for the complete pattern, then add the extraEnv, extraVolumes, extraVolumeMounts, and initContainers blocks to your values file.

Step 3: Deploy the Helm release

Install the chart into the same namespace as your existing registry. Use a release name that doesn't collide with the operator-managed resources:

helm upgrade --install registry-server \
oci://ghcr.io/stacklok/toolhive-registry-server \
-n <NAMESPACE> --create-namespace \
-f values.yaml

Because both deployments point at the same database, the Helm-managed pod runs against your existing data. See Deploy with Helm for the full set of chart values and their defaults.

Step 4: Verify the new deployment

Confirm the Helm-managed Registry Server pod is running and healthy:

kubectl -n <NAMESPACE> get pods -l app.kubernetes.io/instance=registry-server

Port-forward to the new service and check that it serves registry data:

kubectl -n <NAMESPACE> port-forward svc/registry-server 8080:80
curl http://localhost:8080/v0/servers

The Helm release creates a service named after the release (for example, registry-server), which differs from the service the operator created for your MCPRegistry. Note the new service name and endpoint for the next step.

Step 5: Repoint clients

Update any clients, ingress rules, or VirtualMCPServer backends that reference the old operator-managed service so they point at the new Helm-managed service endpoint. Roll out and verify these changes while the old deployment is still running, so you can fall back if needed.

Step 6: Remove the MCPRegistry resource

Once clients are using the Helm-managed Registry Server and you've confirmed it's healthy, delete the MCPRegistry resource. The operator removes the deployment, service, and RBAC resources it created:

kubectl -n <NAMESPACE> delete mcpregistry <NAME>

Deleting the MCPRegistry does not affect the database, so your registry data remains intact for the Helm-managed server.

If the operator is no longer managing any other resources, you can optionally uninstall it. See Deploy the operator for details on what the operator manages before removing it.

Next steps