Skip to main content
Glama
harish235

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