Deploying the OpenShift MCP Server on Openshift
Let’s set the stage This is the last installment of my short MCP series for the homelab. I already covered the overview, deploying aap-mcp on my operator-m...
This is the last installment of my short MCP series for the homelab. I already covered the overview, deploying aap-mcp on my operator-managed platform, and deploying rhel-mcp for Linux host diagnostics. This post is about openshift-mcp: the bridge that lets an assistant in Cursor talk to my Openshift cluster API.
In the overview I said I would write up token hardening for Openshift MCP. What I am really doing here is walking through the full deployment: manifests, auth, and how I connect Cursor. The auth piece is the important part.
The OpenShift MCP Server is based on the upstream Kubernetes MCP server work. It is a tech-preview style project that exposes cluster tools over HTTP so clients like Cursor can list pods, pull logs, query metrics, work with routes, and do a lot of other API-backed tasks without you pasting oc output into chat.
In my lab the server runs as a pod in the openshift-mcp namespace on ocp.bk.lab. Cursor hits a route like openshift-mcp-server-openshift-mcp.apps.ocp.bk.lab/mcp. I do not run it with npx and a local kubeconfig on my laptop, though that is a valid option if you prefer.
There are two auth ideas to keep straight:
I use token passthrough for the second one. That means when I put my Openshift bearer token in Cursor, the MCP server uses my RBAC for API calls, not some shared super-user built into the pod.
Before you apply manifests, you should have:
oc logged in with permission to create a namespace, deployment, route, and a ClusterRoleBindingview to the MCP service account (needed for parts of in-cluster setup)oc whoami -t works for lab use)I keep a directory of YAML files that create the openshift-mcp namespace and roll out the server. Here is what each file is for.
Creates the openshift-mcp project, separate from aap and rhel-mcp.
apiVersion: v1
kind: Namespace
metadata:
name: openshift-mcp
The identity the pod runs as. Even with passthrough auth, the deployment still mounts a service account token for in-cluster provider detection.
apiVersion: v1
kind: ServiceAccount
metadata:
name: openshift-mcp-server
namespace: openshift-mcp
Grants the built-in view ClusterRole to the MCP service account. This matters when cluster_auth_mode is kubeconfig (the default). I still apply it in my lab even though passthrough is what I actually use day to day.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: openshift-mcp-server-view
roleRef:
kind: ClusterRole
name: view
subjects:
- kind: ServiceAccount
name: openshift-mcp-server
namespace: openshift-mcp
The main config.toml for the server. Mine enables several toolsets and is not read-only. That was a deliberate lab choice so the assistant can do more than look around.
port = "8080"
cluster_provider_strategy = "in-cluster"
read_only = false
disable_destructive = false
toolsets = ["core", "config", "openshift", "kubevirt", "metrics", "traces"]
trust_proxy_headers = true
Setting read_only = false means write-style tools can be exposed. What actually happens still depends on your user token’s RBAC. If your account cannot delete a namespace, the assistant cannot either. disable_destructive = false is another knob on the server side; combine that with passthrough and you need to be honest about risk.
For a safer starting point, set read_only = true and leave destructive tools disabled until you know what you need.
A small overlay mounted at /etc/kubernetes-mcp-server/conf.d that switches API auth to passthrough.
cluster_auth_mode = "passthrough"
With this in place, the MCP server forwards the agent’s Authorization: Bearer header to the Openshift API. Tools run as you, not as the pod service account.
I did not turn on require_oauth in the lab. That would force JWT validation on every MCP HTTP call. Openshift tokens from oc whoami -t are opaque, not JWTs, so that path is a better fit when you wire up a full OIDC flow. For my homelab I rely on network isolation plus sending a user token from Cursor.
Runs the container image quay.io/redhat-user-workloads/crt-nshift-lightspeed-tenant/openshift-mcp-server:latest, mounts the main config and auth overlay, and exposes port 8080.
containers:
- name: openshift-mcp-server
image: quay.io/redhat-user-workloads/crt-nshift-lightspeed-tenant/openshift-mcp-server:latest
args:
- "--config"
- "/etc/kubernetes-mcp-server/config.toml"
volumeMounts:
- name: config
mountPath: /etc/kubernetes-mcp-server
readOnly: true
- name: auth-config
mountPath: /etc/kubernetes-mcp-server/conf.d
readOnly: true
Exposes the deployment inside the cluster on port 8080. The route and health probes target this service.
apiVersion: v1
kind: Service
metadata:
name: openshift-mcp-server
namespace: openshift-mcp
spec:
selector:
app: openshift-mcp-server
ports:
- name: http
port: 8080
targetPort: http
protocol: TCP
Creates an Openshift Route so MCP clients outside the cluster can connect over HTTPS. TLS terminates at the router with edge termination.
apiVersion: route.openshift.io/v1
kind: Route
metadata:
name: openshift-mcp-server
namespace: openshift-mcp
annotations:
haproxy.router.openshift.io/timeout: 5m
spec:
to:
kind: Service
name: openshift-mcp-server
weight: 100
port:
targetPort: http
tls:
termination: edge
insecureEdgeTerminationPolicy: Redirect
In my lab the MCP URL is https://openshift-mcp-server-openshift-mcp.apps.ocp.bk.lab/mcp.
Change into the directory with your manifests and apply them.
oc apply -f .
Confirm the pod is running.
oc get pods -n openshift-mcp
Grab the route host.
oc get route openshift-mcp-server -n openshift-mcp -o jsonpath='https://{.spec.host}/mcp{"\n"}'
Optional health check.
curl -sk "$(oc get route openshift-mcp-server -n openshift-mcp -o jsonpath='https://{.spec.host}')/healthz"
For passthrough mode the assistant needs a real Openshift token in every MCP request.
Get a token (lab shortcut):
oc whoami -t
Tokens expire. When tools start failing with auth errors, run it again and update Cursor.
Add the server to ~/.cursor/mcp.json:
{
"mcpServers": {
"openshift-mcp": {
"type": "http",
"url": "https://openshift-mcp-server-openshift-mcp.apps.ocp.example.com/mcp",
"headers": {
"Authorization": "Bearer <token-from-oc-whoami-t>"
}
}
}
}
List pods in the aap namespace
If the token and route are good, you get real data back. If you get forbidden errors, check whether your user actually has permission for that namespace or verb.
When I use my normal admin-capable lab account, the assistant can do anything I could do in the API within the tools exposed by the server. That is powerful and a little scary.
When I use a tighter account, the assistant is tightened too. Same idea as the AAP MCP post: the server is not a bypass around RBAC.
require_oauth on the HTTP endpoint. If someone on my network could reach the URL, they might talk to MCP without your user token depending on server behavior. I count on lab network boundaries. For anything stricter, look at OAuth-protected MCP in the upstream docs.mcp.json with a real bearer token in git.read_only = false plus passthrough means a confused or overly eager assistant could try mutating things you are allowed to change. I accept that in the lab because it helps me move faster. I would tighten both server config and RBAC for production.The upstream repo has a detailed auth guide (AGENT-AUTH.md in the project) covering lab mode, passthrough, and full OAuth. I leaned on passthrough because it maps cleanly to how I already use oc.
On ocp.bk.lab I now have three HTTP MCP endpoints:
I turn on whichever ones match the problem. Cluster question? Openshift MCP. Job template or dispatch? AAP MCP. Service failing on idm01.bk.lab? RHEL MCP. Often two at once, occasionally all three when OpenShift Virtualization is involved.
Authorization in Cursor, passthrough mode has nothing to forward and tools fail in confusing ways.oc whoami -t again and update the config./mcp on the openshift-mcp route, not the main console route.read_only gates which tools exist; your token still decides what API calls succeed.oc get pods -n openshift-mcpmcp.json? oc get route -n openshift-mcpoc whoami -toc auth can-i <verb> <resource> -n <namespace>auth-config volume at conf.dDeploying openshift-mcp closed the loop on the MCP series for my homelab. AAP covers automation, RHEL covers hosts, and Openshift MCP covers the cluster itself. The setup is not hard, but the auth choices matter more than the YAML. Passthrough with a bearer token in Cursor was the right trade for me: the assistant acts as me, and I can narrow that identity whenever I want.
If you have been following along since the overview, this is the Openshift piece I kept promising. All three posts together are how I actually run MCP today on ocp.bk.lab.
For more detail see the OpenShift MCP Server on GitHub and Red Hat’s article on MCP for root-cause analysis in VS Code and Cursor.
As with everything I write about my lab, this is how I run things. Your auth model, toolsets, and appetite for write access may differ. Keep secret data out of git.
Let’s set the stage This is the last installment of my short MCP series for the homelab. I already covered the overview, deploying aap-mcp on my operator-m...
Let’s set the stage Several weeks ago I started a short series on Model Context Protocol (MCP) servers in my homelab. That first post was a broad overview ...
Let’s set the stage Last week I published a post about Model Context Protocol (MCP) servers in my homelab and how I’ve been using them with Cursor to give A...
Let’s set the stage If you’ve been following along, you already know my homelab is built to represent an enterprise environment as closely as I can manage. ...
Let’s set the stage for all of my content As I build demos and content to share, it’s important that I have and easy, repeatable way to demonstrate capabili...
What’s going on with me in 2026 The beginning of every new calendar year comes with change especially when, like me, you work in a large Enterprise sales or...
It’s been a couple of months I was working hard on the Ansible + Terraform series…and was almost ready to complete part 3 (which is still coming, btw!), but...
There’s still more than one best tool In Part 1, I showed you how to configure a basic Terraform project and deploy some infrastructure, in particular EC2 i...
There’s more than one best tool Terraform and Ansible working together is a subject I get asked about fairly regularly. Most of the time, the way the conve...
Just like the environments we work with in datacenters and clouds, a homelab can consist of a variety of hardware, software, configurations, interdependencie...
Making visual improvements You’ll notice that I keep making visual changes to the site. As I find improvements or add pages, they will seem to just magical...
Slight snafu…easy fix! I made a little boo-boo and used a domain name and blog name that I shouldn’t have. All is well and I’ve updated the site to somethi...
Let’s configure custom DNS In my efforts to share knowledge about tech things, setting up a blog seemed like one of the easier things to do. It is a challe...
Welcome to Brad Does Tech This is where I’ll be posting about cool tech things I learn or demo for my customers. Stay tuned for more! –Brad