Skip to main content
Glama
Krishna1704M

mcp-k8s-context-server

by Krishna1704M
README.md
# MCP K8s Context Server

A **FastMCP** server that exposes Kubernetes as a set of read-only tools consumable by LLMs, plus an analytics layer for pod-health analysis and resource-trend tracking.

---

## Features

| Tool | Description |
|------|-------------|
| `list_pods(namespace)` | List pods in a namespace with phase and restart info |
| `get_pod_status(pod_name, namespace)` | Detailed pod status, conditions, and container states |
| `get_pod_logs(pod_name, namespace, tail_lines)` | Tail recent pod logs |
| `get_deployment_manifest(deployment_name, namespace)` | Full deployment spec as JSON |
| `analyze_pod_health(namespace, hours)` | **Analytics**: scan logs, detect error patterns, rank unhealthy pods |
| `get_resource_trends(deployment_name, namespace)` | **Analytics**: CPU/memory from Metrics API with historical SQLite persistence |

---

## Project Structure

```
mcp-k8s-context-server/
├── k8s_mcp_server.py        # FastMCP server (all tools)
├── requirements.txt         # Python dependencies
├── Dockerfile               # Container image definition
├── k8s/
│   ├── serviceaccount.yaml  # ServiceAccount + Namespace
│   ├── role.yaml            # Least-privilege ClusterRole (read-only)
│   ├── rolebinding.yaml     # ClusterRoleBinding
│   └── deployment.yaml      # Deployment + Service
└── .github/
    └── workflows/
        └── ci.yml           # Build + kubeconform validation
```

---

## Local Development

```bash
# Create and activate a virtual environment
python -m venv .venv && source .venv/bin/activate

# Install dependencies
pip install -r requirements.txt

# Run with local kubeconfig (falls back automatically from in-cluster config)
python k8s_mcp_server.py
```

---

## In-Cluster Deployment (minikube)

### Prerequisites

```bash
# Install minikube, kubectl, docker
minikube version   # >= 1.32
kubectl version    # >= 1.28
docker version     # >= 24
```

### Step 1 — Start minikube

```bash
minikube start --cpus=2 --memory=4096
```

### Step 2 — Enable metrics-server (required for `get_resource_trends`)

```bash
minikube addons enable metrics-server
```

### Step 3 — Build and load the image into minikube

```bash
# Build locally
docker build -t mcp-k8s-server:latest .

# Load into minikube's image registry (no registry push needed)
minikube image load mcp-k8s-server:latest

# Verify the image is available
minikube image ls | grep mcp-k8s-server
```

### Step 4 — Apply Kubernetes manifests

```bash
# Apply in dependency order: SA → Role → Binding → Deployment
kubectl apply -f k8s/serviceaccount.yaml
kubectl apply -f k8s/role.yaml
kubectl apply -f k8s/rolebinding.yaml
kubectl apply -f k8s/deployment.yaml
```

### Step 5 — Verify the Pod is Running

```bash
kubectl get pods -n mcp-system
# Expected:
# NAME                              READY   STATUS    RESTARTS   AGE
# mcp-k8s-server-xxxxxxxxx-xxxxx   1/1     Running   0          30s

kubectl logs -n mcp-system deploy/mcp-k8s-server
# Expected: "Using in-cluster Kubernetes config (ServiceAccount token)"
```

### Step 6 — Test read-only tools in-cluster

```bash
# Port-forward to access the server from your laptop
kubectl port-forward -n mcp-system svc/mcp-k8s-server 8000:8000 &

# Create a test pod to query
kubectl run nginx-test --image=nginx --restart=Never

# Test list_pods
curl -s http://localhost:8000/tools/list_pods \
  -H 'Content-Type: application/json' \
  -d '{"namespace":"default"}' | jq .

# Test get_pod_logs
curl -s http://localhost:8000/tools/get_pod_logs \
  -H 'Content-Type: application/json' \
  -d '{"pod_name":"nginx-test","namespace":"default","tail_lines":20}' | jq .

# Test analyze_pod_health
curl -s http://localhost:8000/tools/analyze_pod_health \
  -H 'Content-Type: application/json' \
  -d '{"namespace":"default","hours":1}' | jq .
```

### Step 7 — Prove RBAC blocks write operations

The ServiceAccount has **no write verbs**. To confirm this:

```bash
# Exec into the pod and try to delete another pod using the SA token
MCP_POD=$(kubectl get pod -n mcp-system -l app=mcp-k8s-server -o jsonpath='{.items[0].metadata.name}')

kubectl exec -n mcp-system $MCP_POD -- \
  kubectl delete pod nginx-test --namespace=default \
  --token=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token) \
  --server=https://kubernetes.default.svc \
  --certificate-authority=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
```

**Expected output:**

```
Error from server (Forbidden): pods "nginx-test" is forbidden:
  User "system:serviceaccount:mcp-system:mcp-server-sa" cannot delete
  resource "pods" in API group "" in the namespace "default"
```

This **403 Forbidden** response from the API server is the live proof that the RBAC scoping works — the ServiceAccount can read but cannot modify any resource.

---

## RBAC Least-Privilege Design

### Philosophy

> _Grant only what is needed, explicitly deny everything else._

The MCP server is an **observability tool** — it reads cluster state to help operators and AI systems understand what's happening. It has no legitimate reason to create, modify, or delete any resource.

### What is granted

| Resource | Verbs | Reason |
|---|---|---|
| `pods` | `get, list, watch` | `list_pods`, `get_pod_status`, `analyze_pod_health` |
| `pods/log` | `get, list, watch` | `get_pod_logs`, `analyze_pod_health` |
| `deployments` | `get, list, watch` | `get_deployment_manifest`, `get_resource_trends` |
| `metrics.k8s.io/pods` | `get, list` | `get_resource_trends` (Metrics API) |

### What is explicitly NOT granted

| Verb | Reason for exclusion |
|---|---|
| `create` | No tool creates any resource |
| `update` / `patch` | No tool modifies any resource |
| `delete` / `deletecollection` | Catastrophic if misused; no read tool needs it |
| `escalate` / `bind` | Prevents privilege escalation |

This means a compromised MCP server **cannot** delete pods, scale deployments down to zero, modify secrets, or affect any running workload. The blast radius of a compromised MCP server is limited to **reading** information — not disrupting it.

---

## Analytics Layer

### `analyze_pod_health`

1. Lists all pods in the namespace.
2. Fetches up to 500 log lines per pod.
3. Pattern-matches against a catalogue of known failure indicators:
   - `OOMKilled`, `CrashLoopBackOff`
   - Python/Java exceptions (Traceback, RuntimeError, etc.)
   - Panic, SIGSEGV/SIGKILL, Connection errors, Permission denied
   - Liveness/Readiness probe failures
4. Computes a **health score** per pod (lower = worse).
5. Returns pods ranked worst-first with error frequency counts.
6. Persists results to SQLite for historical analysis.

### `get_resource_trends`

1. Resolves pod selector from the Deployment spec.
2. Reads resource **limits** from pod specs.
3. Queries the **Kubernetes Metrics API** (`metrics.k8s.io/v1beta1`) for live CPU/memory.
4. Computes: average, peak, and % of limit for both CPU and memory.
5. **Persists each snapshot** to `mcp_analytics.db` so trends build up across calls.

> Requires `metrics-server` addon: `minikube addons enable metrics-server`

---

## CI / Continuous Integration

The GitHub Actions workflow (`.github/workflows/ci.yml`) runs on every push and PR:

1. **Docker Build** — builds the image without pushing (validates Dockerfile + dependencies).
2. **kubeconform** — validates all `k8s/*.yaml` manifests against the Kubernetes 1.29 schema in strict mode.
3. **ruff** — lints `k8s_mcp_server.py` for Python errors and style.

---

## Environment Variables

| Variable | Default | Description |
|---|---|---|
| `MCP_DB_PATH` | `mcp_analytics.db` | Path to the SQLite analytics database |

---

## License

MIT