Skip to content

MCP server on ARO#932

Draft
dharmesh-b wants to merge 4 commits into
mainfrom
mcp-server-on-aro
Draft

MCP server on ARO#932
dharmesh-b wants to merge 4 commits into
mainfrom
mcp-server-on-aro

Conversation

@dharmesh-b
Copy link
Copy Markdown

No description provided.

dharmesh-b and others added 2 commits May 26, 2026 17:34
Document Helm-based install, read-only RBAC, route exposure, and testing
on ARO, with references to the Red Hat technology preview announcement.

Signed-off-by: dharmesh-b <dharmesh.b@gmail.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Updated author's name for clarity.
@netlify
Copy link
Copy Markdown

netlify Bot commented May 27, 2026

Deploy Preview for rh-cloud-experts ready!

Name Link
🔨 Latest commit c6fd23d
🔍 Latest deploy log https://app.netlify.com/projects/rh-cloud-experts/deploys/6a1674e79034ea0008fda2fd
😎 Deploy Preview https://deploy-preview-932--rh-cloud-experts.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

Copy link
Copy Markdown
Contributor

@paulczar paulczar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for contributing this guide — the content is well-structured and the RBAC options are a nice touch. However, there are a few issues to address before merge, including one security blocker.

Security blocker: unauthenticated public endpoint

The guide exposes the MCP server via oc expose svc, creating a publicly accessible HTTP route on *.aroapp.io. The test in Step 16 sends a raw JSON-RPC request with no Authorization header. The MCP protocol has no built-in transport-layer auth, so anyone who can reach that URL can query your cluster — pod logs, configmaps, service account names, cluster topology, monitoring rules, etc.

The server authenticates to the cluster using its service account token, but nothing authenticates the clients hitting the MCP endpoint. At minimum, the guide needs to address this — options include:

  • OAuth proxy sidecar (standard OpenShift pattern)
  • Restrict to cluster-internal access only (no external route)
  • NetworkPolicy restricting which pods can reach the service
  • A note that this config is for local/isolated testing only and must not be used in any shared or production environment

Please pick one of these approaches and document it before merging.

Other issues (see inline comments)

  • Missing Technology Preview warning banner
  • oc expose svc creates HTTP (not HTTPS) — should use oc create route edge
  • securityContext in values-openshift.yaml is missing fields required by ARO's restricted-v2 SCC
  • Steps 4 and 10 are trivial no-op verifications that can be removed

Comment thread content/aro/mcp-server-on-aro/index.md Outdated
- Dharmeshkumar Bhamre
---

