Skip to content

Commit 431aeed

Browse files
committed
Add MCP server sidecar support to OpenStackClient
Adds the ability to run the rhos-mcps MCP server as a sidecar container inside the openstackclient pod, exposed via a k8s Service. This allows the OpenStackAssistant (Goose) to execute read-only OpenStack CLI commands through the MCP protocol. OpenStackClient changes: - New MCPConfig struct (enabled, containerImage) on the CR spec - When enabled, adds an mcp-server sidecar container sharing the same clouds.yaml/secure.yaml credential mounts - Controller creates a ConfigMap with rhos-mcps config (openstack enabled, openshift disabled, allow_write: false) - Controller creates a Service on port 8080 for the MCP endpoint OpenStackAssistant changes: - New MCPServerRef (name, url) and mcpServers field on GooseConfig - Each MCP server is passed as MCP_SERVER_<name> env var to the pod - Entrypoint script generates Goose streamable_http extension entries from these env vars Users can create a second OpenStackClient instance with reader-only credentials for credential-level read-only enforcement in addition to the rhos-mcps allow_write:false guardrail.
1 parent 0c5f422 commit 431aeed

16 files changed

Lines changed: 705 additions & 23 deletions

api/assistant/v1beta1/openstackassistant_types.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,26 @@ type LightspeedStackSpec struct {
5252
CaBundleSecretName string `json:"caBundleSecretName,omitempty"`
5353
}
5454

