read-only · evidence-backed · pre-release

One question in.
One ranked diagnosis out.

Built for real 3AM incidents.

argus is a Kubernetes incident-diagnosis MCP server. Ask “why is checkout-api broken?” and it correlates twelve resource kinds in a single read-only pass, then answers with ranked causes — each one citing the evidence it used.

Get started → View source

Go 1.26 · MIT · no writes, enforced by the build

The thesis

Correlation belongs in the server, not the context window

Every other Kubernetes MCP server is kubectl with a JSON schema stapled on: get_pods, describe_pod, get_logs. That pushes the correlation onto the model across ten round-trips, each dumping kilobytes of managedFields into the window. By pod four the context is noise, and a model reasoning from noise guesses.

1 ranked diagnosis with mandatory evidence

Real output

What a diagnosis actually looks like

Generated from real output rather than retyped — this panel is produced from the bytes argus diagnose actually printed, confidence drop included, because that cluster had no metrics API.

argus diagnose

The difference

Resource-shaped vs question-shaped

Typical k8s MCP serverargus
Tool surface40–100+, mirroring kubectl6, one per SRE question
Correlationthe model does it, over many callsserver-side, in one call
Outputraw objects to interpretranked findings, evidence mandatory
Context per pod2,000+ tokensunder 400, enforced by test
Repeated eventsone line eachdeduplicated, blast radius kept
Confidenceabsent, or implied certaintystated, and lowered on partial data
Writesusually available, sometimes gatednone — no mutating call site exists

Measured, not estimated

Context discipline

From one real production Deployment with 93 environment variables and 11 ReplicaSets.

0
tokens per pod
was 946 · budget 400
0
tokens per snapshot
was ~10,400
0
apiserver calls
hard cap 60
0
test suite, no cluster
55 tests, detectors are pure

The correlation engine

Seven detectors, nineteen named causes

Each is a pure function over a snapshot, so each is replayable against a committed fixture. Every fixture asserts its detector fires and that no others do — the negative half is the half that matters, because a tool that reports three wrong causes during an incident costs more time than it saves.

crashloop.*

Reads the exit code instead of restating CrashLoopBackOff. A broken entrypoint, a container that exits zero and should be a Job, SIGSEGV, an abort, a liveness-probe SIGTERM — each gets its own remedy.

lastState reason + exit code + the runtime's own error

oomkill.limit-too-low

The kernel killed it for exceeding its own limit — with a suggested new limit when usage data supports one.

lastState.reason=OOMKilled + limit + peak usage

rollout.bad-template

The new revision is failing and the previous one was healthy. Reports the fields that changed between them.

RS health pair + semantic template diff

image.pull-*

Distinguishes a typo'd tag from a missing pull secret, refused credentials, and a registry rate limit — four causes, one symptom.

waiting.reason + the runtime's own error text

endpoints.*

Tells a selector typo (matches nothing) apart from a readiness failure (matches pods, none ready). Invisible to kubectl get.

selector match count vs endpoint readiness

probe.readiness-misconfigured

Running, alive, not crashing — and still never ready. Compares the probe's real deadline against observed uptime.

initialDelay + period×failureThreshold

node.unhealthy-host

Widens scope. If the node is the cause, it says so and suppresses the per-workload symptoms rather than reporting one cause three times.

node conditions + affected pod set

Safety

Read-only, and not on the honour system

The usual advice is “enforce read-only through RBAC, not in code.” That is correct for an in-cluster deployment and false for how you will actually run this — from your own kubeconfig, where RBAC grants you everything. So the binary holds the line instead.

No mutating call site

A test walks the entire source AST and fails the build on any call to Create, Update, Patch, Delete, Apply or Evict — with a companion test proving the walk can actually fail.

Prompt injection can mislead, never act

Log and event text is user-controlled and reaches model context. argus frames it as untrusted data — but the real mitigation is structural: there is no mutation path to reach.

Secrets never leave

Secret objects are never read. Environment variable values are never projected — only key names, which is all a detector needs. Verified by test.

Self-update fails closed

The one thing argus writes is its own binary. The published SHA-256 must match or the update is abandoned, HTTPS is required across redirects, and the swap is a rename — a failure leaves the working binary intact.

It cannot flood your control plane

A hard apiserver call budget lives in an http.RoundTripper, counting every request and retry. A diagnostic tool is run during an incident. Cluster-wide triage costs 10 calls whatever the cluster size — looping the per-workload diagnosis would have been ~1,700.

Install

Install, connect, run

$ go install github.com/backendArchitect/argus@latest
$ claude mcp add argus -- argus serve

Or drive it straight from a terminal, no MCP involved:

$ argus diagnose checkout-api -n prod

And to update it later — checksum-verified, atomic, and it will not clobber a build you made from a clone:

$ argus update # or: argus update -check

Roadmap

Honest about what exists