Skip to main content
Glama
jasamandehvary

kahlo-mcp

README.md
# kahlo-mcp
![frida-kahlo](frida-kahlo.jpg)

An MCP server for SRE/GitOps forensics. It wraps `kubectl`, the ArgoCD REST
API, and the Dynatrace REST API into tools so an agent can autonomously
chase "why did this deployment go unhealthy"; find the app, see if the
live cluster has drifted from git, look at pods/events/logs, spawn a debug
container if it needs to look inside a running pod, and correlate what it
found against Dynatrace problems.

## Setup

```bash
uv sync
cp .env.example .env   # fill in your ArgoCD / Dynatrace credentials
```

`kubectl` must be on `PATH` and already pointed at the target cluster
(via your normal kubeconfig, or `KUBECTL_CONTEXT` to pick a specific
context).

Run it directly:

```bash
uv run server.py
```

Or point a Claude Desktop / Claude Code MCP config at it, e.g.:

```json
{
  "mcpServers": {
    "sre-gitops-forensics": {
      "command": "uv",
      "args": ["--directory", "/absolute/path/to/frida", "run", "server.py"]
    }
  }
}
```

## Configuration

| Variable | Required for | Notes |
|---|---|---|
| `KUBECTL_CONTEXT` | kubectl tools | optional; defaults to current context |
| `ARGOCD_SERVER` | ArgoCD tools | e.g. `https://argocd.example.com` |
| `ARGOCD_AUTH_TOKEN` | ArgoCD tools | a project or account API token |
| `ARGOCD_INSECURE_SKIP_VERIFY` | ArgoCD tools | `true` to skip TLS verification (self-signed certs) |
| `DYNATRACE_ENV_URL` | Dynatrace tools | e.g. `https://abc12345.live.dynatrace.com` |
| `DYNATRACE_API_TOKEN` | Dynatrace tools | needs `entities.read` and `problems.read` scopes |

## Tools

**ArgoCD**
- `list_argocd_apps(project="")` — discover applications and their health/sync status.
- `get_argocd_app_status(app)` — health, sync status, last operation result, error conditions, unhealthy/out-of-sync resources.
- `get_live_diff(app)` — structural diff between the desired (git) state and the live cluster state, per managed resource. Filters out routine status/metadata noise so what's left is real drift (e.g. an out-of-band `kubectl edit`).

**kubectl**
- `list_pods(namespace="", label_selector="", app="")` — pods with phase, restarts, and any waiting/terminated reason (CrashLoopBackOff, OOMKilled, ImagePullBackOff, ...). Filtering by `app` matches ArgoCD's `app.kubernetes.io/instance` tracking label.
- `get_pod_logs(pod, namespace, container="", previous=False, tail_lines=200)`
- `describe_resource(kind, name, namespace)` — raw `kubectl describe` output, including its event tail.
- `get_events(cursor="", namespace="", involved_object="", limit=50)` — cursor-paginated, chronological event feed for walking an incident timeline.
- `exec_in_pod(pod, command, namespace, container="")` — run a command in a pod/container, including a spawned debug container.
- `spawn_ephemeral_debug_container(pod, namespace, image="busybox:1.36", target_container="", duration_seconds=3600, initial_command="")` — attaches an ephemeral debug container via `kubectl debug` and waits for it to come up. **Mutates the live pod** and the container can't be removed short of restarting the pod — scope RBAC for this tool's identity accordingly (`ephemeralcontainers` patch + `pods/exec`).

**Dynatrace**
- `find_dynatrace_entity(name, entity_type="")` — map a Kubernetes workload/pod name to a Dynatrace entity ID.
- `correlate_trace(dynatrace_entity_id, timeframe="now-2h")` — entity identity/tags plus any problems (with root cause and evidence) in the given timeframe.

## Typical forensics chain

```
list_argocd_apps
  -> get_argocd_app_status(app)
  -> get_live_diff(app)               # is this drift, or a real bug?
  -> list_pods(app=app)                # which pod is actually unhealthy?
  -> get_events(involved_object=pod)   # what happened around the time it broke?
  -> get_pod_logs(pod, previous=True)  # what did it say before it died?
  -> spawn_ephemeral_debug_container(pod) + exec_in_pod(...)  # look inside, if logs aren't enough
  -> find_dynatrace_entity(pod) -> correlate_trace(entity_id)  # does this line up with a known problem?
```

All tools return plain text and never raise — failures come back as
`Error: ...` strings so the calling agent can read what went wrong and try
a different path.

TDQS

A4.4/5.0

Scored across 11 tools

Disambiguation5/5

Each tool targets a distinct diagnostic step: ArgoCD app listing/status/diff, Kubernetes pod/log/event/describe/debug operations, and Dynatrace entity lookup/correlation. There is no overlapping purpose; even the three ArgoCD tools are clearly separated by whether you need inventory, status, or spec drift.

Naming Consistency5/5

All tools use snake_case verb_noun names with clear, consistent verbs: list/get/describe/exec/spawn/find/correlate. The pattern is predictable, so an agent can infer what a tool does from its name alone.

Tool Count5/5

11 tools is a well-scoped size for a Kubernetes/ArgoCD/Dynatrace troubleshooting server. Each tool earns its place in the incident-investigation workflow without redundancy.

Completeness5/5

The set covers the full observability loop: discover an ArgoCD app, check status and drift, inspect pods/logs/events/describe, spawn debug containers and exec commands, then correlate with Dynatrace problems. No dead ends or obvious missing operations for the stated diagnostic purpose.

Maintenance

ActivityMaintained
ResponsivenessNo issues