Skip to main content
Glama
README.md
# kubeaid-mcp

An MCP (Model Context Protocol) server that exposes a Kubernetes cluster to any
MCP-compatible AI client (Claude Code, Claude Desktop, Cursor, ...). The client
launches the server as a subprocess and talks to it over stdio (JSON-RPC 2.0);
the server translates tool calls into Kubernetes API calls via
[`@kubernetes/client-node`](https://github.com/kubernetes-client/javascript).

Built in TypeScript on the [NitroStack](https://nitrostack.ai) MCP framework.

See [design.md](./design.md) for the architecture.

## Demo

[![kubeaid-mcp demo](https://img.youtube.com/vi/QFLlo8RDWf8/maxresdefault.jpg)](https://www.youtube.com/watch?v=QFLlo8RDWf8)

## Tools

| Tool | Description |
|------|-------------|
| `list_contexts` | List the kubeconfig contexts (clusters) the server can target. |
| `list_namespaces` | List namespaces in a cluster, with status. |
| `list_pods` | List pods in a namespace (or all namespaces), with derived status, ready count, restarts and age. |
| `describe_pod` | Pod status, per-container state (waiting/termination reasons, last restart), and recent events. |
| `get_pod_logs` | Tail a container's logs; `previous: true` reads a crashed instance's prior logs. |
| `list_deployments` | List deployments with ready/up-to-date/available replica counts and age. |
| `list_nodes` | List cluster nodes with Ready status, roles, version and internal IP. |
| `get_events` | Recent events in a namespace (or all), sorted oldest to newest. |
| `describe_resource` | Fetch any resource kind (incl. CRDs) by kind/plural/short-name and name. |

Every tool accepts an optional `context` argument to target a specific
kubeconfig context. Omit it to use the server's default context.

### Write tools (opt-in)

These are registered only when `KUBEAID_ALLOW_WRITES=true`. Each accepts an
optional `dry_run` to simulate the change server-side without persisting it.

| Tool | Description |
|------|-------------|
| `apply_manifest` | Create or update resources from a YAML/JSON manifest (server-side apply). |
| `patch_resource` | Patch an existing resource (strategic / merge / json). |
| `delete_resource` | Delete a resource by kind and name. |
| `scale_deployment` | Set a deployment's replica count. |
| `rollout_restart` | Rolling-restart a deployment/statefulset/daemonset. |
| `exec_command` | Run a command inside a container (only with `KUBEAID_ALLOW_EXEC=true`). |

## Prompts

Prompts are user-invoked workflow templates (surfaced as slash commands / menu
items in the client). Unlike tools, a prompt does not touch the cluster — it
returns a message that guides the model through a task using the tools above.

| Prompt | Arguments | What it does |
|--------|-----------|--------------|
| `diagnose_pod` | `namespace`, `pod_name`, `context?` | Walk through describe → logs to find why a pod is unhealthy and suggest a fix. |
| `triage_namespace` | `namespace`, `context?` | Find every unhealthy workload in a namespace and investigate each. |
| `cluster_health_check` | `context?` | High-level health sweep: nodes, pods across all namespaces, recent warnings. |
| `review_warnings` | `namespace?`, `context?` | Review recent Warning events and explain what they mean. |

## Installation

Requires **Node.js 20+**. Build the server once, then register it with your AI
client(s).

### 1. Build the server

```bash
git clone https://github.com/1shubham7/kubeaid-mcp-ts.git
cd kubeaid-mcp-ts
npm install
npm run build        # compiles TypeScript to dist/ (entry: dist/index.js)
```

Note the absolute path to the entry point — the AI clients need it:

```bash
echo "$(pwd)/dist/index.js"
```

For local iteration you can also run `npm run dev` (NitroStack's dev server with
hot reload), which is handy with [NitroStudio](https://nitrostack.ai/studio) as a
visual MCP client.

### 2. Register with Claude Code

```bash
claude mcp add kubeaid -- node "$(pwd)/dist/index.js"
```

With no `KUBEAID_CONTEXT` set, the server follows your kubeconfig's
current-context live, so `kubectl config use-context <name>` switches the target
cluster without re-registering. Pin a fixed default by adding
`-e KUBEAID_CONTEXT=kind-kubeaid` if you'd rather it never move.

Read tools only are exposed by default. To enable the mutating tools
(apply/patch/delete/scale/rollout), pass `-e KUBEAID_ALLOW_WRITES=true`, and list
any production contexts as protected so they can never be written to:

```bash
claude mcp add kubeaid \
  -e KUBEAID_ALLOW_WRITES=true \
  -e KUBEAID_PROTECTED_CONTEXTS=prod-cluster,another-prod-cluster \
  -- node "$(pwd)/dist/index.js"
```

### 3. Register with Claude Desktop

Recent Claude Desktop builds gate local MCP servers behind a setting, so order
matters:

1. **Enable local MCP:** Settings → Developer → **Local MCP servers**. Local
   stdio servers are off by default; opening/enabling this is required.
2. **Edit the config:** on that page click **Edit Config** — it opens the file
   the app actually reads (`~/.config/Claude/claude_desktop_config.json` on
   Linux; macOS `~/Library/Application Support/Claude/`; Windows
   `%APPDATA%\Claude\`). Add a top-level `mcpServers` key, using the absolute
   path from step 1:

   ```json
   {
     "mcpServers": {
       "kubeaid": {
         "command": "node",
         "args": ["/home/you/kubeaid-mcp-ts/dist/index.js"]
       }
     }
   }
   ```

   If the file already has other keys (e.g. `preferences`), keep them and add
   `mcpServers` alongside — don't overwrite the file.

3. **Fully quit and reopen** Claude Desktop. Closing the window is not enough on
   Linux — the process must actually exit. The server then appears under
   Settings → Developer → Local MCP servers.

**Enabling writes:** add the options via an `env` block — e.g. make the local
cluster writable while protecting production:

```json
{
  "mcpServers": {
    "kubeaid": {
      "command": "node",
      "args": ["/home/you/kubeaid-mcp-ts/dist/index.js"],
      "env": {
        "KUBEAID_CONTEXT": "kind-kubeaid",
        "KUBEAID_ALLOW_WRITES": "true",
        "KUBEAID_PROTECTED_CONTEXTS": "prod-cluster,another-prod-cluster"
      }
    }
  }
}
```

Add `"KUBEAID_ALLOW_EXEC": "true"` for the `exec_command` tool, and re-run
step 3 after changing the config.

**Notes:**

- `command`/`args` must use absolute paths; GUI apps don't inherit your shell
  `PATH`, and Node needs the absolute path to `dist/index.js`.
- Destructive tools carry a `destructiveHint`, so Desktop still prompts you per
  action — the env vars control what's *possible*; the prompt is your confirmation.
- If your account is enterprise-managed, an admin policy can disable local MCP
  entirely, in which case no local config will load.

## Safety

The server is **read-only by default** — the read tools only call non-mutating
verbs (get, list, watch, log). Mutating tools exist but are gated:

- `KUBEAID_ALLOW_WRITES=true` must be set for `apply_manifest`, `patch_resource`,
  `delete_resource`, `scale_deployment`, and `rollout_restart` to be exposed at
  all.
- `KUBEAID_ALLOW_EXEC=true` (in addition) is required for `exec_command`.
- `KUBEAID_PROTECTED_CONTEXTS` lists contexts that may **never** be written to or
  exec'd into, even with the flags above — put your production contexts here.
- Tools are annotated (`readOnlyHint` / `destructiveHint`) so clients can prompt
  before risky actions.

The server authenticates with your kubeconfig credentials, so it can only do
what your account is already permitted to do.

## Configuration

All configuration is read from the environment at startup. An MCP client passes
these via the server entry's `env` block (Claude Desktop) or `-e` flags (Claude
Code). A local `.env` file also works for development — see
[`.env.example`](./.env.example).

| Variable | Default | Meaning |
|----------|---------|---------|
| `KUBECONFIG` | `~/.kube/config` | Path to the kubeconfig file. |
| `KUBEAID_CONTEXT` | follows kubeconfig current-context (live) | Pin a fixed default context. Omit it to track current-context live, so `kubectl config use-context` switches the cluster mid-session. Individual tool calls can always override it. |
| `KUBEAID_REQUEST_TIMEOUT` | `30s` | Per-request timeout for Kubernetes API calls (e.g. `30s`, `1m`, or milliseconds). |
| `KUBEAID_ALLOW_WRITES` | `false` | Expose the mutating tools (apply/patch/delete/scale/rollout). |
| `KUBEAID_ALLOW_EXEC` | `false` | Expose `exec_command` (run commands in containers). |
| `KUBEAID_PROTECTED_CONTEXTS` | none | Comma-separated contexts that may never be written to or exec'd into. |

## Development

Drive the server by hand (no AI client needed) to inspect the raw protocol and
confirm which tools are registered:

```bash
npm run build
KUBECONFIG=~/.kube/config node scripts/drive.mjs   # initialize + tools/list + prompts/list
```

TDQS

A4.2/5.0

Scored across 9 tools

Disambiguation5/5

Every tool targets a distinct Kubernetes resource or action (e.g., describe_pod vs describe_resource, list_pods vs list_deployments), with no overlapping purposes.

Naming Consistency5/5

All tools follow a consistent verb_noun pattern with lowercase and underscores (e.g., list_pods, get_events, describe_resource), making them predictable and easy to differentiate.

Tool Count5/5

With 9 tools, the surface is lean yet comprehensive for a diagnostic Kubernetes MCP server, covering essential inspection operations without unnecessary bloat.

Completeness4/5

The tool set covers core diagnostic workflows—listing, describing, logs, events—but misses operational actions like exec, port-forward, or resource creation. Minor gap given the diagnostic focus.

Maintenance

ActivityInactive
ResponsivenessNo issues