Kex-anHarness: governed AI agent with MCP tools, supervision and human approvals.
2.7K
A governed AI agent for Kafka operations. It watches your integration processes through MCP tools, explains what it sees, and asks a named human before it acts — every decision carrying its confidence, its evidence and an audit trail.
Built on Spring Boot 4 / Spring AI 2, Java 21. Ships with a browser console (the Control Center) served by the agent itself, no build step and no CDN. The console manages MCP connections at runtime, shows session activity and lifecycle, and lets you call tools, read resources and fill parameterized resource templates.
| Tag | What it is |
|---|---|
latest | Most recent stable release |
x.y.z | An exact release — what you pin in production |
x.y / x | The newest patch of that minor / major line — moves with each release |
sha-<short> | A single commit, kept for traceability |
edge | The latest manual build from main — never a release |
Pre-releases get neither latest nor the moving x.y / x tags — a docker pull without a tag should not bring back code nobody
has finished judging.
The same tags are mirrored to ghcr.io/devdownin/kex-agent-ai.
linux/amd64 only: an arm64 image would mean QEMU and an emulated Maven build, an order of magnitude
more build time. Each image ships an SBOM, and is scanned for vulnerabilities before it is
pushed — the scan runs on a locally loaded build, so a vulnerable image is never published first and
judged afterwards. After the push it is pulled back from the registry and started, because a
successful push says the layers left, not that the manifest is servable.
Against a Kafka SQL Explorer you already run:
docker run --rm -p 8081:8081 \
-e ANTHROPIC_API_KEY=sk-ant-... \
-e KEX_AGENT_API_KEY="$(openssl rand -hex 32)" \
-e KAFKA_EXPLORER_URL=http://host.docker.internal:8080 \
compagnonsdudev/kex-agent-ai:latest
Then open http://localhost:8081 and paste the same bearer once — it lives in sessionStorage
and never leaves the browser. On a fresh install the first screen is a setup checklist that names
what is still missing — model key, a reachable MCP server, declared processes — and Run now
stays disabled, with its reason, until an analysis cycle can actually succeed. Or talk to the API directly:
curl -X POST localhost:8081/api/agent/chat \
-H "Authorization: Bearer $KEX_AGENT_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"message":"List the topics whose name starts with demo. and tell me which ones are empty."}'
The whole stack — Kafka 4.3 (KRaft), Explorer with its MCP server on, and this agent wired to it —
is one docker compose up away from
the repository.
Under Intégrations (the console is in French), connections can be tested before they are added, enabled or disabled, restricted per tool, diagnosed, and imported/exported. HTTP, SSE and stdio transports are supported. Each connection's Details panel exposes active/idle MCP sessions and recent activity, and lets you call tools, browse/read resources and select resource templates; template fields are generated immediately from the selected template instead of requiring a URI to be assembled manually.
Runtime connections can be encrypted and persisted with KEX_MCP_STORAGE_KEY. For stdio servers,
executables remain opt-in through KEX_MCP_STDIO_ALLOWED_COMMANDS. MCP sessions expire after 30 minutes
of inactivity by default.
SpectraLLM 0.10.0+ serves its indexed documentation over MCP. Point the agent at it as well as at Kafka SQL Explorer, and one question can trace a record through the cluster, then find the runbook that explains it:
docker run --rm -p 8081:8081 \
-e ANTHROPIC_API_KEY=sk-ant-... -e KEX_AGENT_API_KEY=secret \
-e KAFKA_EXPLORER_URL=http://host.docker.internal:8080 \
-e SPECTRALLM_URL=http://host.docker.internal:8089 -e SPECTRA_API_KEY=... \
-e SPRING_AI_MCP_CLIENT_STREAMABLEHTTP_CONNECTIONS_SPECTRALLM_URL=http://host.docker.internal:8089 \
-e SPRING_AI_MCP_CLIENT_STREAMABLEHTTP_CONNECTIONS_SPECTRALLM_ENDPOINT=/mcp \
compagnonsdudev/kex-agent-ai:latest
The key travels in X-API-Key, and only to requests under SPECTRALLM_URL. The agent keeps
spectra_search, spectra_list_documents and spectra_preview_document; spectra_ask, which would
have SpectraLLM's own model write the answer, and the diagnostic spectra_status are denied by
default (KEX_SPECTRA_ASK_DENIED=false / KEX_SPECTRA_STATUS_DENIED=false to restore them).
The full guide.
On an agent image built after this feature is released, and with a compatible Kafka SQL Explorer MCP server connected, the agent can answer (check its advertised tools):
| Ask | MCP evidence | Interpretation |
|---|---|---|
| "Is the orders topic compliant in prod?" | kex_topic_policy_review(topic, environment) | Compares the observed settings with an operator-configured rule for that environment; NOT_CONFIGURED is not a pass. |
| "Is this consumer falling behind?" | kex_consumer_lag_trend(topic, groupId) | Needs two complete readings; the first or an expired baseline has no measured trend. |
| "Where does orders.dlq lead?" | kex_dlq_review(queueTopic) | Reads bounded Kafka evidence and reports the declared source, retry topics, monitoring reference and replay runbook. No automatic replay. |
Configure topic policies and DLQ routes on Kafka SQL Explorer, not on the agent. For a baseline that survives Explorer restarts or works across replicas, configure its shared lag history directory on a writable volume with interprocess locking. See Kafka SQL Explorer's deployment example and the agent's MCP guide. The agent distinguishes declarations from live observations and treats unavailable data as unmeasured.
| Variable | Role |
|---|---|
KEX_AGENT_API_KEY | Bearer for the agent's own API. Without it every /api/** route answers 503 — the agent refuses to serve rather than serve unauthenticated |
ANTHROPIC_API_KEY | Model provider key. Absent, the agent starts and reports itself DEGRADED rather than pretending to be healthy |
KAFKA_EXPLORER_URL | Base URL of the Kafka SQL Explorer MCP server |
EXPLORER_MCP_AUTH_TOKEN | Bearer for that MCP server, when it requires one |
KEX_AGENT_LLM_PROVIDER | anthropic (default) or openai — the latter also covers OpenRouter-compatible gateways |
KEX_MCP_STORAGE_KEY | Encrypt and persist MCP connections created from the Control Center |
KEX_MCP_STDIO_ALLOWED_COMMANDS | Explicit allowlist of executables accepted for stdio MCP servers |
SPECTRALLM_URL, SPECTRA_API_KEY | SpectraLLM's API and key, sent as X-API-Key to that URL only — see above |
KEX_AGENT_TASKS_ENABLED | true turns on durable tasks (plan, approval, execution). Off, the Tâches screen says so and names this variable |
An unreachable MCP server never blocks startup: the agent boots, says so, and keeps serving what it still can. Every setting, with its reasons.
| Endpoint | Content |
|---|---|
/actuator/health | Liveness and readiness — the only route left open, deliberately |
/actuator/prometheus | Metrics, bearer required |
/swagger-ui.html | The API, documented from the running instance |
The container exposes 8081 and runs as an unprivileged user (10001:10001).
/var/lib/kex holds everything the agent remembers outside a database: long-term facts, skills a
human approved, the operating charter, and the encrypted MCP connections created from the console.
It is declared as a volume — mount a named one over it, or those survive only as long as the
container does:
docker run --rm -p 8081:8081 -v kex_state:/var/lib/kex ... compagnonsdudev/kex-agent-ai:latest
With the shared-memory profile and a PostgreSQL datasource, memory, skills, the supervision audit
and the decision state move to the database instead — which is what you want behind a load
balancer, where a decision approved on one replica has to exist for the others. The encrypted MCP
connections stay on disk either way, so the volume is never pointless.
The Kafka SQL Explorer MCP server is read-only by default. In front of it the agent observes and recommends; it does not act. Where a capability can act, autonomy is declared per capability, an execution mode can only narrow it, and anything below the confidence floor goes back to a human. Nothing here is a default you inherit by accident: an unlisted capability is forbidden.
Three open-source projects, published under the same Docker Hub namespace, each usable on its own and wired to the others through MCP:
| Project | What it does | Image | License |
|---|---|---|---|
| Kafka SQL Explorer | Explore Kafka, query it in Flink SQL, audit it with AI — and serve it to agents as a read-only MCP server | compagnonsdudev/kafkaexplorer | AGPL-3.0-or-later |
| SpectraLLM | Turn your documents into a private, fine-tuned AI — local RAG, fine-tuning, and an MCP server over the corpus | compagnonsdudev/spectrallm | AGPL-3.0-or-later |
| Kex-anHarness (this project) | A governed AI agent that works through MCP tools — supervision, human approvals, audit trail | compagnonsdudev/kex-agent-ai | GPL-3.0-or-later |
How they fit: Kex-anHarness reads Kafka through Kafka SQL Explorer's MCP server and searches documents through SpectraLLM's; Kafka SQL Explorer can use SpectraLLM as its private LLM provider.
All three together, from published images — nothing is built:
git clone https://github.com/devdownin/Kafkaexplorer.git && cd Kafkaexplorer
docker compose -f compose/spectra-hub.yml -f compose/spectra-hub.mcp.yml \
-f compose/ecosystem.yml up -d
Ports, one plan for the three: 8080 Kafka SQL Explorer · 8081 Kex-anHarness · 8088 / 8089 SpectraLLM UI / API · 9092 Kafka. SpectraLLM's own stack keeps 80 / 8080 when it runs alone; SPECTRA_UI_PORT=8088 SPECTRA_API_PORT=8089 puts it beside the other two.
The project is now called Kex-anHarness. The
GitHub repository uses the new name. Published images
keep their existing kex-agent-ai names; deployment commands above continue to use those image names.
Content type
Image
Digest
sha256:24d8714bf…
Size
246.4 MB
Last updated
about 16 hours ago
docker pull compagnonsdudev/kex-agent-ai