ToolHive Operator Helm Chart

July 22, 2026 ยท View on GitHub

Version: 0.40.1 Type: application

A Helm chart for deploying the ToolHive Operator into Kubernetes.


TL;DR

helm upgrade -i toolhive-operator oci://ghcr.io/stacklok/toolhive/toolhive-operator -n toolhive-system --create-namespace

Prerequisites

  • Kubernetes 1.25+
  • Helm 3.10+ minimum, 3.14+ recommended

Usage

Installing from the Chart

Install one of the available versions:

helm upgrade -i <release_name> oci://ghcr.io/stacklok/toolhive/toolhive-operator --version=<version> -n toolhive-system --create-namespace

Tip: List all releases using helm list

Uninstalling the Chart

To uninstall/delete the toolhive-operator deployment:

helm uninstall <release_name>

The command removes all the Kubernetes components associated with the chart and deletes the release. You will have to delete the namespace manually if you used Helm to create it.

Values

KeyTypeDefaultDescription
fullnameOverridestring"toolhive-operator"Provide a fully-qualified name override for resources
nameOverridestring""Override the name of the chart
operatorobject{"affinity":{},"autoscaling":{"enabled":false,"maxReplicas":100,"minReplicas":1,"targetCPUUtilizationPercentage":80},"containerSecurityContext":{"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]},"readOnlyRootFilesystem":true,"runAsNonRoot":true,"runAsUser":1000,"seccompProfile":{"type":"RuntimeDefault"}},"defaultImagePullSecrets":[],"defaultRedis":{"addr":"","existingSecret":"","existingSecretKey":""},"env":[],"features":{"experimental":false,"storageVersionMigrator":true},"gc":{"gogc":75,"gomemlimit":"110MiB"},"image":"ghcr.io/stacklok/toolhive/operator:v0.40.1","imagePullPolicy":"IfNotPresent","imagePullSecrets":[],"leaderElectionRole":{"binding":{"name":"toolhive-operator-leader-election-rolebinding"},"name":"toolhive-operator-leader-election-role","rules":[{"apiGroups":[""],"resources":["configmaps"],"verbs":["get","list","watch","create","update","patch","delete"]},{"apiGroups":["coordination.k8s.io"],"resources":["leases"],"verbs":["get","list","watch","create","update","patch","delete"]},{"apiGroups":["events.k8s.io"],"resources":["events"],"verbs":["create","patch"]}]},"livenessProbe":{"httpGet":{"path":"/healthz","port":"health"},"initialDelaySeconds":15,"periodSeconds":20},"nodeSelector":{},"podAnnotations":{},"podLabels":{},"podSecurityContext":{"runAsNonRoot":true},"ports":[{"containerPort":8080,"name":"metrics","protocol":"TCP"},{"containerPort":8081,"name":"health","protocol":"TCP"}],"proxyHost":"0.0.0.0","rbac":{"allowedNamespaces":[],"scope":"cluster"},"readinessProbe":{"httpGet":{"path":"/readyz","port":"health"},"initialDelaySeconds":5,"periodSeconds":10},"replicaCount":1,"resources":{"limits":{"cpu":"500m","memory":"128Mi"},"requests":{"cpu":"10m","memory":"64Mi"}},"serviceAccount":{"annotations":{},"automountServiceAccountToken":true,"create":true,"labels":{},"name":"toolhive-operator"},"tolerations":[],"toolhiveRunnerImage":"ghcr.io/stacklok/toolhive/proxyrunner:v0.40.1","vmcpImage":"ghcr.io/stacklok/toolhive/vmcp:v0.40.1","volumeMounts":[],"volumes":[]}All values for the operator deployment and associated resources
operator.affinityobject{}Affinity settings for the operator pod
operator.autoscalingobject{"enabled":false,"maxReplicas":100,"minReplicas":1,"targetCPUUtilizationPercentage":80}Configuration for horizontal pod autoscaling
operator.autoscaling.enabledboolfalseEnable autoscaling for the operator
operator.autoscaling.maxReplicasint100Maximum number of replicas
operator.autoscaling.minReplicasint1Minimum number of replicas
operator.autoscaling.targetCPUUtilizationPercentageint80Target CPU utilization percentage for autoscaling
operator.containerSecurityContextobject{"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]},"readOnlyRootFilesystem":true,"runAsNonRoot":true,"runAsUser":1000,"seccompProfile":{"type":"RuntimeDefault"}}Container security context settings for the operator
operator.defaultImagePullSecretslist[]List of image pull secrets that the operator applies as defaults to every workload it spawns (proxy runners, vMCP servers, registry API, etc.). Per-CR imagePullSecrets take precedence on name collisions; chart-level entries are appended additively. The operator parses these once at startup from the TOOLHIVE_DEFAULT_IMAGE_PULL_SECRETS environment variable. The Secrets must exist in the namespace where each workload is created. Each entry may be either a plain string (the Secret name) or an object with a name field, e.g.: defaultImagePullSecrets: - regcred - name: otherscred The two shapes are equivalent; the object form matches operator.imagePullSecrets above for convenience.
operator.defaultRedisobject{"addr":"","existingSecret":"","existingSecretKey":""}Default Redis/Valkey address used by the operator when a workload CR has no sessionStorage configured. The operator injects this as TOOLHIVE_DEFAULT_REDIS_ADDR on pods it creates. When empty, no global Redis default is active. Override per-CR with spec.sessionStorage. global.redis.host (from a parent umbrella chart) is used as fallback when addr is empty here. Both express the same addr concept; addr takes precedence. For the password, reference a pre-existing Kubernetes Secret: defaultRedis: addr: "myredis.svc:6379" existingSecret: "redis-credentials" existingSecretKey: "password"
operator.defaultRedis.addrstring""addr is the Redis/Valkey address (host:port).
operator.defaultRedis.existingSecretstring""existingSecret is the name of a Secret containing the Redis password.
operator.defaultRedis.existingSecretKeystring""existingSecretKey is the key within existingSecret that holds the password. Empty means use global.redis.existingSecretKey or fall back to "redis-password".
operator.envlist[]Environment variables to set in the operator container. Supported toolhive-specific variables include: - TOOLHIVE_SKIP_UPDATE_CHECK: set to "true" to disable the operator's periodic update check against the ToolHive update API. Also disables the usage-metrics collection that is gated on the same check.
operator.features.experimentalboolfalseEnable experimental features
operator.features.storageVersionMigratorbooltrueEnable the StorageVersionMigrator controller, which auto-cleans status.storedVersions on opted-in toolhive.stacklok.dev CRDs so a future release can drop deprecated versions (e.g. v1alpha1) without orphaning etcd objects in the cluster. Enabled by default; set to false to opt out and handle storage-version cleanup yourself. Sets TOOLHIVE_ENABLE_STORAGE_VERSION_MIGRATOR in the operator deployment. Requires operator.rbac.scope=cluster โ€” the controller watches cluster-scoped CRDs and re-stores resources across all namespaces, so the chart rejects this being true when scope is namespace.
operator.gcobject{"gogc":75,"gomemlimit":"110MiB"}Go memory limits and garbage collection percentage for the operator container
operator.gc.gogcint75Go garbage collection percentage for the operator container
operator.gc.gomemlimitstring"110MiB"Go memory limits for the operator container
operator.imagestring"ghcr.io/stacklok/toolhive/operator:v0.40.1"Container image for the operator
operator.imagePullPolicystring"IfNotPresent"Image pull policy for the operator container
operator.imagePullSecretslist[]List of image pull secrets to use
operator.leaderElectionRoleobject{"binding":{"name":"toolhive-operator-leader-election-rolebinding"},"name":"toolhive-operator-leader-election-role","rules":[{"apiGroups":[""],"resources":["configmaps"],"verbs":["get","list","watch","create","update","patch","delete"]},{"apiGroups":["coordination.k8s.io"],"resources":["leases"],"verbs":["get","list","watch","create","update","patch","delete"]},{"apiGroups":["events.k8s.io"],"resources":["events"],"verbs":["create","patch"]}]}Leader election role configuration
operator.leaderElectionRole.binding.namestring"toolhive-operator-leader-election-rolebinding"Name of the role binding for leader election
operator.leaderElectionRole.namestring"toolhive-operator-leader-election-role"Name of the role for leader election
operator.leaderElectionRole.ruleslist[{"apiGroups":[""],"resources":["configmaps"],"verbs":["get","list","watch","create","update","patch","delete"]},{"apiGroups":["coordination.k8s.io"],"resources":["leases"],"verbs":["get","list","watch","create","update","patch","delete"]},{"apiGroups":["events.k8s.io"],"resources":["events"],"verbs":["create","patch"]}]Rules for the leader election role
operator.livenessProbeobject{"httpGet":{"path":"/healthz","port":"health"},"initialDelaySeconds":15,"periodSeconds":20}Liveness probe configuration for the operator
operator.nodeSelectorobject{}Node selector for the operator pod
operator.podAnnotationsobject{}Annotations to add to the operator pod
operator.podLabelsobject{}Labels to add to the operator pod
operator.podSecurityContextobject{"runAsNonRoot":true}Pod security context settings
operator.portslist[{"containerPort":8080,"name":"metrics","protocol":"TCP"},{"containerPort":8081,"name":"health","protocol":"TCP"}]List of ports to expose from the operator container
operator.proxyHoststring"0.0.0.0"Host for the proxy deployed by the operator
operator.rbacobject{"allowedNamespaces":[],"scope":"cluster"}RBAC configuration for the operator
operator.rbac.allowedNamespaceslist[]List of namespaces that the operator is allowed to have permissions to manage. Only used if scope is set to "namespace".
operator.rbac.scopestring"cluster"Scope of the RBAC configuration. - cluster: The operator will have cluster-wide permissions via ClusterRole and ClusterRoleBinding. - namespace: The operator will have permissions to manage resources in the namespaces specified in allowedNamespaces. The operator will have a ClusterRole and RoleBinding for each namespace in allowedNamespaces.
operator.readinessProbeobject{"httpGet":{"path":"/readyz","port":"health"},"initialDelaySeconds":5,"periodSeconds":10}Readiness probe configuration for the operator
operator.replicaCountint1Number of replicas for the operator deployment
operator.resourcesobject{"limits":{"cpu":"500m","memory":"128Mi"},"requests":{"cpu":"10m","memory":"64Mi"}}Resource requests and limits for the operator container
operator.serviceAccountobject{"annotations":{},"automountServiceAccountToken":true,"create":true,"labels":{},"name":"toolhive-operator"}Service account configuration for the operator
operator.serviceAccount.annotationsobject{}Annotations to add to the service account
operator.serviceAccount.automountServiceAccountTokenbooltrueAutomatically mount a ServiceAccount's API credentials
operator.serviceAccount.createbooltrueSpecifies whether a service account should be created
operator.serviceAccount.labelsobject{}Labels to add to the service account
operator.serviceAccount.namestring"toolhive-operator"The name of the service account to use. If not set and create is true, a name is generated.
operator.tolerationslist[]Tolerations for the operator pod
operator.toolhiveRunnerImagestring"ghcr.io/stacklok/toolhive/proxyrunner:v0.40.1"Image to use for Toolhive runners
operator.vmcpImagestring"ghcr.io/stacklok/toolhive/vmcp:v0.40.1"Image to use for Virtual MCP Server (vMCP) deployments
operator.volumeMountslist[]Additional volume mounts on the operator container
operator.volumeslist[]Additional volumes to mount on the operator pod
registryAPIobject{"image":"ghcr.io/stacklok/thv-registry-api:v1.3.0"}All values for the registry API deployment and associated resources
registryAPI.imagestring"ghcr.io/stacklok/thv-registry-api:v1.3.0"Container image for the registry API

Contributing

See CONTRIBUTING.md for guidelines on contributing to this chart.