apiVersion: v1 kind: Namespace metadata: labels: app.kubernetes.io/managed-by: kustomize app.kubernetes.io/name: mcp-lifecycle-operator control-plane: controller-manager name: mcp-lifecycle-operator-system --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.20.0 name: mcpservers.mcp.x-k8s.io spec: group: mcp.x-k8s.io names: kind: MCPServer listKind: MCPServerList plural: mcpservers singular: mcpserver scope: Namespaced versions: - additionalPrinterColumns: - jsonPath: .status.phase name: Phase type: string - jsonPath: .spec.source.containerImage.ref name: Image type: string - jsonPath: .spec.config.port name: Port type: integer - jsonPath: .status.address.url name: Address type: string - jsonPath: .metadata.creationTimestamp name: Age type: date name: v1alpha1 schema: openAPIV3Schema: description: MCPServer is the Schema for the mcpservers API properties: apiVersion: description: |- APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources type: string kind: description: |- Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds type: string metadata: type: object spec: description: spec defines the desired state of MCPServer properties: config: description: |- Config is a required field that defines how the MCP server should be configured when it runs. This includes runtime settings such as the server port, command-line arguments, environment variables, and storage mounts. properties: arguments: description: |- Arguments are command line arguments for the MCP server container. Use this to pass configuration flags to the server. Example: ["--config", "/etc/mcp-config/config.toml", "--verbose"] When not specified, the container image's default arguments (CMD/ENTRYPOINT) are used. An empty array [] is allowed and will override the container image's default arguments with no arguments. Empty strings within the array are not allowed. items: type: string type: array x-kubernetes-validations: - message: arguments must not contain empty strings rule: self.all(arg, arg.size() > 0) env: description: |- Env is a list of environment variables to set in the MCP server container. Supports the full Kubernetes EnvVar API including valueFrom for secrets and configmaps. items: description: EnvVar represents an environment variable present in a Container. properties: name: description: |- Name of the environment variable. May consist of any printable ASCII characters except '='. type: string value: description: |- Variable references $(VAR_NAME) are expanded using the previously defined environment variables in the container and any service environment variables. If a variable cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless of whether the variable exists or not. Defaults to "". type: string valueFrom: description: Source for the environment variable's value. Cannot be used if value is not empty. 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['']`, `metadata.annotations['']`, 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 fileKeyRef: description: |- FileKeyRef selects a key of the env file. Requires the EnvFiles feature gate to be enabled. properties: key: description: |- The key within the env file. An invalid key will prevent the pod from starting. The keys defined within a source may consist of any printable ASCII characters except '='. During Alpha stage of the EnvFiles feature gate, the key size is limited to 128 characters. type: string optional: default: false description: |- Specify whether the file or its key must be defined. If the file or key does not exist, then the env var is not published. If optional is set to true and the specified key does not exist, the environment variable will not be set in the Pod's containers. If optional is set to false and the specified key does not exist, an error will be returned during Pod creation. type: boolean path: description: |- The path within the volume from which to select the file. Must be relative and may not contain the '..' path or start with '..'. type: string volumeName: description: The name of the volume mount containing the env file. type: string required: - key - path - volumeName 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 required: - name type: object type: array envFrom: description: |- EnvFrom is a list of sources to populate environment variables in the MCP server container. Each entry injects all key-value pairs from a Secret or ConfigMap as environment variables. The keys become the variable names. Useful when a Secret's keys already match the expected env var names (e.g., GITHUB_TOKEN). items: description: EnvFromSource represents the source of a set of ConfigMaps or Secrets properties: configMapRef: description: The ConfigMap to select from properties: 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 must be defined type: boolean type: object x-kubernetes-map-type: atomic prefix: description: |- Optional text to prepend to the name of each environment variable. May consist of any printable ASCII characters except '='. type: string secretRef: description: The Secret to select from properties: 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 must be defined type: boolean type: object x-kubernetes-map-type: atomic type: object type: array path: default: /mcp description: |- Path is the HTTP path where the MCP server listens for SSE/Streamable HTTP connections. This path is appended to the service address in the status URL. Must be a valid URI path component starting with '/'. Maximum 253 characters. Cannot contain spaces, control characters, or query/fragment separators (? #). Examples: /mcp, /api/v1/mcp, /services/mcp-server Defaults to /mcp if not specified. maxLength: 253 minLength: 1 type: string x-kubernetes-validations: - message: path must start with '/' rule: self.startsWith('/') - message: path must not contain spaces rule: '!self.contains('' '')' - message: path must not contain query string separator '?' rule: '!self.contains(''?'')' - message: path must not contain fragment separator '#' rule: '!self.contains(''#'')' - message: path must not contain control characters (newlines, tabs) rule: '!self.contains(''\n'') && !self.contains(''\r'') && !self.contains(''\t'')' port: description: |- Port is a required field that specifies the port number on which the MCP server listens for connections. Must be between 1 and 65535. This should match the port that the MCP server container exposes and will be used for configuring the Kubernetes Service. format: int32 maximum: 65535 minimum: 1 type: integer storage: description: |- Storage defines storage mounts for ConfigMaps, Secrets, and EmptyDirs. Each item uses native Kubernetes volume source types for consistency and feature parity. If specified, must contain at least 1 item. Maximum 64 items. Each storage mount must have a unique path. items: description: |- StorageMount defines a storage mount combining volume source and mount configuration. The Path and Permissions fields apply to all storage types, while Source contains the type-specific configuration (ConfigMap, Secret, or EmptyDir). properties: path: description: |- Path is a required field that specifies where the volume should be mounted in the container. Must be an absolute path (starting with /). The ConfigMap or Secret data will be accessible to the MCP server process at this location. Must be between 1 and 4096 characters, start with '/', and must not contain ':'. maxLength: 4096 minLength: 1 type: string x-kubernetes-validations: - message: path must be an absolute path (must start with '/') rule: self.startsWith('/') - message: path must not contain ':' character rule: '!self.contains('':'')' permissions: default: ReadOnly description: |- Permissions specifies the access permissions for the mount. Allowed values are ReadOnly, ReadWrite, and RecursiveReadOnly. When set to ReadOnly, the mount is read-only. When set to ReadWrite, the mount is read-write. When set to RecursiveReadOnly, the mount and all submounts are recursively read-only. Defaults to ReadOnly for ConfigMap and Secret mounts. For EmptyDir mounts, ReadWrite is more common for writable scratch space. enum: - ReadOnly - ReadWrite - RecursiveReadOnly type: string source: description: Source defines where the storage data comes from (ConfigMap, Secret, or EmptyDir). properties: configMap: description: |- ConfigMap specifies a ConfigMap volume source (when Type is ConfigMap). Uses native Kubernetes ConfigMapVolumeSource type for full feature parity. properties: defaultMode: description: |- defaultMode is optional: mode bits used to set permissions on created files by default. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. Defaults to 0644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set. format: int32 type: integer items: description: |- items if unspecified, each key-value pair in the Data field of the referenced ConfigMap will be projected into the volume as a file whose name is the key and content is the value. If specified, the listed keys will be projected into the specified paths, and unlisted keys will not be present. If a key is specified which is not present in the ConfigMap, the volume setup will error unless it is marked optional. Paths must be relative and may not contain the '..' path or start with '..'. items: description: Maps a string key to a path within a volume. properties: key: description: key is the key to project. type: string mode: description: |- mode is Optional: mode bits used to set permissions on this file. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set. format: int32 type: integer path: description: |- path is the relative path of the file to map the key to. May not be an absolute path. May not contain the path element '..'. May not start with the string '..'. type: string required: - key - path type: object type: array x-kubernetes-list-type: atomic 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: optional specify whether the ConfigMap or its keys must be defined type: boolean type: object x-kubernetes-map-type: atomic emptyDir: description: |- EmptyDir specifies an EmptyDir volume source (when Type is EmptyDir). Uses native Kubernetes EmptyDirVolumeSource type for full feature parity. properties: medium: description: |- medium represents what type of storage medium should back this directory. The default is "" which means to use the node's default medium. Must be an empty string (default) or Memory. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir type: string sizeLimit: anyOf: - type: integer - type: string description: |- sizeLimit is the total amount of local storage required for this EmptyDir volume. The size limit is also applicable for memory medium. The maximum usage on memory medium EmptyDir would be the minimum value between the SizeLimit specified here and the sum of memory limits of all containers in a pod. The default is nil which means that the limit is undefined. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true type: object secret: description: |- Secret specifies a Secret volume source (when Type is Secret). Uses native Kubernetes SecretVolumeSource type for full feature parity. properties: defaultMode: description: |- defaultMode is Optional: mode bits used to set permissions on created files by default. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. Defaults to 0644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set. format: int32 type: integer items: description: |- items If unspecified, each key-value pair in the Data field of the referenced Secret will be projected into the volume as a file whose name is the key and content is the value. If specified, the listed keys will be projected into the specified paths, and unlisted keys will not be present. If a key is specified which is not present in the Secret, the volume setup will error unless it is marked optional. Paths must be relative and may not contain the '..' path or start with '..'. items: description: Maps a string key to a path within a volume. properties: key: description: key is the key to project. type: string mode: description: |- mode is Optional: mode bits used to set permissions on this file. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set. format: int32 type: integer path: description: |- path is the relative path of the file to map the key to. May not be an absolute path. May not contain the path element '..'. May not start with the string '..'. type: string required: - key - path type: object type: array x-kubernetes-list-type: atomic optional: description: optional field specify whether the Secret or its keys must be defined type: boolean secretName: description: |- secretName is the name of the secret in the pod's namespace to use. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret type: string type: object type: description: |- Type is a required field that specifies the type of volume source. Allowed values are: ConfigMap, Secret, EmptyDir. This determines which volume source field (configMap, secret, or emptyDir) should be configured. enum: - ConfigMap - Secret - EmptyDir type: string required: - type type: object x-kubernetes-validations: - message: configMap must be set when type is ConfigMap and must not be set otherwise rule: 'self.type == ''ConfigMap'' ? has(self.configMap) : !has(self.configMap)' - message: secret must be set when type is Secret and must not be set otherwise rule: 'self.type == ''Secret'' ? has(self.secret) : !has(self.secret)' - message: emptyDir must be set when type is EmptyDir and must not be set otherwise rule: 'self.type == ''EmptyDir'' ? has(self.emptyDir) : !has(self.emptyDir)' required: - path - source type: object maxItems: 64 minItems: 1 type: array x-kubernetes-list-map-keys: - path x-kubernetes-list-type: map required: - port type: object runtime: description: |- Runtime defines runtime management configuration. If not specified, default runtime settings will be applied. minProperties: 1 properties: health: description: |- Health defines health check configuration for the MCP server. If not specified, no health probes will be configured. minProperties: 1 properties: livenessProbe: description: |- LivenessProbe defines the liveness probe for the MCP server container. Kubernetes uses liveness probes to know when to restart a container. If not specified, no liveness probe will be configured. This probe is passed directly to the container spec without transformation, providing full compatibility with the Kubernetes Probe API. properties: exec: description: Exec specifies a command to execute in the container. properties: command: description: |- Command is the command line to execute inside the container, the working directory for the command is root ('/') in the container's filesystem. The command is simply exec'd, it is not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use a shell, you need to explicitly call out to that shell. Exit status of 0 is treated as live/healthy and non-zero is unhealthy. items: type: string type: array x-kubernetes-list-type: atomic type: object failureThreshold: description: |- Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3. Minimum value is 1. format: int32 type: integer grpc: description: GRPC specifies a GRPC HealthCheckRequest. properties: port: description: Port number of the gRPC service. Number must be in the range 1 to 65535. format: int32 type: integer service: default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). If this is not specified, the default behavior is defined by gRPC. type: string required: - port type: object httpGet: description: HTTPGet specifies an HTTP GET request to perform. properties: host: description: |- Host name to connect to, defaults to the pod IP. You probably want to set "Host" in httpHeaders instead. type: string httpHeaders: description: Custom headers to set in the request. HTTP allows repeated headers. items: description: HTTPHeader describes a custom header to be used in HTTP probes properties: name: description: |- The header field name. This will be canonicalized upon output, so case-variant names will be understood as the same header. type: string value: description: The header field value type: string required: - name - value type: object type: array x-kubernetes-list-type: atomic path: description: Path to access on the HTTP server. type: string port: anyOf: - type: integer - type: string description: |- Name or number of the port to access on the container. Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME. x-kubernetes-int-or-string: true scheme: description: |- Scheme to use for connecting to the host. Defaults to HTTP. type: string required: - port type: object initialDelaySeconds: description: |- Number of seconds after the container has started before liveness probes are initiated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes format: int32 type: integer periodSeconds: description: |- How often (in seconds) to perform the probe. Default to 10 seconds. Minimum value is 1. format: int32 type: integer successThreshold: description: |- Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. format: int32 type: integer tcpSocket: description: TCPSocket specifies a connection to a TCP port. properties: host: description: 'Optional: Host name to connect to, defaults to the pod IP.' type: string port: anyOf: - type: integer - type: string description: |- Number or name of the port to access on the container. Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME. x-kubernetes-int-or-string: true required: - port type: object terminationGracePeriodSeconds: description: |- Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. format: int64 type: integer timeoutSeconds: description: |- Number of seconds after which the probe times out. Defaults to 1 second. Minimum value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes format: int32 type: integer type: object readinessProbe: description: |- ReadinessProbe defines the readiness probe for the MCP server container. Kubernetes uses readiness probes to know when a container is ready to start accepting traffic. If not specified, no readiness probe will be configured. This probe is passed directly to the container spec without transformation, providing full compatibility with the Kubernetes Probe API. properties: exec: description: Exec specifies a command to execute in the container. properties: command: description: |- Command is the command line to execute inside the container, the working directory for the command is root ('/') in the container's filesystem. The command is simply exec'd, it is not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use a shell, you need to explicitly call out to that shell. Exit status of 0 is treated as live/healthy and non-zero is unhealthy. items: type: string type: array x-kubernetes-list-type: atomic type: object failureThreshold: description: |- Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3. Minimum value is 1. format: int32 type: integer grpc: description: GRPC specifies a GRPC HealthCheckRequest. properties: port: description: Port number of the gRPC service. Number must be in the range 1 to 65535. format: int32 type: integer service: default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). If this is not specified, the default behavior is defined by gRPC. type: string required: - port type: object httpGet: description: HTTPGet specifies an HTTP GET request to perform. properties: host: description: |- Host name to connect to, defaults to the pod IP. You probably want to set "Host" in httpHeaders instead. type: string httpHeaders: description: Custom headers to set in the request. HTTP allows repeated headers. items: description: HTTPHeader describes a custom header to be used in HTTP probes properties: name: description: |- The header field name. This will be canonicalized upon output, so case-variant names will be understood as the same header. type: string value: description: The header field value type: string required: - name - value type: object type: array x-kubernetes-list-type: atomic path: description: Path to access on the HTTP server. type: string port: anyOf: - type: integer - type: string description: |- Name or number of the port to access on the container. Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME. x-kubernetes-int-or-string: true scheme: description: |- Scheme to use for connecting to the host. Defaults to HTTP. type: string required: - port type: object initialDelaySeconds: description: |- Number of seconds after the container has started before liveness probes are initiated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes format: int32 type: integer periodSeconds: description: |- How often (in seconds) to perform the probe. Default to 10 seconds. Minimum value is 1. format: int32 type: integer successThreshold: description: |- Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. format: int32 type: integer tcpSocket: description: TCPSocket specifies a connection to a TCP port. properties: host: description: 'Optional: Host name to connect to, defaults to the pod IP.' type: string port: anyOf: - type: integer - type: string description: |- Number or name of the port to access on the container. Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME. x-kubernetes-int-or-string: true required: - port type: object terminationGracePeriodSeconds: description: |- Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. format: int64 type: integer timeoutSeconds: description: |- Number of seconds after which the probe times out. Defaults to 1 second. Minimum value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes format: int32 type: integer type: object type: object replicas: description: |- Replicas is the number of MCP server pod replicas to run. Defaults to 1 if not specified. Set to 0 to scale down the deployment. This field is a pointer (*int32) to distinguish between: - nil (not specified) -> defaults to 1 replica - ptr.To(0) (explicit 0) -> scale-to-zero This follows the same pattern as Deployment.Spec.Replicas in k8s.io/api/apps/v1. format: int32 minimum: 0 type: integer resources: description: |- Resources defines the resource requirements for the MCP server container. This includes CPU and memory requests and limits. If not specified, the container will run without explicit resource constraints. Supports partial specification (e.g., only requests or only limits). Example: resources: requests: cpu: "100m" memory: "256Mi" limits: cpu: "500m" memory: "512Mi" properties: claims: description: |- Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. This field depends on the DynamicResourceAllocation feature gate. This field is immutable. It can only be set for containers. items: description: ResourceClaim references one entry in PodSpec.ResourceClaims. properties: name: description: |- Name must match the name of one entry in pod.spec.resourceClaims of the Pod where this field is used. It makes that resource available inside a container. type: string request: description: |- Request is the name chosen for a request in the referenced claim. If empty, everything from the claim is made available, otherwise only the result of this request. type: string required: - name type: object type: array x-kubernetes-list-map-keys: - name x-kubernetes-list-type: map limits: additionalProperties: anyOf: - type: integer - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true description: |- Limits describes the maximum amount of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object requests: additionalProperties: anyOf: - type: integer - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true description: |- Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. Requests cannot exceed Limits. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object type: object security: description: |- Security defines security-related configuration. If not specified, default security settings will be applied. properties: podSecurityContext: description: PodSecurityContext specifies the security context for the MCP server pod. properties: appArmorProfile: description: |- appArmorProfile is the AppArmor options to use by the containers in this pod. Note that this field cannot be set when spec.os.name is windows. properties: localhostProfile: description: |- localhostProfile indicates a profile loaded on the node that should be used. The profile must be preconfigured on the node to work. Must match the loaded name of the profile. Must be set if and only if type is "Localhost". type: string type: description: |- type indicates which kind of AppArmor profile will be applied. Valid options are: Localhost - a profile pre-loaded on the node. RuntimeDefault - the container runtime's default profile. Unconfined - no AppArmor enforcement. type: string required: - type type: object fsGroup: description: |- A special supplemental group that applies to all containers in a pod. Some volume types allow the Kubelet to change the ownership of that volume to be owned by the pod: 1. The owning GID will be the FSGroup 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) 3. The permission bits are OR'd with rw-rw---- If unset, the Kubelet will not modify the ownership and permissions of any volume. Note that this field cannot be set when spec.os.name is windows. format: int64 type: integer fsGroupChangePolicy: description: |- fsGroupChangePolicy defines behavior of changing ownership and permission of the volume before being exposed inside Pod. This field will only apply to volume types which support fsGroup based ownership(and permissions). It will have no effect on ephemeral volume types such as: secret, configmaps and emptydir. Valid values are "OnRootMismatch" and "Always". If not specified, "Always" is used. Note that this field cannot be set when spec.os.name is windows. type: string runAsGroup: description: |- The GID to run the entrypoint of the container process. Uses runtime default if unset. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence for that container. Note that this field cannot be set when spec.os.name is windows. format: int64 type: integer runAsNonRoot: description: |- Indicates that the container must run as a non-root user. If true, the Kubelet will validate the image at runtime to ensure that it does not run as UID 0 (root) and fail to start the container if it does. If unset or false, no such validation will be performed. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. type: boolean runAsUser: description: |- The UID to run the entrypoint of the container process. Defaults to user specified in image metadata if unspecified. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence for that container. Note that this field cannot be set when spec.os.name is windows. format: int64 type: integer seLinuxChangePolicy: description: |- seLinuxChangePolicy defines how the container's SELinux label is applied to all volumes used by the Pod. It has no effect on nodes that do not support SELinux or to volumes does not support SELinux. Valid values are "MountOption" and "Recursive". "Recursive" means relabeling of all files on all Pod volumes by the container runtime. This may be slow for large volumes, but allows mixing privileged and unprivileged Pods sharing the same volume on the same node. "MountOption" mounts all eligible Pod volumes with `-o context` mount option. This requires all Pods that share the same volume to use the same SELinux label. It is not possible to share the same volume among privileged and unprivileged Pods. Eligible volumes are in-tree FibreChannel and iSCSI volumes, and all CSI volumes whose CSI driver announces SELinux support by setting spec.seLinuxMount: true in their CSIDriver instance. Other volumes are always re-labelled recursively. "MountOption" value is allowed only when SELinuxMount feature gate is enabled. If not specified and SELinuxMount feature gate is enabled, "MountOption" is used. If not specified and SELinuxMount feature gate is disabled, "MountOption" is used for ReadWriteOncePod volumes and "Recursive" for all other volumes. This field affects only Pods that have SELinux label set, either in PodSecurityContext or in SecurityContext of all containers. All Pods that use the same volume should use the same seLinuxChangePolicy, otherwise some pods can get stuck in ContainerCreating state. Note that this field cannot be set when spec.os.name is windows. type: string seLinuxOptions: description: |- The SELinux context to be applied to all containers. If unspecified, the container runtime will allocate a random SELinux context for each container. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence for that container. Note that this field cannot be set when spec.os.name is windows. properties: level: description: Level is SELinux level label that applies to the container. type: string role: description: Role is a SELinux role label that applies to the container. type: string type: description: Type is a SELinux type label that applies to the container. type: string user: description: User is a SELinux user label that applies to the container. type: string type: object seccompProfile: description: |- The seccomp options to use by the containers in this pod. Note that this field cannot be set when spec.os.name is windows. properties: localhostProfile: description: |- localhostProfile indicates a profile defined in a file on the node should be used. The profile must be preconfigured on the node to work. Must be a descending path, relative to the kubelet's configured seccomp profile location. Must be set if type is "Localhost". Must NOT be set for any other type. type: string type: description: |- type indicates which kind of seccomp profile will be applied. Valid options are: Localhost - a profile defined in a file on the node should be used. RuntimeDefault - the container runtime default profile should be used. Unconfined - no profile should be applied. type: string required: - type type: object supplementalGroups: description: |- A list of groups applied to the first process run in each container, in addition to the container's primary GID and fsGroup (if specified). If the SupplementalGroupsPolicy feature is enabled, the supplementalGroupsPolicy field determines whether these are in addition to or instead of any group memberships defined in the container image. If unspecified, no additional groups are added, though group memberships defined in the container image may still be used, depending on the supplementalGroupsPolicy field. Note that this field cannot be set when spec.os.name is windows. items: format: int64 type: integer type: array x-kubernetes-list-type: atomic supplementalGroupsPolicy: description: |- Defines how supplemental groups of the first container processes are calculated. Valid values are "Merge" and "Strict". If not specified, "Merge" is used. (Alpha) Using the field requires the SupplementalGroupsPolicy feature gate to be enabled and the container runtime must implement support for this feature. Note that this field cannot be set when spec.os.name is windows. type: string sysctls: description: |- Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported sysctls (by the container runtime) might fail to launch. Note that this field cannot be set when spec.os.name is windows. items: description: Sysctl defines a kernel parameter to be set properties: name: description: Name of a property to set type: string value: description: Value of a property to set type: string required: - name - value type: object type: array x-kubernetes-list-type: atomic windowsOptions: description: |- The Windows specific settings applied to all containers. If unspecified, the options within a container's SecurityContext will be used. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. Note that this field cannot be set when spec.os.name is linux. properties: gmsaCredentialSpec: description: |- GMSACredentialSpec is where the GMSA admission webhook (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the GMSA credential spec named by the GMSACredentialSpecName field. type: string gmsaCredentialSpecName: description: GMSACredentialSpecName is the name of the GMSA credential spec to use. type: string hostProcess: description: |- HostProcess determines if a container should be run as a 'Host Process' container. All of a Pod's containers must have the same effective HostProcess value (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers). In addition, if HostProcess is true then HostNetwork must also be set to true. type: boolean runAsUserName: description: |- The UserName in Windows to run the entrypoint of the container process. Defaults to the user specified in image metadata if unspecified. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. type: string type: object type: object securityContext: description: SecurityContext specifies the security context for the MCP server container. properties: allowPrivilegeEscalation: description: |- AllowPrivilegeEscalation controls whether a process can gain more privileges than its parent process. This bool directly controls if the no_new_privs flag will be set on the container process. AllowPrivilegeEscalation is true always when the container is: 1) run as Privileged 2) has CAP_SYS_ADMIN Note that this field cannot be set when spec.os.name is windows. type: boolean appArmorProfile: description: |- appArmorProfile is the AppArmor options to use by this container. If set, this profile overrides the pod's appArmorProfile. Note that this field cannot be set when spec.os.name is windows. properties: localhostProfile: description: |- localhostProfile indicates a profile loaded on the node that should be used. The profile must be preconfigured on the node to work. Must match the loaded name of the profile. Must be set if and only if type is "Localhost". type: string type: description: |- type indicates which kind of AppArmor profile will be applied. Valid options are: Localhost - a profile pre-loaded on the node. RuntimeDefault - the container runtime's default profile. Unconfined - no AppArmor enforcement. type: string required: - type type: object capabilities: description: |- The capabilities to add/drop when running containers. Defaults to the default set of capabilities granted by the container runtime. Note that this field cannot be set when spec.os.name is windows. properties: add: description: Added capabilities items: description: Capability represent POSIX capabilities type type: string type: array x-kubernetes-list-type: atomic drop: description: Removed capabilities items: description: Capability represent POSIX capabilities type type: string type: array x-kubernetes-list-type: atomic type: object privileged: description: |- Run container in privileged mode. Processes in privileged containers are essentially equivalent to root on the host. Defaults to false. Note that this field cannot be set when spec.os.name is windows. type: boolean procMount: description: |- procMount denotes the type of proc mount to use for the containers. The default value is Default which uses the container runtime defaults for readonly paths and masked paths. This requires the ProcMountType feature flag to be enabled. Note that this field cannot be set when spec.os.name is windows. type: string readOnlyRootFilesystem: description: |- Whether this container has a read-only root filesystem. Default is false. Note that this field cannot be set when spec.os.name is windows. type: boolean runAsGroup: description: |- The GID to run the entrypoint of the container process. Uses runtime default if unset. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. Note that this field cannot be set when spec.os.name is windows. format: int64 type: integer runAsNonRoot: description: |- Indicates that the container must run as a non-root user. If true, the Kubelet will validate the image at runtime to ensure that it does not run as UID 0 (root) and fail to start the container if it does. If unset or false, no such validation will be performed. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. type: boolean runAsUser: description: |- The UID to run the entrypoint of the container process. Defaults to user specified in image metadata if unspecified. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. Note that this field cannot be set when spec.os.name is windows. format: int64 type: integer seLinuxOptions: description: |- The SELinux context to be applied to the container. If unspecified, the container runtime will allocate a random SELinux context for each container. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. Note that this field cannot be set when spec.os.name is windows. properties: level: description: Level is SELinux level label that applies to the container. type: string role: description: Role is a SELinux role label that applies to the container. type: string type: description: Type is a SELinux type label that applies to the container. type: string user: description: User is a SELinux user label that applies to the container. type: string type: object seccompProfile: description: |- The seccomp options to use by this container. If seccomp options are provided at both the pod & container level, the container options override the pod options. Note that this field cannot be set when spec.os.name is windows. properties: localhostProfile: description: |- localhostProfile indicates a profile defined in a file on the node should be used. The profile must be preconfigured on the node to work. Must be a descending path, relative to the kubelet's configured seccomp profile location. Must be set if type is "Localhost". Must NOT be set for any other type. type: string type: description: |- type indicates which kind of seccomp profile will be applied. Valid options are: Localhost - a profile defined in a file on the node should be used. RuntimeDefault - the container runtime default profile should be used. Unconfined - no profile should be applied. type: string required: - type type: object windowsOptions: description: |- The Windows specific settings applied to all containers. If unspecified, the options from the PodSecurityContext will be used. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. Note that this field cannot be set when spec.os.name is linux. properties: gmsaCredentialSpec: description: |- GMSACredentialSpec is where the GMSA admission webhook (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the GMSA credential spec named by the GMSACredentialSpecName field. type: string gmsaCredentialSpecName: description: GMSACredentialSpecName is the name of the GMSA credential spec to use. type: string hostProcess: description: |- HostProcess determines if a container should be run as a 'Host Process' container. All of a Pod's containers must have the same effective HostProcess value (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers). In addition, if HostProcess is true then HostNetwork must also be set to true. type: boolean runAsUserName: description: |- The UserName in Windows to run the entrypoint of the container process. Defaults to the user specified in image metadata if unspecified. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. type: string type: object type: object serviceAccountName: description: |- ServiceAccountName is the name of the ServiceAccount to use for the MCP server pods. The ServiceAccount should have appropriate RBAC permissions for the MCP server's operations. If not specified, the default ServiceAccount for the namespace will be used. Must be a string that follows the DNS1123 subdomain format. Must be at most 253 characters in length, and must consist only of lower case alphanumeric characters, '-' and '.', and must start and end with an alphanumeric character. Example: For kubernetes-mcp-server with read-only access, create a ServiceAccount and bind it to the 'view' ClusterRole. maxLength: 253 type: string x-kubernetes-validations: - message: 'serviceAccountName must be a valid DNS subdomain name: a lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters, ''-'' or ''.'', and must start and end with an alphanumeric character.' rule: self == '' || !format.dns1123Subdomain().validate(self).hasValue() type: object type: object source: description: |- Source is a required field that defines where the MCP server should be sourced from. Currently supports container images, with potential for additional source types in the future. This configuration determines how the MCP server will be deployed and run. properties: containerImage: description: ContainerImage specifies container image details when Type is ContainerImage. properties: ref: description: |- Ref is the container image containing the MCP server implementation. Must be a valid OCI image reference. Examples: - ghcr.io/modelcontextprotocol/servers/filesystem:latest - ghcr.io/modelcontextprotocol/servers/github:v1.0.0 - custom-registry.io/my-mcp-server:1.2.3 - custom-registry.io/my-mcp-server@sha256:1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef maxLength: 1000 minLength: 1 type: string x-kubernetes-validations: - message: must start with a valid domain. valid domains must be alphanumeric characters (lowercase and uppercase) separated by the "." character. rule: self.matches('^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])((\\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]))+)?(:[0-9]+)?\\b') - message: a valid name is required. valid names must contain lowercase alphanumeric characters separated only by the ".", "_", "__", "-" characters. rule: self.find('(\\/[a-z0-9]+((([._]|__|[-]*)[a-z0-9]+)+)?((\\/[a-z0-9]+((([._]|__|[-]*)[a-z0-9]+)+)?)+)?)') != "" - message: must end with a digest or a tag rule: self.find('(@.*:)') != "" || self.find(':.*$') != "" - message: tag is invalid. the tag must not be more than 127 characters rule: 'self.find(''(@.*:)'') == "" ? (self.find('':.*$'') != "" ? self.find('':.*$'').substring(1).size() <= 127 : true) : true' - message: tag is invalid. valid tags must begin with a word character (alphanumeric + "_") followed by word characters or ".", and "-" characters rule: 'self.find(''(@.*:)'') == "" ? (self.find('':.*$'') != "" ? self.find('':.*$'').matches('':[\\w][\\w.-]*$'') : true) : true' - message: digest algorithm is not valid. valid algorithms must start with an uppercase or lowercase alpha character followed by alphanumeric characters and may contain the "-", "_", "+", and "." characters. rule: 'self.find(''(@.*:)'') != "" ? self.find(''(@.*:)'').matches(''(@[A-Za-z][A-Za-z0-9]*([-_+.][A-Za-z][A-Za-z0-9]*)*[:])'') : true' - message: digest is not valid. the encoded string must be at least 32 characters rule: 'self.find(''(@.*:)'') != "" ? self.find('':.*$'').substring(1).size() >= 32 : true' - message: digest is not valid. the encoded string must only contain hex characters (A-F, a-f, 0-9) rule: 'self.find(''(@.*:)'') != "" ? self.find('':.*$'').matches('':[0-9A-Fa-f]*$'') : true' required: - ref type: object type: description: |- Type is a required field that configures how the MCP server should be sourced. Allowed values are: ContainerImage. When set to ContainerImage, the MCP server will be sourced directly from an OCI container image following the configuration specified in containerImage. enum: - ContainerImage type: string required: - type type: object x-kubernetes-validations: - message: containerImage must be set when type is ContainerImage and must not be set otherwise rule: 'self.type == ''ContainerImage'' ? has(self.containerImage) : !has(self.containerImage)' required: - config - source type: object status: description: status defines the observed state of MCPServer properties: address: description: Address contains the address of the MCP server service. properties: url: description: |- URL is the cluster-internal address of the MCP server service. Format: http://..svc.cluster.local:/ type: string type: object conditions: description: |- Conditions represent the current state of the MCPServer resource. Each condition has a unique type and reflects the status of a specific aspect of the resource. Standard condition types include "Ready", "Progressing", and "Degraded". The "Ready" condition indicates the resource is fully functional and available. The "Progressing" condition indicates the resource is being created or updated. The "Degraded" condition indicates the resource failed to reach or maintain its desired state. The status of each condition is one of True, False, or Unknown. items: description: Condition contains details for one aspect of the current state of this API Resource. properties: lastTransitionTime: description: |- lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. format: date-time type: string message: description: |- message is a human readable message indicating details about the transition. This may be an empty string. maxLength: 32768 type: string observedGeneration: description: |- observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance. format: int64 minimum: 0 type: integer reason: description: |- reason contains a programmatic identifier indicating the reason for the condition's last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty. maxLength: 1024 minLength: 1 pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ type: string status: description: status of the condition, one of True, False, Unknown. enum: - "True" - "False" - Unknown type: string type: description: type of condition in CamelCase or in foo.example.com/CamelCase. maxLength: 316 pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ type: string required: - lastTransitionTime - message - reason - status - type type: object type: array x-kubernetes-list-map-keys: - type x-kubernetes-list-type: map deploymentName: description: DeploymentName is the name of the Deployment created for this MCPServer. type: string phase: description: |- Phase represents the current lifecycle phase of the MCPServer. Possible values: Pending, Running, Failed type: string serviceName: description: ServiceName is the name of the Service created for this MCPServer. type: string type: object required: - spec type: object served: true storage: true subresources: status: {} --- apiVersion: v1 kind: ServiceAccount metadata: labels: app.kubernetes.io/managed-by: kustomize app.kubernetes.io/name: mcp-lifecycle-operator name: mcp-lifecycle-operator-controller-manager namespace: mcp-lifecycle-operator-system --- apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: labels: app.kubernetes.io/managed-by: kustomize app.kubernetes.io/name: mcp-lifecycle-operator name: mcp-lifecycle-operator-leader-election-role namespace: mcp-lifecycle-operator-system 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 --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: mcp-lifecycle-operator-manager-role rules: - apiGroups: - "" resources: - configmaps - secrets verbs: - get - list - watch - apiGroups: - "" resources: - services verbs: - create - delete - get - list - patch - update - watch - apiGroups: - apps resources: - deployments verbs: - create - delete - get - list - patch - update - watch - apiGroups: - mcp.x-k8s.io resources: - mcpservers verbs: - create - delete - get - list - patch - update - watch - apiGroups: - mcp.x-k8s.io resources: - mcpservers/finalizers verbs: - update - apiGroups: - mcp.x-k8s.io resources: - mcpservers/status verbs: - get - patch - update --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: labels: app.kubernetes.io/managed-by: kustomize app.kubernetes.io/name: mcp-lifecycle-operator rbac.authorization.k8s.io/aggregate-to-admin: "true" name: mcp-lifecycle-operator-mcpserver-admin-role rules: - apiGroups: - mcp.x-k8s.io resources: - mcpservers verbs: - '*' - apiGroups: - mcp.x-k8s.io resources: - mcpservers/status verbs: - get --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: labels: app.kubernetes.io/managed-by: kustomize app.kubernetes.io/name: mcp-lifecycle-operator rbac.authorization.k8s.io/aggregate-to-edit: "true" name: mcp-lifecycle-operator-mcpserver-editor-role rules: - apiGroups: - mcp.x-k8s.io resources: - mcpservers verbs: - create - delete - get - list - patch - update - watch - apiGroups: - mcp.x-k8s.io resources: - mcpservers/status verbs: - get --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: labels: app.kubernetes.io/managed-by: kustomize app.kubernetes.io/name: mcp-lifecycle-operator rbac.authorization.k8s.io/aggregate-to-view: "true" name: mcp-lifecycle-operator-mcpserver-viewer-role rules: - apiGroups: - mcp.x-k8s.io resources: - mcpservers verbs: - get - list - watch - apiGroups: - mcp.x-k8s.io resources: - mcpservers/status verbs: - get --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: mcp-lifecycle-operator-metrics-auth-role rules: - apiGroups: - authentication.k8s.io resources: - tokenreviews verbs: - create - apiGroups: - authorization.k8s.io resources: - subjectaccessreviews verbs: - create --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: mcp-lifecycle-operator-metrics-reader rules: - nonResourceURLs: - /metrics verbs: - get --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: labels: app.kubernetes.io/managed-by: kustomize app.kubernetes.io/name: mcp-lifecycle-operator name: mcp-lifecycle-operator-leader-election-rolebinding namespace: mcp-lifecycle-operator-system roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: mcp-lifecycle-operator-leader-election-role subjects: - kind: ServiceAccount name: mcp-lifecycle-operator-controller-manager namespace: mcp-lifecycle-operator-system --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: labels: app.kubernetes.io/managed-by: kustomize app.kubernetes.io/name: mcp-lifecycle-operator name: mcp-lifecycle-operator-manager-rolebinding roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: mcp-lifecycle-operator-manager-role subjects: - kind: ServiceAccount name: mcp-lifecycle-operator-controller-manager namespace: mcp-lifecycle-operator-system --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: mcp-lifecycle-operator-metrics-auth-rolebinding roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: mcp-lifecycle-operator-metrics-auth-role subjects: - kind: ServiceAccount name: mcp-lifecycle-operator-controller-manager namespace: mcp-lifecycle-operator-system --- apiVersion: v1 kind: Service metadata: labels: app.kubernetes.io/managed-by: kustomize app.kubernetes.io/name: mcp-lifecycle-operator control-plane: controller-manager name: mcp-lifecycle-operator-controller-manager-metrics-service namespace: mcp-lifecycle-operator-system spec: ports: - name: https port: 8443 protocol: TCP targetPort: 8443 selector: app.kubernetes.io/name: mcp-lifecycle-operator control-plane: controller-manager --- apiVersion: apps/v1 kind: Deployment metadata: labels: app.kubernetes.io/managed-by: kustomize app.kubernetes.io/name: mcp-lifecycle-operator control-plane: controller-manager name: mcp-lifecycle-operator-controller-manager namespace: mcp-lifecycle-operator-system spec: replicas: 1 selector: matchLabels: app.kubernetes.io/name: mcp-lifecycle-operator control-plane: controller-manager template: metadata: annotations: kubectl.kubernetes.io/default-container: manager labels: app.kubernetes.io/name: mcp-lifecycle-operator control-plane: controller-manager spec: containers: - args: - --metrics-bind-address=:8443 - --leader-elect - --health-probe-bind-address=:8081 command: - /manager image: quay.io/matzew/mcp-lifecycle-operator:latest livenessProbe: httpGet: path: /healthz port: 8081 initialDelaySeconds: 15 periodSeconds: 20 name: manager ports: [] readinessProbe: httpGet: path: /readyz port: 8081 initialDelaySeconds: 5 periodSeconds: 10 resources: limits: cpu: 500m memory: 128Mi requests: cpu: 10m memory: 64Mi securityContext: allowPrivilegeEscalation: false capabilities: drop: - ALL readOnlyRootFilesystem: true runAsNonRoot: true seccompProfile: type: RuntimeDefault volumeMounts: [] serviceAccountName: mcp-lifecycle-operator-controller-manager terminationGracePeriodSeconds: 10 volumes: []