This guide walks through deploying the [OpenShift Kubernetes MCP Server](https://github.com/openshift/openshift-mcp-server) on an **Azure Red Hat OpenShift (ARO)** cluster. You install the server with Helm, bind a read-only ClusterRole to a dedicated service account, and expose the MCP endpoint on an OpenShift route for client testing.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Red Hat blog post linked in the References section confirms this is a Technology Preview feature. Please add a TP warning banner here:

Suggested change
This guide walks through deploying the [OpenShift Kubernetes MCP Server](https://github.com/openshift/openshift-mcp-server) on an **Azure Red Hat OpenShift (ARO)** cluster. You install the server with Helm, bind a read-only ClusterRole to a dedicated service account, and expose the MCP endpoint on an OpenShift route for client testing.
{{% alert state="warning" %}}The OpenShift MCP Server is a Technology Preview feature. Technology Preview features are not supported with Red Hat production service level agreements (SLAs) and might not be functionally complete. Red Hat does not recommend using them in production.{{% /alert %}}
This guide walks through deploying the [OpenShift Kubernetes MCP Server](https://github.com/openshift/openshift-mcp-server) on an **Azure Red Hat OpenShift (ARO)** cluster. You install the server with Helm, bind a read-only ClusterRole to a dedicated service account, and expose the MCP endpoint on an OpenShift route for client testing.

Comment thread content/aro/mcp-server-on-aro/index.md Outdated
Confirm the service account was created successfully.

```bash
oc get sa -n mcp-server
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This step runs oc get sa immediately after creating the service account — it will always succeed unless the prior step failed, so it adds no diagnostic value. Consider removing Step 4 to keep the guide tight.

Review the default Helm chart values before customization.

```bash
cat values.yaml
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Running cat values.yaml has no actionable purpose in the guide — the reader is about to override it with a custom file anyway. Consider removing Step 10.

Comment thread content/aro/mcp-server-on-aro/index.md Outdated
cpu: 500m
memory: 512Mi

securityContext:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ARO's default restricted-v2 SCC (OpenShift 4.11+) requires seccompProfile and capabilities.drop: [ALL] in addition to runAsNonRoot and allowPrivilegeEscalation: false. Without these, the pod will likely be rejected at admission. Please expand the security context:

Suggested change
securityContext:
securityContext:
runAsNonRoot: true
allowPrivilegeEscalation: false
seccompProfile:
type: RuntimeDefault
capabilities:
drop:
- ALL

Comment thread content/aro/mcp-server-on-aro/index.md Outdated
Create an OpenShift route to expose the MCP server externally.

```bash
oc expose svc kubernetes-mcp-server -n mcp-server
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oc expose svc creates a plaintext HTTP route. Combined with the lack of client authentication on the MCP endpoint (see main review comment), this means cluster data is served over unencrypted HTTP to anyone on the internet. Please use an edge-terminated TLS route instead:

Suggested change
oc expose svc kubernetes-mcp-server -n mcp-server
oc create route edge kubernetes-mcp-server \
--service=kubernetes-mcp-server \
-n mcp-server

Comment thread content/aro/mcp-server-on-aro/index.md Outdated

```bash
curl -i -X POST \
http://kubernetes-mcp-server-mcp-server.apps.<xxx>.<xxx>.aroapp.io/mcp \
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the route is changed to edge-terminated TLS (see Step 14 comment), update this to https://:

Suggested change
http://kubernetes-mcp-server-mcp-server.apps.<xxx>.<xxx>.aroapp.io/mcp \
https://kubernetes-mcp-server-mcp-server.apps.<xxx>.<xxx>.aroapp.io/mcp \

dharmesh-b and others added 2 commits May 27, 2026 10:02
Document OIDC on the MCP endpoint, group-based RBAC with token passthrough, corrected chart config, and HTTPS route testing.

Co-authored-by: Cursor <cursoragent@cursor.com>
@paulczar
Copy link
Copy Markdown
Contributor

Follow-up: additional issues in values-openshift.yaml

After reviewing the upstream chart's values.yaml and templates more closely, there are three more issues beyond what the initial review flagged.

1. mcp.args is not a valid chart key (silent failure)

The chart has no mcp.args field. Helm silently ignores unknown keys, so the --read-only, --disable-destructive, and --toolsets flags are never passed to the server. The MCP server runs with full write access and destructive operations enabled.

These should go in extraArgs instead:

extraArgs:
  - --read-only
  - --disable-destructive
  - --toolsets=config,core,helm

2. securityContext override removes chart defaults (makes things worse)

The chart template uses default .Values.defaultSecurityContext .Values.securityContext — meaning any non-empty securityContext value replaces the defaults entirely. By setting a partial override, the guide removes these protections that the chart already provides:

  • readOnlyRootFilesystem: true
  • capabilities.drop: [ALL]
  • seccompProfile.type: RuntimeDefault

The fix is to remove the securityContext block completely and let the chart defaults apply.

3. The chart ships its own values-openshift.yaml

The cloned repo already has charts/kubernetes-mcp-server/values-openshift.yaml which sets openshift: true and adds ACM RBAC. The install command should layer files rather than replace them:

helm install kubernetes-mcp-server . \
  -n mcp-server \
  -f values-openshift.yaml \
  -f values-aro.yaml

Recommended values-aro.yaml

With openshift: true, the chart's Ingress template automatically adds the route.openshift.io/termination: edge annotation — creating an edge-terminated HTTPS route without needing oc expose svc at all.

# values-aro.yaml — layer on top of the chart's values-openshift.yaml

serviceAccount:
  create: false
  name: kubernetes-mcp-server

service:
  type: ClusterIP
  port: 8080

# Chart creates an edge-terminated OpenShift Route automatically
ingress:
  enabled: true
  termination: edge
  host: "kubernetes-mcp-server-mcp-server.apps.<cluster-name>.<region>.aroapp.io"

# Correct key for CLI flags (mcp.args is not a valid chart field)
extraArgs:
  - --read-only
  - --disable-destructive
  - --toolsets=config,core,helm

resources:
  requests:
    cpu: 100m
    memory: 128Mi
  limits:
    cpu: 100m
    memory: 128Mi

# Do NOT set securityContext or podSecurityContext —
# the chart defaults already satisfy OpenShift's restricted-v2 SCC.

On authentication

For a local testing walkthrough, the simplest safe approach is oc port-forward instead of exposing a route — it avoids the unauthenticated public endpoint problem entirely:

oc port-forward svc/kubernetes-mcp-server 8080:8080 -n mcp-server

Then test against http://localhost:8080/mcp with no external exposure. If external access is needed, the extraContainers field supports adding an OAuth proxy sidecar — the service.targetPort value is designed for exactly this pattern — but that's probably scope for a follow-up guide.

@paulczar
Copy link
Copy Markdown
Contributor

Scope: nothing here is ARO-specific

Looking at the guide end-to-end, there's no step that requires ARO specifically — it would work identically on ROSA, OSD, or any self-managed OpenShift cluster. The only ARO-flavoured detail is the example hostname (*.aroapp.io) in the curl test.

It might be worth generalising this into an aro/ocp/ or top-level openshift/ guide that covers all OpenShift distributions, with a note that the example hostname will differ by platform. That would make it more discoverable and avoid duplicating the content if someone wants to cover ROSA later.

@paulczar
Copy link
Copy Markdown
Contributor

Live deployment test on ROSA HCP 4.19.30

Tested the OAuth passthrough auth config on a live ROSA HCP cluster. Results:

What works ✅

  • Auth enforcement (require_oauth: true + skip_jwt_verification: true + cluster_auth_mode: passthrough):
    • Unauthenticated request → 401 Unauthorized
    • Request with oc whoami --show-token Bearer token → 200 OK + SSE stream

Bug found in the values example ❌

The guide sets serviceAccount.automountToken: false, which causes CrashLoopBackOff:

Error: unable to create kubernetes target provider: no current-context is set and no contexts are defined in kubeconfig.

Even in passthrough mode, the server needs the SA token mounted to discover the cluster's API URL and CA cert via in-cluster config. The SA token is used for cluster discovery only — the actual API calls use the forwarded user Bearer token. Without it, the server can't find the cluster and dies.

Fix: set automountToken: true (or omit it, as true is the default).

serviceAccount:
  create: true
  automountToken: true   # ← required even in passthrough mode

Also: ingress.host must not be empty ❌

The chart template calls required on ingress.host, so leaving it as host: "" will fail at helm install time with a hard error. The guide should either instruct users to substitute their actual hostname, or show how to retrieve it first (e.g. rosa describe cluster -c $CLUSTER --output json | jq -r '.dns.base_domain').

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants