argus

command module
v0.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 17, 2026 License: MIT Imports: 11 Imported by: 0

README ΒΆ

argus

Go License MCP Status CI Release Read-only

One question in, one ranked diagnosis out.

argus is a Kubernetes incident-diagnosis MCP server. You ask "why is checkout-api broken?" and it answers with a ranked list of causes, each one citing the evidence it used.

Named for Argus Panoptes, the hundred-eyed watchman who never slept because only some of his eyes closed at a time β€” it watches twelve resource kinds at once so you don't have to correlate them by hand.

🌐 See it in action β†’ backendarchitect.github.io/argus

Status: pre-release. diagnose_workload works end to end β€” six detectors, ranked findings, mandatory evidence β€” and is verified against fixtures captured from real clusters. cluster_triage and get_workload_logs are not built yet. See Roadmap.


Why this exists

Every Kubernetes MCP server available today is kubectl with a JSON schema stapled on: get_pods, describe_pod, get_logs. That is worse than nothing, because it pushes the correlation work onto the model across ten round-trips, each one dumping 8KB of managedFields into the context window. By pod four the context is full of YAML noise and the model starts guessing.

argus takes the opposite position: the unit of work is a question, not a resource.

Resource-shaped servers argus
Tool surface 40–100+ tools mirroring kubectl 3 tools, one per SRE question
Correlation the model does it, over many calls done server-side, in one call
Output raw objects ranked findings with mandatory evidence
Context per pod 2,000+ tokens under 400, enforced by test
Repeated events one line each deduplicated, with the blast radius kept
Writes usually available, sometimes gated none β€” no mutating call site exists

What it does today

# Diagnose a workload from the terminal β€” the same pipeline the MCP tool uses.
argus diagnose checkout-api -n prod

# Run as an MCP server over stdio.
argus serve

# Collect a raw diagnosis snapshot as YAML (this is also the fixture generator).
argus capture deploy/checkout-api -n prod

A real diagnosis, captured verbatim:

DIAGNOSIS  Deployment argus-broken/oom-victim
replicas   0/1 ready, 1 updated, 0 available
findings   1 (1 critical)

1. [critical Β· confidence 71%] oomkill.limit-too-low
   Container "app" is being OOM-killed by its own memory limit
   The kernel killed container "app" for exceeding its memory limit of 32Mi. It is now in
   CrashLoopBackOff, so it will keep restarting and dying until the limit is raised or its
   memory use comes down. Current usage is unavailable (the metrics API did not answer), so
   there is no measured basis for a new limit.
   evidence:
     Β· pod/oom-victim-7cb68bdb99-r8tsf (pod.lastState): reason=OOMKilled, exitCode=137, 127s ago
     Β· pod/oom-victim-7cb68bdb99-r8tsf (pod.spec): container "app" memory limit is 32Mi
     Β· pod/oom-victim-7cb68bdb99-r8tsf (pod.status): restarted 6 times; state CrashLoopBackOff
   next: get_workload_logs(previous=true) β€” the current container is in backoff and has
         produced nothing

incomplete β€” these lookups failed, and any finding relying on them has had its confidence
reduced:
  Β· metrics: the server could not find the requested resource

(13 apiserver calls against kind-argus-test)

Note the confidence drop and the stated gap. That cluster had no metrics API, and saying so beats implying memory looks fine.

Under the hood, one pass resolves a fuzzy name, fans out concurrently across the workload, its ReplicaSets, pods, events, metrics, Services, endpoints, nodes, HPA and PDB, then projects all of it down to an allowlisted, deduplicated snapshot. On a real production Deployment that is 13 apiserver calls and ~3,300 tokens β€” the same data unprojected runs to roughly 10,400.

The snapshot is plain YAML by design. That single constraint is what makes the test suite possible: capture writes fixtures, tests replay them with no cluster at all, and production runs the identical code path.

argus capture    β†’  gather β†’ Snapshot β†’ yaml            (writes testdata/snapshots/*.yaml)
go test          β†’  yaml   β†’ Snapshot β†’ detect β†’ assert (no cluster, sub-second)
argus serve      β†’  gather β†’ Snapshot β†’ detect β†’ rank   (production)

Read-only, and not on the honour system

argus never writes to your cluster. That is not a convention or a flag β€” there is no mutating call site in the binary, and a test walks the entire source tree's AST and fails the build on any call to Create, Update, Patch, Delete, Apply, Evict or friends.

This matters more than it sounds. The usual advice is "enforce read-only at the RBAC layer, not in your code" β€” correct for an in-cluster deployment, but false for how you will actually run this, which is from your own kubeconfig, where RBAC grants you everything. RBAC will not hold that line, so the binary holds it instead.

Two more limits are built into the client rather than bolted on:

  • A call budget. A hard cap on apiserver requests per invocation, enforced in an http.RoundTripper so it counts every request and every retry. A diagnostic tool that DoSes the control plane during an incident is a career-limiting artifact.
  • A deadline with graceful degradation. A slow cluster produces a partial snapshot that records what was missed, not a hung MCP session β€” and detectors reading partial data must lower their own confidence rather than quietly reasoning from absence.

Full threat model, including prompt injection via log and event content: SECURITY.md.


Install

Requires Go 1.26+ and a working kubeconfig.

Method Command
Go go install github.com/backendArchitect/argus@latest
Docker see below β€” the image runs as nonroot, so the kubeconfig needs mounting deliberately
Source git clone https://github.com/backendArchitect/argus && cd argus && go install .

Prebuilt binaries (Linux/macOS/Windows Β· amd64 & arm64) are on the Releases page.

The container image is distroless and runs as a nonroot uid, so mount the kubeconfig file and name it explicitly β€” mounting ~/.kube as a directory lands on a path the container user cannot read:

docker run --rm -u "$(id -u):$(id -g)" \
  -v ~/.kube/config:/kube/config:ro \
  ghcr.io/backendarchitect/argus \
  diagnose checkout-api -n prod --kubeconfig /kube/config

Note the apiserver must be reachable from inside the container: this works for a real cluster, but not for a local kind cluster listening on the host's 127.0.0.1 (add --network host for that).

Connect it to an AI editor:

claude mcp add argus -- argus serve

Roadmap

Working now

  • diagnose_workload β€” the flagship: one call in, a ranked diagnosis out
  • Six detectors β€” OOM limit too low Β· bad rollout Β· image pull (four distinct causes) Β· readiness misconfigured Β· endpoint gap (selector typo vs readiness failure) Β· node-caused, which widens scope and suppresses the per-workload symptoms it explains
  • The broken-fixture suite β€” each fixture asserts its detector fires and no others do, with a healthy control that must produce nothing
  • MCP server over stdio, with schemas derived from Go types
  • Fuzzy workload resolution (Deployment / StatefulSet / DaemonSet / Argo Rollout), returning candidates on ambiguity rather than guessing
  • Concurrent gather with a call budget, deadline, and degradation tracking
  • Projection layer: allowlisted fields, per-pod token budget, event deduplication
  • argus capture β€” snapshot to YAML, doubling as the fixture generator
  • Read-only enforcement, verified by an AST test

v0.1 β€” next

  • cluster_triage β€” what is broken right now, grouped by owner rather than per pod
  • get_workload_logs β€” auto-selects the failing container, defaults to previous on crashloop, groups stack traces, budgets output by tokens

v0.2 β€” explain_pending, trace_service_path, informer cache, kind-based CI. v0.3 β€” GKE integrations (Cloud Logging fallback for dead pods, Autopilot, Managed Prometheus), compare_environments, check_reachability, in-cluster deployment with Workload Identity.

Later, maybe never β€” mutations. That is where the liability is; read-only diagnosis is where nearly all the value is.


Learn more

In one line: argus is a read-only Kubernetes diagnosis MCP server that answers SRE questions with ranked, evidence-backed findings instead of handing a model a pile of YAML.

License

MIT

Documentation ΒΆ

Overview ΒΆ

Command argus is a read-only Kubernetes incident-diagnosis MCP server.

It answers SRE questions ("why is this workload broken?") with a ranked, evidence-backed diagnosis rather than exposing Kubernetes resources for a model to correlate itself.

Usage:

argus serve                    # MCP server over stdio (default)
argus capture deploy/foo -n ns # write a Snapshot fixture to stdout
argus diagnose foo -n ns       # run the pipeline from the CLI, no MCP

Directories ΒΆ

Path Synopsis
internal
detect
Package detect holds the correlation engine: pure functions over a model.Snapshot that produce ranked, evidence-backed findings.
Package detect holds the correlation engine: pure functions over a model.Snapshot that produce ranked, evidence-backed findings.
kube
Package kube talks to the apiserver and projects what it finds into model.Snapshot.
Package kube talks to the apiserver and projects what it finds into model.Snapshot.
model
Package model holds the plain-data types shared by the gather, detect and tool layers.
Package model holds the plain-data types shared by the gather, detect and tool layers.
project
Package project reduces raw Kubernetes objects to the allowlisted fields argus emits.
Package project reduces raw Kubernetes objects to the allowlisted fields argus emits.
tools
Package tools wires the diagnosis pipeline to MCP tools.
Package tools wires the diagnosis pipeline to MCP tools.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL