Skip to content

Volumes Not Mounted in Pods #2606

@therealnb

Description

@therealnb

Type: Missing feature / regression
Introduced: November 10, 2025

Description

Volumes defined in spec.volumes are accepted by the MCPServer CRD but are never:

  1. Added to runconfig.json
  2. Created in the pod spec
  3. Mounted in the container

This makes it impossible to deploy applications that need writable filesystem access (databases, caches, logs) because the operator enforces readOnlyRootFilesystem: true.

Root Cause

File: cmd/thv-operator/controllers/mcpserver_runconfig.go:87

envVars := convertEnvVarsFromMCPServer(m.Spec.Env)
volumes := convertVolumesFromMCPServer(m.Spec.Volumes)  // ← Converted but never used!

The volumes are read and converted to the builder format, but they're never:

  • Added to the runconfig.json (not in the RunConfigBuilder options)
  • Applied to the pod spec when creating workloads

Steps to Reproduce

  1. Create an MCPServer with volumes:
apiVersion: toolhive.stacklok.dev/v1alpha1
kind: MCPServer
metadata:
  name: test-server
spec:
  image: my-image:latest
  volumes:
    - name: data
      hostPath: ""  # emptyDir
      mountPath: /data
      readOnly: false
  env:
    - name: DATA_PATH
      value: /data
  1. Deploy and check the runconfig:
kubectl get configmap test-server-runconfig -o jsonpath='{.data.runconfig\.json}' | jq '.volumes'
# Output: null
  1. Check the pod spec:
kubectl get pod test-server-0 -o jsonpath='{.spec.volumes[*].name}'
# Output: Only "kube-api-access-*" (no user-defined volumes)

kubectl get pod test-server-0 -o jsonpath='{.spec.containers[0].volumeMounts}' | jq
# Output: Only serviceaccount mount (no user-defined mounts)
  1. Application fails trying to write:
kubectl logs test-server-0
# Error: unable to open database file
# Or: Read-only file system

Expected Behavior

Volumes defined in spec.volumes should be:

  1. Included in runconfig.json OR applied directly to pod spec
  2. Created as Kubernetes volumes in the pod
  3. Mounted in the container at the specified mount paths
  4. Writable (when readOnly: false)

Actual Behavior

  • Volumes are accepted in MCPServer CRD validation ✓
  • Volumes appear in spec.volumes
  • Volumes are NOT in runconfig.json ✗
  • Volumes are NOT in pod spec ✗
  • Applications crash trying to write to read-only filesystem ✗

Impact

  • Blocks critical deployments: Applications needing disk writes cannot be deployed
  • No workaround available: Cannot be fixed from MCPServer configuration
  • Affects MCP Optimizer: Cannot deploy the official MCP Optimizer in Kubernetes
  • Security conflict: readOnlyRootFilesystem: true (good security) + no volume mounts (bug) = impossible to write files

Evidence from MCP Optimizer Deployment

Security Context Applied by Operator:

{
  "allowPrivilegeEscalation": false,
  "privileged": false,
  "readOnlyRootFilesystem": true,  // ← Makes entire filesystem read-only
  "runAsNonRoot": true,
  "runAsUser": 1000
}

MCPServer Configuration:

spec:
  volumes:
    - name: data
      hostPath: ""
      mountPath: /data
      readOnly: false
  env:
    - name: DB_URL
      value: "sqlite:///data/mcp_optimizer.db"

Result:

  • Volume not mounted
  • /data directory doesn't exist or is read-only
  • SQLite error: unable to open database file
  • Pod in CrashLoopBackOff

What Used to Work (Before Nov 10, 2025)

The original configuration in helm/mcp-optimizer/values.yaml (commit 48921bc):

spec:
  podTemplateSpec:
    spec:
      volumes:
        - name: data
          emptyDir: {}
        - name: tmp
          emptyDir: {}
      containers:
        - name: mcp
          volumeMounts:
            - name: data
              mountPath: /data
            - name: tmp
              mountPath: /tmp
          env:
            - name: DB_URL
              value: "sqlite:///data/mcp_optimizer.db"

This worked because the operator:

  1. Read podTemplateSpec
  2. Converted it to CLI flags for thv-proxyrunner
  3. Proxyrunner created pods with proper volumes and env vars

Environment

  • ToolHive Operator Version: 0.2.22
  • ToolHive Operator CRDs: 0.0.34
  • Kubernetes: Rancher Desktop (Docker-based)
  • Test Application: MCP Optimizer v0.1.1
  • Test Date: November 17, 2025

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingkubernetesItems related to Kubernetesoperator

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions