From 670afff001104d6fc7f04b92d5867727ed33b04a Mon Sep 17 00:00:00 2001 From: Jakub Hrozek Date: Fri, 28 Nov 2025 20:47:21 +0000 Subject: [PATCH 1/2] Add vMCP image to operator-deploy-local task The operator-deploy-local task now builds and loads the vMCP image into Kind alongside the operator and proxyrunner images. This makes local development easier when working with VirtualMCPServer resources. Changes: - Add VMCP_IMAGE variable to operator-deploy-local task - Add vmcpImage to operator Helm chart values - Set VMCP_IMAGE env var in operator deployment template --- .github/workflows/test-e2e-lifecycle.yml | 3 +-- cmd/thv-operator/Taskfile.yml | 5 +++++ deploy/charts/operator/README.md | 3 ++- deploy/charts/operator/templates/deployment.yaml | 2 ++ deploy/charts/operator/values.yaml | 3 +++ 5 files changed, 13 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test-e2e-lifecycle.yml b/.github/workflows/test-e2e-lifecycle.yml index 697ecedf8..b9c6bacad 100644 --- a/.github/workflows/test-e2e-lifecycle.yml +++ b/.github/workflows/test-e2e-lifecycle.yml @@ -102,8 +102,7 @@ jobs: helm upgrade --install toolhive-operator deploy/charts/operator \ --set operator.image=${OPERATOR_IMAGE} \ --set operator.toolhiveRunnerImage=${TOOLHIVE_IMAGE} \ - --set-string 'operator.env[0].name=VMCP_IMAGE' \ - --set-string "operator.env[0].value=${{ env.VMCP_IMAGE }}" \ + --set operator.vmcpImage=${{ env.VMCP_IMAGE }} \ --namespace toolhive-system \ --create-namespace \ --kubeconfig kconfig.yaml diff --git a/cmd/thv-operator/Taskfile.yml b/cmd/thv-operator/Taskfile.yml index 52cf8e1af..f0005c19d 100644 --- a/cmd/thv-operator/Taskfile.yml +++ b/cmd/thv-operator/Taskfile.yml @@ -142,15 +142,20 @@ tasks: sh: KO_DOCKER_REPO=kind.local ko build --local -B ./cmd/thv-operator | tail -n 1 TOOLHIVE_IMAGE: sh: KO_DOCKER_REPO=kind.local ko build --local -B ./cmd/thv-proxyrunner | tail -n 1 + VMCP_IMAGE: + sh: KO_DOCKER_REPO=kind.local ko build --local -B ./cmd/vmcp | tail -n 1 cmds: - echo "Loading toolhive operator image {{.OPERATOR_IMAGE}} into kind..." - kind load docker-image --name toolhive {{.OPERATOR_IMAGE}} - echo "Loading toolhive image {{.TOOLHIVE_IMAGE}} into kind..." - kind load docker-image --name toolhive {{.TOOLHIVE_IMAGE}} + - echo "Loading vmcp image {{.VMCP_IMAGE}} into kind..." + - kind load docker-image --name toolhive {{.VMCP_IMAGE}} - | helm upgrade --install toolhive-operator deploy/charts/operator \ --set operator.image={{.OPERATOR_IMAGE}} \ --set operator.toolhiveRunnerImage={{.TOOLHIVE_IMAGE}} \ + --set operator.vmcpImage={{.VMCP_IMAGE}} \ --set operator.features.experimental={{.ENABLE_EXPERIMENTAL_FEATURES}} \ --set registryAPI.image={{.REGISTRY_API_IMAGE}} \ --namespace toolhive-system \ diff --git a/deploy/charts/operator/README.md b/deploy/charts/operator/README.md index ab65fe785..534de51b6 100644 --- a/deploy/charts/operator/README.md +++ b/deploy/charts/operator/README.md @@ -52,7 +52,7 @@ The command removes all the Kubernetes components associated with the chart and |-----|-------------|------|---------| | fullnameOverride | string | `"toolhive-operator"` | Provide a fully-qualified name override for resources | | nameOverride | string | `""` | Override the name of the chart | -| operator | object | `{"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"}},"env":{},"features":{"experimental":false},"gc":{"gogc":75,"gomeglimit":"150MiB"},"image":"ghcr.io/stacklok/toolhive/operator:v0.6.9","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":[""],"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.6.9","volumeMounts":[],"volumes":[]}` | All values for the operator deployment and associated resources | +| operator | object | `{"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"}},"env":{},"features":{"experimental":false},"gc":{"gogc":75,"gomeglimit":"150MiB"},"image":"ghcr.io/stacklok/toolhive/operator:v0.6.9","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":[""],"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.6.9","vmcpImage":"ghcr.io/stacklok/toolhive/vmcp:v0.6.9","volumeMounts":[],"volumes":[]}` | All values for the operator deployment and associated resources | | operator.affinity | object | `{}` | Affinity settings for the operator pod | | operator.autoscaling | object | `{"enabled":false,"maxReplicas":100,"minReplicas":1,"targetCPUUtilizationPercentage":80}` | Configuration for horizontal pod autoscaling | | operator.autoscaling.enabled | bool | `false` | Enable autoscaling for the operator | @@ -92,6 +92,7 @@ The command removes all the Kubernetes components associated with the chart and | operator.serviceAccount.name | string | `"toolhive-operator"` | The name of the service account to use. If not set and create is true, a name is generated. | | operator.tolerations | list | `[]` | Tolerations for the operator pod | | operator.toolhiveRunnerImage | string | `"ghcr.io/stacklok/toolhive/proxyrunner:v0.6.9"` | Image to use for Toolhive runners | +| operator.vmcpImage | string | `"ghcr.io/stacklok/toolhive/vmcp:v0.6.9"` | Image to use for Virtual MCP Server (vMCP) deployments | | operator.volumeMounts | list | `[]` | Additional volume mounts on the operator container | | operator.volumes | list | `[]` | Additional volumes to mount on the operator pod | | registryAPI | object | `{"image":"ghcr.io/stacklok/thv-registry-api:v0.3.1","serviceAccount":{"annotations":{},"automountServiceAccountToken":true,"labels":{},"name":"toolhive-registry-api"}}` | All values for the registry API deployment and associated resources | diff --git a/deploy/charts/operator/templates/deployment.yaml b/deploy/charts/operator/templates/deployment.yaml index d42e00f19..19f34e9d0 100644 --- a/deploy/charts/operator/templates/deployment.yaml +++ b/deploy/charts/operator/templates/deployment.yaml @@ -64,6 +64,8 @@ spec: {{- end }} - name: TOOLHIVE_RUNNER_IMAGE value: "{{ .Values.operator.toolhiveRunnerImage }}" + - name: VMCP_IMAGE + value: "{{ .Values.operator.vmcpImage }}" - name: TOOLHIVE_PROXY_HOST value: "{{ .Values.operator.proxyHost }}" - name: TOOLHIVE_REGISTRY_API_IMAGE diff --git a/deploy/charts/operator/values.yaml b/deploy/charts/operator/values.yaml index 2c81bc8e0..5149df8a7 100644 --- a/deploy/charts/operator/values.yaml +++ b/deploy/charts/operator/values.yaml @@ -21,6 +21,9 @@ operator: # -- Image to use for Toolhive runners toolhiveRunnerImage: ghcr.io/stacklok/toolhive/proxyrunner:v0.6.9 + # -- Image to use for Virtual MCP Server (vMCP) deployments + vmcpImage: ghcr.io/stacklok/toolhive/vmcp:v0.6.9 + # -- Host for the proxy deployed by the operator proxyHost: 0.0.0.0 From a7d80fdde0eaeb58ba8325728b5ee29e4e3d44b7 Mon Sep 17 00:00:00 2001 From: Jakub Hrozek Date: Sun, 30 Nov 2025 18:10:01 +0000 Subject: [PATCH 2/2] Bump Helm chart version to 0.5.5 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bump the operator Helm chart version to fix CI failure. The chart was modified to add the vmcpImage value but the version wasn't bumped. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- deploy/charts/operator/Chart.yaml | 2 +- deploy/charts/operator/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/deploy/charts/operator/Chart.yaml b/deploy/charts/operator/Chart.yaml index da929a731..435d45299 100644 --- a/deploy/charts/operator/Chart.yaml +++ b/deploy/charts/operator/Chart.yaml @@ -2,5 +2,5 @@ apiVersion: v2 name: toolhive-operator description: A Helm chart for deploying the ToolHive Operator into Kubernetes. type: application -version: 0.5.4 +version: 0.5.5 appVersion: "v0.6.9" diff --git a/deploy/charts/operator/README.md b/deploy/charts/operator/README.md index 534de51b6..5af108046 100644 --- a/deploy/charts/operator/README.md +++ b/deploy/charts/operator/README.md @@ -1,6 +1,6 @@ # ToolHive Operator Helm Chart -![Version: 0.5.4](https://img.shields.io/badge/Version-0.5.4-informational?style=flat-square) +![Version: 0.5.5](https://img.shields.io/badge/Version-0.5.5-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) A Helm chart for deploying the ToolHive Operator into Kubernetes.