Skip to content

Commit a44819c

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 1918fc2 commit a44819c

15 files changed

Lines changed: 391 additions & 1 deletion

api/assistant/v1beta1/openstackassistant_types.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,18 @@ 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+
type MCPServerRef struct {
57+
// Name is the extension name in Goose config
58+
// +kubebuilder:validation:Required
59+
Name string `json:"name"`
60+
61+
// URL is the MCP server's Streamable HTTP endpoint
62+
// (e.g. http://openstackclient-mcp.openstack.svc:8080/openstack/)
63+
// +kubebuilder:validation:Required
64+
URL string `json:"url"`
65+
}
66+
5567
// GooseConfig defines Goose-specific provider configuration
5668
type GooseConfig struct {
5769
// Model is the model identifier for the Goose AI agent
@@ -70,6 +82,10 @@ type GooseConfig struct {
7082
// will be written to ~/.goosehints in the pod.
7183
// +kubebuilder:validation:Optional
7284
Hints *string `json:"hints,omitempty"`
85+
86+
// MCPServers lists MCP server endpoints to configure as Goose extensions.
87+
// +kubebuilder:validation:Optional
88+
MCPServers []MCPServerRef `json:"mcpServers,omitempty"`
7389
}
7490

7591
// 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: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,26 @@ 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: MCPServerRef references an MCP server endpoint
196+
to configure as a Goose extension
197+
properties:
198+
name:
199+
description: Name is the extension name in Goose config
200+
type: string
201+
url:
202+
description: |-
203+
URL is the MCP server's Streamable HTTP endpoint
204+
(e.g. http://openstackclient-mcp.openstack.svc:8080/openstack/)
205+
type: string
206+
required:
207+
- name
208+
- url
209+
type: object
210+
type: array
191211
model:
192212
description: |-
193213
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: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,26 @@ 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: MCPServerRef references an MCP server endpoint
195+
to configure as a Goose extension
196+
properties:
197+
name:
198+
description: Name is the extension name in Goose config
199+
type: string
200+
url:
201+
description: |-
202+
URL is the MCP server's Streamable HTTP endpoint
203+
(e.g. http://openstackclient-mcp.openstack.svc:8080/openstack/)
204+
type: string
205+
required:
206+
- name
207+
- url
208+
type: object
209+
type: array
190210
model:
191211
description: |-
192212
Model is the model identifier for the Goose AI agent
@@ -748,6 +768,23 @@ spec:
748768
x-kubernetes-list-map-keys:
749769
- name
750770
x-kubernetes-list-type: map
771+
mcp:
772+
description: |-
773+
MCP is the optional MCP server sidecar configuration.
774+
When enabled, the rhos-mcps server runs alongside the openstackclient
775+
container and is exposed via a k8s Service.
776+
properties:
777+
containerImage:
778+
description: ContainerImage for the rhos-mcps MCP server container.
779+
type: string
780+
enabled:
781+
default: false
782+
description: Enabled controls whether the MCP server sidecar is
783+
added to the pod.
784+
type: boolean
785+
required:
786+
- containerImage
787+
type: object
751788
nodeSelector:
752789
additionalProperties:
753790
type: string
@@ -13816,6 +13853,16 @@ spec:
1381613853
x-kubernetes-list-map-keys:
1381713854
- name
1381813855
x-kubernetes-list-type: map
13856+
mcp:
13857+
properties:
13858+
containerImage:
13859+
type: string
13860+
enabled:
13861+
default: false
13862+
type: boolean
13863+
required:
13864+
- containerImage
13865+
type: object
1381913866
nodeSelector:
1382013867
additionalProperties:
1382113868
type: string

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

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,26 @@ 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: MCPServerRef references an MCP server endpoint
196+
to configure as a Goose extension
197+
properties:
198+
name:
199+
description: Name is the extension name in Goose config
200+
type: string
201+
url:
202+
description: |-
203+
URL is the MCP server's Streamable HTTP endpoint
204+
(e.g. http://openstackclient-mcp.openstack.svc:8080/openstack/)
205+
type: string
206+
required:
207+
- name
208+
- url
209+
type: object
210+
type: array
191211
model:
192212
description: |-
193213
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)