55+
// MCPServerRef references an MCP server endpoint to configure as a Goose extension.
56+
// Either URL or OpenStackClientRef must be specified, but not both.
57+
type MCPServerRef struct {
58+
// Name is the extension name in Goose config
59+
// +kubebuilder:validation:Required
60+
Name string `json:"name"`
61+
62+
// URL is the MCP server's Streamable HTTP endpoint.
63+
// Mutually exclusive with OpenStackClientRef.
64+
// +kubebuilder:validation:Optional
65+
URL string `json:"url,omitempty"`
66+
67+
// OpenStackClientRef is the name of an OpenStackClient CR in the same
68+
// namespace that has MCP enabled. The controller auto-computes the
69+
// correct service URL and TLS CA configuration.
70+
// Mutually exclusive with URL.
71+
// +kubebuilder:validation:Optional
72+
OpenStackClientRef string `json:"openstackClientRef,omitempty"`
73+
}
74+
5575
// GooseConfig defines Goose-specific provider configuration
5676
type GooseConfig struct {
5777
// Model is the model identifier for the Goose AI agent
@@ -70,6 +90,10 @@ type GooseConfig struct {
7090
// will be written to ~/.goosehints in the pod.
7191
// +kubebuilder:validation:Optional
7292
Hints *string `json:"hints,omitempty"`
93+
94+
// MCPServers lists MCP server endpoints to configure as Goose extensions.
95+
// +kubebuilder:validation:Optional
96+
MCPServers []MCPServerRef `json:"mcpServers,omitempty"`
7397
}
7498

7599
// OpenStackAssistantSpec defines the desired state of OpenStackAssistant

api/assistant/v1beta1/zz_generated.deepcopy.go

Lines changed: 20 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/bases/assistant.openstack.org_openstackassistants.yaml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,33 @@ spec:
188188
The ConfigMap must have a key "hints" with the content that
189189
will be written to ~/.goosehints in the pod.
190190
type: string
191+
mcpServers:
192+
description: MCPServers lists MCP server endpoints to configure
193+
as Goose extensions.
194+
items:
195+
description: |-
196+
MCPServerRef references an MCP server endpoint to configure as a Goose extension.
197+
Either URL or OpenStackClientRef must be specified, but not both.
198+
properties:
199+
name:
200+
description: Name is the extension name in Goose config
201+
type: string
202+
openstackClientRef:
203+
description: |-
204+
OpenStackClientRef is the name of an OpenStackClient CR in the same
205+
namespace that has MCP enabled. The controller auto-computes the
206+
correct service URL and TLS CA configuration.
207+
Mutually exclusive with URL.
208+
type: string
209+
url:
210+
description: |-
211+
URL is the MCP server's Streamable HTTP endpoint.
212+
Mutually exclusive with OpenStackClientRef.
213+
type: string
214+
required:
215+
- name
216+
type: object
217+
type: array
191218
model:
192219
description: |-
193220
Model is the model identifier for the Goose AI agent

api/bases/client.openstack.org_openstackclients.yaml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,23 @@ spec:
180180
x-kubernetes-list-map-keys:
181181
- name
182182
x-kubernetes-list-type: map
183+
mcp:
184+
description: |-
185+
MCP is the optional MCP server sidecar configuration.
186+
When enabled, the rhos-mcps server runs alongside the openstackclient
187+
container and is exposed via a k8s Service.
188+
properties:
189+
containerImage:
190+
description: ContainerImage for the rhos-mcps MCP server container.
191+
type: string
192+
enabled:
193+
default: false
194+
description: Enabled controls whether the MCP server sidecar is
195+
added to the pod.
196+
type: boolean
197+
required:
198+
- containerImage
199+
type: object
183200
nodeSelector:
184201
additionalProperties:
185202
type: string

api/bases/core.openstack.org_openstackcontrolplanes.yaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12982,6 +12982,16 @@ spec:
1298212982
x-kubernetes-list-map-keys:
1298312983
- name
1298412984
x-kubernetes-list-type: map
12985+
mcp:
12986+
properties:
12987+
containerImage:
12988+
type: string
12989+
enabled:
12990+
default: false
12991+
type: boolean
12992+
required:
12993+
- containerImage
12994+
type: object
1298512995
nodeSelector:
1298612996
additionalProperties:
1298712997
type: string

api/client/v1beta1/openstackclient_types.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,18 @@ type OpenStackClientSpec struct {
3737
ContainerImage string `json:"containerImage"`
3838
}
3939

40+
// MCPConfig defines optional MCP server sidecar configuration
41+
type MCPConfig struct {
42+
// Enabled controls whether the MCP server sidecar is added to the pod.
43+
// +kubebuilder:validation:Optional
44+
// +kubebuilder:default=false
45+
Enabled bool `json:"enabled"`
46+
47+
// ContainerImage for the rhos-mcps MCP server container.
48+
// +kubebuilder:validation:Required
49+
ContainerImage string `json:"containerImage"`
50+
}
51+
4052
// OpenStackClientSpecCore defines the desired state of OpenStackClient
4153
type OpenStackClientSpecCore struct {
4254
// +kubebuilder:validation:Required
@@ -67,6 +79,12 @@ type OpenStackClientSpecCore struct {
6779
// +optional
6880
// List of environment variables to set in the container.
6981
Env []corev1.EnvVar `json:"env,omitempty" patchMergeKey:"name" patchStrategy:"merge"`
82+
83+
// MCP is the optional MCP server sidecar configuration.
84+
// When enabled, the rhos-mcps server runs alongside the openstackclient
85+
// container and is exposed via a k8s Service.
86+
// +kubebuilder:validation:Optional
87+
MCP *MCPConfig `json:"mcp,omitempty"`
7088
}
7189

7290
// OpenStackClientStatus defines the observed state of OpenStackClient

api/client/v1beta1/zz_generated.deepcopy.go

Lines changed: 20 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

bindata/crds/crds.yaml

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,33 @@ spec:
187187
The ConfigMap must have a key "hints" with the content that
188188
will be written to ~/.goosehints in the pod.
189189
type: string
190+
mcpServers:
191+
description: MCPServers lists MCP server endpoints to configure
192+
as Goose extensions.
193+
items:
194+
description: |-
195+
MCPServerRef references an MCP server endpoint to configure as a Goose extension.
196+
Either URL or OpenStackClientRef must be specified, but not both.
197+
properties:
198+
name:
199+
description: Name is the extension name in Goose config
200+
type: string
201+
openstackClientRef:
202+
description: |-
203+
OpenStackClientRef is the name of an OpenStackClient CR in the same
204+
namespace that has MCP enabled. The controller auto-computes the
205+
correct service URL and TLS CA configuration.
206+
Mutually exclusive with URL.
207+
type: string
208+
url:
209+
description: |-
210+
URL is the MCP server's Streamable HTTP endpoint.
211+
Mutually exclusive with OpenStackClientRef.
212+
type: string
213+
required:
214+
- name
215+
type: object
216+
type: array
190217
model:
191218
description: |-
192219
Model is the model identifier for the Goose AI agent
@@ -748,6 +775,23 @@ spec:
748775
x-kubernetes-list-map-keys:
749776
- name
750777
x-kubernetes-list-type: map
778+
mcp:
779+
description: |-
780+
MCP is the optional MCP server sidecar configuration.
781+
When enabled, the rhos-mcps server runs alongside the openstackclient
782+
container and is exposed via a k8s Service.
783+
properties:
784+
containerImage:
785+
description: ContainerImage for the rhos-mcps MCP server container.
786+
type: string
787+
enabled:
788+
default: false
789+
description: Enabled controls whether the MCP server sidecar is
790+
added to the pod.
791+
type: boolean
792+
required:
793+
- containerImage
794+
type: object
751795
nodeSelector:
752796
additionalProperties:
753797
type: string
@@ -13816,6 +13860,16 @@ spec:
1381613860
x-kubernetes-list-map-keys:
1381713861
- name
1381813862
x-kubernetes-list-type: map
13863+
mcp:
13864+
properties:
13865+
containerImage:
13866+
type: string
13867+
enabled:
13868+
default: false
13869+
type: boolean
13870+
required:
13871+
- containerImage
13872+
type: object
1381913873
nodeSelector:
1382013874
additionalProperties:
1382113875
type: string

config/crd/bases/assistant.openstack.org_openstackassistants.yaml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,33 @@ spec:
188188
The ConfigMap must have a key "hints" with the content that
189189
will be written to ~/.goosehints in the pod.
190190
type: string
191+
mcpServers:
192+
description: MCPServers lists MCP server endpoints to configure
193+
as Goose extensions.
194+
items:
195+
description: |-
196+
MCPServerRef references an MCP server endpoint to configure as a Goose extension.
197+
Either URL or OpenStackClientRef must be specified, but not both.
198+
properties:
199+
name:
200+
description: Name is the extension name in Goose config
201+
type: string
202+
openstackClientRef:
203+
description: |-
204+
OpenStackClientRef is the name of an OpenStackClient CR in the same
205+
namespace that has MCP enabled. The controller auto-computes the
206+
correct service URL and TLS CA configuration.
207+
Mutually exclusive with URL.
208+
type: string
209+
url:
210+
description: |-
211+
URL is the MCP server's Streamable HTTP endpoint.
212+
Mutually exclusive with OpenStackClientRef.
213+
type: string
214+
required:
215+
- name
216+
type: object
217+
type: array
191218
model:
192219
description: |-
193220
Model is the model identifier for the Goose AI agent

config/crd/bases/client.openstack.org_openstackclients.yaml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,23 @@ spec:
180180
x-kubernetes-list-map-keys:
181181
- name
182182
x-kubernetes-list-type: map
183+
mcp:
184+
description: |-
185+
MCP is the optional MCP server sidecar configuration.
186+
When enabled, the rhos-mcps server runs alongside the openstackclient
187+
container and is exposed via a k8s Service.
188+
properties:
189+
containerImage:
190+
description: ContainerImage for the rhos-mcps MCP server container.
191+
type: string
192+
enabled:
193+
default: false
194+
description: Enabled controls whether the MCP server sidecar is
195+
added to the pod.
196+
type: boolean
197+
required:
198+
- containerImage
199+
type: object
183200
nodeSelector:
184201
additionalProperties:
185202
type: string

0 commit comments

Comments
 (0)