k8s-ops-mcp-server
by harish235
README.md
# k8s-ops-mcp-server
A [Model Context Protocol (MCP)](https://modelcontextprotocol.io) server that connects Claude Desktop to any Kubernetes cluster. Ask Claude questions in plain English — it calls your cluster's API, reads the real data, and gives you a diagnosis or performs an action.
```
"Why is the orders-service pod crashing?"
"Show me recent warning events in the payments namespace."
"Scale the api-gateway deployment to 5 replicas."
```
Works with any Kubernetes cluster — GKE, EKS, AKS, on-prem, or local Minikube. No code changes needed to switch between them, only a `kubectl` context switch.
---
## How it works
```
You (natural language)
↓
Claude Desktop ──── MCP (stdio) ────▶ k8s-ops-mcp-server
↓
@kubernetes/client-node
↓
Kubernetes API Server
(GKE / EKS / AKS / Minikube)
```
Claude decides which tools to call, calls them, and reasons over the results. The MCP server contains **no AI** — it is a thin, stateless layer over the Kubernetes API. All reasoning happens inside Claude Desktop.
---
## Available tools
| Tool | What it does | Example question |
|---|---|---|
| `list_pods` | List all pods with status, restarts, age, node | *"What pods are running in production?"* |
| `get_pod_status` | Detailed status — phase, conditions, last termination reason | *"Why is orders-service unhealthy?"* |
| `get_pod_logs` | Fetch pod logs; `previous=true` gets logs from before a crash | *"Show me the crash logs for api-gateway"* |
| `get_recent_events` | Kubernetes events sorted by recency — reveals root cause | *"What warning events happened recently?"* |
| `get_resource_usage` | Live CPU/memory vs requests/limits (requires metrics-server) | *"Which pods are near their memory limit?"* |
| `get_deployment_status` | Rollout status — desired vs ready vs available replicas | *"Did the latest deployment roll out successfully?"* |
| `scale_deployment` | ⚠️ Scale a deployment to N replicas | *"Scale payments-service to 3 replicas"* |
| `restart_pod` | ⚠️ Delete a pod to trigger recreation | *"Restart the crashing orders-service pod"* |
> ⚠️ Write actions (`scale_deployment`, `restart_pod`) default to `dryRun=true`. Claude will show you what would happen before asking for confirmation to execute.
---
## Prerequisites
- [Node.js](https://nodejs.org) v18 or later
- [kubectl](https://kubernetes.io/docs/tasks/tools/) installed, configured, and pointing at your cluster
- [Claude Desktop](https://claude.ai/download) installed
Verify kubectl is connected to your cluster before proceeding:
```bash
kubectl get nodes
```
You should see your cluster nodes listed. If this works, the MCP server will work.
---
## Setup
### 1. Clone the repo
```bash
git clone https://github.com/YOUR_USERNAME/k8s-ops-mcp-server.git
cd k8s-ops-mcp-server
```
### 2. Install dependencies and build
```bash
npm install
npm run build
```
### 3. Verify the server starts
```bash
node dist/index.js
# k8s-ops-mcp-server running on stdio
```
The process hangs waiting for input — that is correct. It is ready for an MCP client to connect. Press `Ctrl+C` to stop it.
### 4. Test all tools with MCP Inspector
Before connecting Claude Desktop, verify every tool works using the Inspector — a web UI that acts as a fake MCP client. This is the fastest way to catch issues.
```bash
npm run inspector
```
The terminal prints a URL with a session token:
```
Open inspector at: http://localhost:5173/?MCP_PROXY_AUTH_TOKEN=abc123...
```
Open that **full URL** (including the token) in your browser. Then:
1. Set **Command** to `node`
2. Set **Arguments** to the absolute path to your built server, e.g. `/Users/yourname/k8s-ops-mcp-server/dist/index.js`
3. Click **Connect** — all 8 tools appear on the left
4. Try calling `list_pods` — it should return pods from your cluster
> Get the absolute path by running `echo "$(pwd)/dist/index.js"` in the project directory.
### 5. Configure Claude Desktop
Open the Claude Desktop config file:
```bash
open ~/Library/Application\ Support/Claude/claude_desktop_config.json
```
Add the `mcpServers` section (keep any existing content in the file):
```json
{
"mcpServers": {
"k8s-ops": {
"command": "node",
"args": ["/absolute/path/to/k8s-ops-mcp-server/dist/index.js"]
}
}
}
```
Replace the path with the actual absolute path on your machine (the output of `echo "$(pwd)/dist/index.js"`).
**Quit Claude Desktop completely** with Cmd+Q and reopen it. Click the **"+" icon → Connectors** — you should see `k8s-ops` listed and enabled with all 8 tools.
### 6. Start diagnosing
Open a new chat and ask:
```
"List all pods and highlight any that are unhealthy."
"Why is the orders-service pod restarting?"
"Show me warning events from the last few minutes."
"What is the CPU and memory usage across all pods in the default namespace?"
```
---
## Switching between clusters
The server uses `kubectl`'s active context. To point it at a different cluster:
```bash
# List available contexts
kubectl config get-contexts
# Switch context
kubectl config use-context YOUR_CONTEXT_NAME
```
Then restart Claude Desktop (or just start a new conversation — the server process reloads the config). No code changes, no config file edits.
### Example: connecting to GKE
```bash
gcloud container clusters get-credentials YOUR_CLUSTER --zone us-central1-a
kubectl config use-context gke_your-project_us-central1-a_your-cluster
# Restart Claude Desktop — it now talks to GKE
```
---
## Local testing with Minikube
> Skip this section if you already have a real cluster to connect to. This is only for trying the server locally without a cloud cluster.
Minikube runs a single-node Kubernetes cluster on your laptop inside Docker. It is useful for testing the MCP tools against a real (though local) cluster, and for triggering deliberate failures to practice diagnosing them.
### Start Minikube
```bash
# Install Minikube if needed: https://minikube.sigs.k8s.io/docs/start/
minikube start
# Enable metrics-server (required for get_resource_usage)
minikube addons enable metrics-server
```
Verify it is running:
```bash
kubectl get nodes
# NAME STATUS ROLES AGE
# minikube Ready control-plane 1m
```
### Deploy the test app
The `test-app/` directory contains a small Node.js app designed to simulate real failure modes — crashes, OOM kills, and latency spikes.
**Step 1 — Point Docker at Minikube's internal engine**
This lets Kubernetes find the image without a registry. Must be run in every new terminal session.
```bash
eval $(minikube docker-env)
```
**Step 2 — Build the image**
```bash
docker build -t test-app:latest ./test-app
```
**Step 3 — Deploy**
```bash
kubectl apply -f test-app/k8s-manifests/
# Watch pods start
kubectl get pods -w
# NAME READY STATUS RESTARTS AGE
# test-app-584b76c4fc-bfwgb 1/1 Running 0 15s
# test-app-584b76c4fc-svqbk 1/1 Running 0 15s
```
### Trigger failures to test your MCP tools
```bash
# Get the test app URL
URL=$(minikube service test-app --url)
# Trigger a crash — causes CrashLoopBackOff after the liveness probe fails
curl $URL/crash
curl $URL/crash
# Trigger OOMKill — pod gets killed for exceeding the 64Mi memory limit
curl $URL/oom
```
Then ask Claude Desktop:
> *"The test-app pod keeps restarting. What's wrong with it?"*
Claude will call `list_pods` → `get_pod_status` → `get_pod_logs` (with `previous=true`) → `get_recent_events` automatically and return a real diagnosis.
### Test app endpoints
| Endpoint | What happens | Simulates |
|---|---|---|
| `GET /healthy` | Returns 200, logs each request | Normal healthy traffic |
| `GET /crash` | Throws an error, process exits | `CrashLoopBackOff` |
| `GET /slow` | Sleeps 5 seconds | Latency issues |
| `GET /oom` | Allocates memory until killed | `OOMKilled` event |
---
## Project structure
```
k8s-ops-mcp-server/
├── src/
│ ├── index.ts # MCP server entry point
│ ├── k8s/
│ │ ├── client.ts # Kubernetes client (loadFromDefault)
│ │ ├── podOperations.ts # listPods, getPodStatus, getPodLogs, restartPod
│ │ ├── deploymentOperations.ts # getDeploymentStatus, scaleDeployment
│ │ ├── eventOperations.ts # getRecentEvents
│ │ └── metricsOperations.ts # getResourceUsage
│ ├── tools/
│ │ ├── definitions.ts # MCP tool schemas and descriptions
│ │ └── handlers.ts # Routes tool calls to k8s functions
│ └── utils/
│ └── formatter.ts # Cleans up raw k8s API responses
│
├── test-app/ # Deliberately flaky app for local testing
│ ├── app.js
│ ├── Dockerfile
│ └── k8s-manifests/
│ ├── deployment.yaml # 2 replicas, 64Mi memory limit, liveness probe
│ └── service.yaml
│
├── package.json
└── tsconfig.json
```
---
## Troubleshooting
**`kubectl get nodes` fails**
Your kubeconfig is not set up. Follow your cluster provider's instructions to configure it (e.g. `gcloud container clusters get-credentials ...` for GKE).
**MCP Inspector connection error**
Use the full URL printed in the terminal — it includes a required session token (`?MCP_PROXY_AUTH_TOKEN=...`). Opening `localhost:5173` without the token fails.
**`get_pod_logs` returns an error**
Use the exact pod name from `list_pods` output (e.g. `orders-service-7d9f8b-x2k1p`), not the deployment name. After a crash, set `previous=true` to get logs from before the restart.
**`get_resource_usage` fails**
Metrics server is not installed or not yet ready. On Minikube: `minikube addons enable metrics-server`. On GKE/EKS it is usually pre-installed. Wait ~60 seconds after enabling it before querying.
**Tools disappear from Claude Desktop**
The MCP server process crashed. Confirm the path in `claude_desktop_config.json` is the correct absolute path, then restart Claude Desktop.
**Minikube: `ErrImageNeverPull`**
The image was built in your laptop's Docker, not Minikube's. Run `eval $(minikube docker-env)` in the same terminal, rebuild the image, then restart the deployment:
```bash
eval $(minikube docker-env)
docker build -t test-app:latest ./test-app
kubectl rollout restart deployment/test-app
```
---
## Security
This server is intended for **personal or local use**. Write actions execute immediately once confirmed — there is no authentication or authorization layer.
- Do not expose this server over a network
- Do not use in a shared or multi-user environment without adding an authorization layer
- All write actions (`scale_deployment`, `restart_pod`) are logged to stderr with a timestamp for local audit purposes
- Be careful when connected to a production cluster — Claude will confirm before write actions, but always review before approving
TDQS
A4.4/5.0
Scored across 8 tools
Disambiguation5/5
Each tool targets a distinct aspect of Kubernetes operations: deployment status, pod logs, pod status, events, resource usage, pod listing, pod restart, and deployment scaling. No functional overlap.
Naming Consistency5/5
All tools follow a consistent verb_noun pattern (get_deployment_status, get_pod_logs, list_pods, restart_pod, scale_deployment) with clear action and resource.
Tool Count5/5
8 tools is well-scoped for Kubernetes ops: covers critical monitoring and management actions without being overwhelming.
Completeness4/5
Covers core monitoring (logs, status, events, resource usage) and basic actions (restart, scale). Minor gaps: no describe resource, exec, or deployment rollout history, but the set is focused and practical.
Maintenance
ActivityInactive
ResponsivenessNo issues