feat: Support env.valueFrom in MCP server config
What type of PR is this?
/kind feature
What this PR does / why we need it:
Changes AgentConfig.spec.mcpServers[].env from a map[string]string to []corev1.EnvVar so each entry can pull its value from a single key of a Secret or ConfigMap via the standard valueFrom shape (secretKeyRef, configMapKeyRef). The existing envFrom (whole-Secret) field is preserved and still wins over env on name collision.
Only SecretKeyRef and ConfigMapKeyRef variants of valueFrom are honored — fieldRef, resourceFieldRef and fileKeyRef are pod-scoped (or file-gated) and meaningless for an MCP server process, so they are rejected with an error. Unlike a pod env, MCP env is resolved by the controller (not the kubelet), so those variants have nothing to resolve against.
Because the env field is now a list rather than a map, this is a breaking change for any AgentConfig that sets mcpServers[].env. The CLI --mcp flag still accepts the {"KEY":"VAL"} shorthand alongside the new [{name,value/valueFrom}] form.
Includes RBAC permission to read ConfigMaps.
Which issue(s) this PR is related to:
Fixes #1152
Special notes for your reviewer:
The shape choice mirrors PodOverrides.Env in api/v1alpha1/task_types.go:78 so MCP env now uses the same idiom users already see elsewhere in the API. Migration for existing YAML:
# Before
env:
DSN: postgres://localhost/db
# After
env:
- name: DSN
value: postgres://localhost/db
Validation is enforced at reconcile time (the Task transitions to Failed with an MCPSecretFailed event and a clear message) rather than at admission. A CRD generated from corev1.EnvVar exposes the full upstream valueFrom schema, and CEL XValidation over that list is rejected by the API server's cost budget — the unbounded upstream string fields can't be given a maxLength, so even a trivial rule blows the per-element budget. Keeping []corev1.EnvVar (consistent with PodOverrides.Env) plus a clear reconcile-time error was preferred over introducing a divergent custom type.
valueFrom entries marked optional now match kubelet semantics: when the referenced Secret/ConfigMap or key is missing, the variable is omitted from the MCP server instead of being set to an empty string.
Does this PR introduce a user-facing change?
[ACTION REQUIRED] AgentConfig: `mcpServers[].env` is now a list of `EnvVar` (matching `PodOverrides.env`) and supports `valueFrom.secretKeyRef` and `valueFrom.configMapKeyRef` for pulling a single key out of a Secret or ConfigMap; other `valueFrom` variants (`fieldRef`, `resourceFieldRef`, `fileKeyRef`) are rejected. A `valueFrom` marked optional whose Secret/ConfigMap or key is missing omits the variable (matching kubelet semantics) instead of setting it empty. The previous `map[string]string` shape is no longer accepted — existing in-cluster AgentConfig objects that set `mcpServers[].env` must be re-applied in the new list form after upgrade.
Summary by cubic
Adds valueFrom support for MCP server env by changing AgentConfig.spec.mcpServers[].env to a list of corev1.EnvVar, enabling per-key Secret/ConfigMap references. envFrom still wins on name collision, the CLI keeps the {"KEY":"VAL"} shorthand, and RBAC/CRDs were updated.
-
New Features
mcpServers[].envis now[]corev1.EnvVarwithvalueFrom.secretKeyRefandvalueFrom.configMapKeyRef.- Controller resolves
valueFromto literals;fieldRef/resourceFieldRefare rejected. envFromcontinues to overrideenvon key collision.- Added permission to read ConfigMaps; CRD/manifests updated.
-
Migration
- Update YAML from map to list. Example:
env: {DSN: "postgres://..."}→env: [{name: "DSN", value: "postgres://..."}]. The CLI--mcpflag still accepts the old map shorthand.
- Update YAML from map to list. Example: