Gives Claude read-only access to your Kubernetes clusters through kubectl-style operations: list resources, describe objects, tail logs, check events, and pull metrics from metrics-server. Built in Go over stdio. Secrets are automatically masked before they reach the model, and the server locks to whatever kubeconfig context is active at startup, so prompt injection can't make Claude pivot to production. Responses are token-efficient, returning only diagnostic fields instead of full API objects. When Claude wants to mutate something, it prints the kubectl command for you to run manually. If you troubleshoot Kubernetes incidents with an AI and want guardrails that work even when you're tired, this handles the inspection layer safely.
A read-only MCP server that gives Claude access to Kubernetes clusters. Built in Go, it communicates over stdio using the MCP protocol.
get, describe, logs, and top style operations. No create, update, or delete. If a mutating operation is needed, the server prints the equivalent kubectl command for you to run manually. Safe to use while on-call at night: Claude can never accidentally mutate your cluster, even under prompt fatigue.| Object/Field | Reason |
|---|---|
| Secret.data | Secret leak prevention |
| Secret.stringData | Secret leak prevention |
| CertificateSigningRequest.spec.request | Large base64 PEM blob, no diagnostic value, saves tokens |
| Certificate (cert-manager) .spec.keystores | Cert chain PEM blobs, no diagnostic value, saves tokens |
| Certificate (cert-manager) status.conditions[].message | Cert chain PEM blobs, no diagnostic value, saves tokens |
| *.managedFields | No diagnostic value, saves tokens |
| Tool | Description |
|---|---|
k8s_list_resources | List any resource type by name — pods, deployments, CRDs, etc. Accepts optional namespace filter. Returns name, status, readiness, restarts, node, IP, and more depending on resource kind. |
k8s_describe_resource | Return the full YAML of a single resource. Secret data is masked. |
k8s_list_resource_types | List all available resource types via the discovery API. Accepts optional API group filter. |
k8s_get_logs | Fetch pod logs. Supports container selector, tail lines, and --previous for crashed containers. |
k8s_get_events | List Kubernetes events for a namespace or the whole cluster, sorted by most recent. |
k8s_top_pods | CPU and memory usage per pod, with per-container breakdown. Requires metrics-server. |
k8s_top_nodes | CPU and memory usage per node, with percentage of allocatable capacity. Requires metrics-server. |
| Environment variable | Default | Description |
|---|---|---|
KUBECONFIG | ~/.kube/config | Path to kubeconfig file |
Build the binary and add it to your Claude Desktop or claude CLI configuration:
make build
# binary is written to bin/mcp-k8s-ro
{
"mcpServers": {
"k8s": {
"type" : "stdio",
"command": "/path/to/bin/mcp-k8s-ro",
"env": {
"KUBECONFIG": "/path/to/.kube/config"
}
}
}
}
Or via the CLI:
claude mcp add --transport stdio --scope user mcp-k8s-ro [path to binary]
Pull the image from GitHub Container Registry (pinning a specific version is recommended):
docker pull ghcr.io/your-ko/mcp-k8s-ro:latest
Add it to your Claude Desktop or claude CLI configuration. The kubeconfig directory is mounted read-only into the container:
{
"mcpServers": {
"k8s": {
"command": "docker",
"args": [
"run", "--rm", "-i",
"-v", "/path/to/.kube:/home/nonroot/.kube:ro",
"ghcr.io/your-ko/mcp-k8s-ro:latest"
]
}
}
}
If your kubeconfig is in a non-standard location, pass it via KUBECONFIG:
{
"mcpServers": {
"k8s": {
"command": "docker",
"args": [
"run", "--rm", "-i",
"-e", "KUBECONFIG=/config/my-kubeconfig",
"-v", "/path/to/my-kubeconfig:/config/my-kubeconfig:ro",
"ghcr.io/your-ko/mcp-k8s-ro:latest"
]
}
}
}
The server intentionally operates on one kubeconfig context and provides no tool to switch clusters at runtime. The reasons are:
To point the server at a different cluster, stop the server, switch context, and restart:
kubectl config use-context my-other-cluster
# then restart the MCP server / reload Claude Desktop
To work with multiple clusters simultaneously, register a separate server instance per cluster in your MCP config:
{
"mcpServers": {
"k8s-staging": {
"type": "stdio",
"command": "/path/to/bin/mcp-k8s-ro",
"env": { "KUBECONFIG": "/path/to/.kube/config" }
},
"k8s-prod": {
"type": "stdio",
"command": "/path/to/bin/mcp-k8s-ro",
"env": { "KUBECONFIG": "/path/to/.kube/config-prod" }
}
}
}
Claude will address each server by name and each instance only ever sees its own cluster.
This server is published on registry.modelcontextprotocol.io
KUBECONFIGPath to the kubeconfig file. Defaults to ~/.kube/config.
silenceper/mcp-k8s
azure/containerization-assist
io.github.evozim/aws-builder
reza-gholizade/k8s-mcp-server
flux159/mcp-server-kubernetes