Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 36 additions & 1 deletion api/v1alpha1/mcpserver_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ limitations under the License.
package v1alpha1

import (
"encoding/json"

corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
Expand Down Expand Up @@ -215,7 +217,7 @@ type MCPServerDeployment struct {

// Env defines the environment variables to set in the container.
// +optional
Env map[string]string `json:"env,omitempty"`
Env map[string]EnvVarCfg `json:"env,omitempty"`

// SecretRefs defines the list of Kubernetes secrets to reference.
// These secrets will be mounted as volumes to the MCP server container.
Expand Down Expand Up @@ -247,6 +249,39 @@ type MCPServerDeployment struct {
ServiceAccount *ServiceAccountConfig `json:"serviceAccount,omitempty"`
}

// EnvVarCfg allows specifying either a literal value or a reference to a source for the environment variable.
type EnvVarCfg struct {
// Value contains the value for the environment variable.
// Defaults to "" if not set.
// +optional
Value string `json:"value,omitempty"`

// ValueFrom specifies a source the value of this EnvVar to come from.
// +optional
ValueFrom *corev1.EnvVarSource `json:"valueFrom,omitempty"`
}

// UnmarshalJSON implements json.Unmarshaler for EnvVarCfg.
// It allows unmarshalling a plain string into the Value field, or an object into Value/ValueFrom.
func (e *EnvVarCfg) UnmarshalJSON(data []byte) error {
// Try to unmarshal as a string
var str string
if err := json.Unmarshal(data, &str); err == nil {
e.Value = str
return nil
}

// If not a string, try to unmarshal as an object
type rawEnvVarCfg EnvVarCfg // Use a new type to avoid infinite recursion
var raw rawEnvVarCfg
if err := json.Unmarshal(data, &raw); err != nil {
return err
}
e.Value = raw.Value
e.ValueFrom = raw.ValueFrom
return nil
}

// InitContainerConfig defines the configuration for the init container.
type InitContainerConfig struct {
// Image defines the full image reference for the init container.
Expand Down
24 changes: 22 additions & 2 deletions api/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

104 changes: 103 additions & 1 deletion config/crd/bases/kagent.dev_mcpservers.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,109 @@ spec:
type: array
env:
additionalProperties:
type: string
description: EnvVarCfg allows specifying either a literal value
or a reference to a source for the environment variable.
properties:
value:
description: |-
Value contains the value for the environment variable.
Defaults to "" if not set.
type: string
valueFrom:
description: ValueFrom specifies a source the value of this
EnvVar to come from.
properties:
configMapKeyRef:
description: Selects a key of a ConfigMap.
properties:
key:
description: The key to select.
type: string
name:
default: ""
description: |-
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
type: string
optional:
description: Specify whether the ConfigMap or its
key must be defined
type: boolean
required:
- key
type: object
x-kubernetes-map-type: atomic
fieldRef:
description: |-
Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['<KEY>']`, `metadata.annotations['<KEY>']`,
spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs.
properties:
apiVersion:
description: Version of the schema the FieldPath
is written in terms of, defaults to "v1".
type: string
fieldPath:
description: Path of the field to select in the
specified API version.
type: string
required:
- fieldPath
type: object
x-kubernetes-map-type: atomic
resourceFieldRef:
description: |-
Selects a resource of the container: only resources limits and requests
(limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported.
properties:
containerName:
description: 'Container name: required for volumes,
optional for env vars'
type: string
divisor:
anyOf:
- type: integer
- type: string
description: Specifies the output format of the
exposed resources, defaults to "1"
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
x-kubernetes-int-or-string: true
resource:
description: 'Required: resource to select'
type: string
required:
- resource
type: object
x-kubernetes-map-type: atomic
secretKeyRef:
description: Selects a key of a secret in the pod's
namespace
properties:
key:
description: The key of the secret to select from. Must
be a valid secret key.
type: string
name:
default: ""
description: |-
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
type: string
optional:
description: Specify whether the Secret or its key
must be defined
type: boolean
required:
- key
type: object
x-kubernetes-map-type: atomic
type: object
type: object
description: Env defines the environment variables to set in the
container.
type: object
Expand Down
104 changes: 103 additions & 1 deletion helm/kmcp-crds/templates/mcpserver-crd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,109 @@ spec:
type: array
env:
additionalProperties:
type: string
description: EnvVarCfg allows specifying either a literal value
or a reference to a source for the environment variable.
properties:
value:
description: |-
Value contains the value for the environment variable.
Defaults to "" if not set.
type: string
valueFrom:
description: ValueFrom specifies a source the value of this
EnvVar to come from.
properties:
configMapKeyRef:
description: Selects a key of a ConfigMap.
properties:
key:
description: The key to select.
type: string
name:
default: ""
description: |-
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
type: string
optional:
description: Specify whether the ConfigMap or its
key must be defined
type: boolean
required:
- key
type: object
x-kubernetes-map-type: atomic
fieldRef:
description: |-
Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['<KEY>']`, `metadata.annotations['<KEY>']`,
spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs.
properties:
apiVersion:
description: Version of the schema the FieldPath
is written in terms of, defaults to "v1".
type: string
fieldPath:
description: Path of the field to select in the
specified API version.
type: string
required:
- fieldPath
type: object
x-kubernetes-map-type: atomic
resourceFieldRef:
description: |-
Selects a resource of the container: only resources limits and requests
(limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported.
properties:
containerName:
description: 'Container name: required for volumes,
optional for env vars'
type: string
divisor:
anyOf:
- type: integer
- type: string
description: Specifies the output format of the
exposed resources, defaults to "1"
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
x-kubernetes-int-or-string: true
resource:
description: 'Required: resource to select'
type: string
required:
- resource
type: object
x-kubernetes-map-type: atomic
secretKeyRef:
description: Selects a key of a secret in the pod's
namespace
properties:
key:
description: The key of the secret to select from. Must
be a valid secret key.
type: string
name:
default: ""
description: |-
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
type: string
optional:
description: Specify whether the Secret or its key
must be defined
type: boolean
required:
- key
type: object
x-kubernetes-map-type: atomic
type: object
type: object
description: Env defines the environment variables to set in the
container.
type: object
Expand Down
13 changes: 11 additions & 2 deletions pkg/cli/internal/commands/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ func runPackageDeploy(_ *cobra.Command, _ []string) error {
Port: uint16(port),
Cmd: packageManager,
Args: deployArgs,
Env: envMap,
Env: toEnvVarCfgMap(envMap),
SecretRefs: secretRefs,
},
TransportType: getTransportType(),
Expand Down Expand Up @@ -468,7 +468,7 @@ func generateMCPServer(
Port: uint16(port),
Cmd: command,
Args: args,
Env: envVars,
Env: toEnvVarCfgMap(envVars),
SecretRefs: secretRefs,
},
TransportType: transportType,
Expand Down Expand Up @@ -571,6 +571,15 @@ func parseEnvVars(envVars []string) map[string]string {
return result
}

// toEnvVarCfgMap converts a map[string]string to a map[string]v1alpha1.EnvVarCfg
func toEnvVarCfgMap(envMapString map[string]string) map[string]v1alpha1.EnvVarCfg {
result := make(map[string]v1alpha1.EnvVarCfg)
for k, v := range envMapString {
result[k] = v1alpha1.EnvVarCfg{Value: v}
}
return result
}

func applyToCluster(projectDir, yamlContent string, mcpServer *v1alpha1.MCPServer) error {
fmt.Printf("🚀 Applying MCPServer to cluster...\n")

Expand Down
Loading