KIP design + a Python conformance reference for the security control model.
What is specified, what is proven in code, and what is still future work.
Python stdio / in-memory reference · Java is the KIP production target · Vaquar Khan
One rule: describe the KIP as the full design; describe this repo as a control-model proof. Never claim the reference has a KIP capability listed as a gap.
| Area | This reference (proven) | KIP / Java track |
|---|---|---|
| Transport | stdio only | stdio + Streamable HTTP + OAuth |
| Backend | In-memory Kafka | Real Admin / Producer / Consumer |
| Tools / resources | 13 tools, subset of resources | ~30+ tools, ~20 resources |
| Security pipeline | 9-step fail-closed, 302/302 tests | same model in production Java |
| EOS / fencing / distributed rate / durable audit | not implemented | specified in KIP |
Slides marked KIP design are aspirational. Slides marked reference match code in this repo.
Giving AI agents safe, governed access to Kafka.
The Model Context Protocol is an open standard (announced by Anthropic, Nov 2024; donated to the Linux Foundation Agentic AI Foundation, Dec 2025). It uses JSON-RPC 2.0 in a client, host, server architecture.
Functions the model executes. State changing actions.
Read only context and data for the model.
Templated workflows (future phase).
MCP solves the N×M integration problem: one standard interface instead of a custom connector per (data source, AI tool) pair. Already adopted across Claude, GitHub Copilot, and Google ADK.
Motivating question: should Apache Kafka provide a first-party MCP server so agents can operate clusters through a standard protocol? The KIP answers yes.
Wiring a Kafka cluster to an unvetted third-party MCP server means trusting a stranger with the control plane (ACLs, broker configs, reassignment) and the data plane.
Named, demonstrated attack classes: tool poisoning, rug-pulls, confused-deputy, token pass-through, indirect prompt injection.
Open-source Kafka MCP servers already exist. The KIP aims to close shared gaps; the Python reference proves the control model, not every KIP tool yet.
| Gap in existing servers | KIP-1318 (design) |
|---|---|
| Weak or missing MCP-side guardrails | 9-step fail-closed pipeline (proven in reference) |
| No ACL management | ACL tools in KIP; reference has in-memory create_acls only |
| No transactional produce (EOS) | KIP specifies produce_transactional - not in reference |
| Cloud / REST coupling | Vanilla Kafka clients (Java track) |
Shipped default: read/consume only. Extra KIP tools (delete_records, Connect, EOS, …) are design-only here.
kafka://topics, /{name}, /{name}/offsetskafka://groups, /{id}, /offsets, /lagkafka://cluster, audit/recent, healthKIP: standalone process wrapping real Admin/Producer/Consumer. Reference: same pipeline shape over stdio + InMemoryKafka.
Modules use per-process circuit breakers. Connect / real brokers are Java-track work.
Honest by design: taint/DLP are best-effort; broker ACLs remain the load-bearing control.
First denial wins. No execute-then-check paths. Around execute: input validation (-32046), rogue-agent quarantine (-32047), egress DLP on produce (-32045), sensitive-topic gating, post-execute DLP scrub, and audit. Identity comes only from the transport, never from tool arguments.
agent.*)Reference config defaults match KIP secure-by-default: read/consume allow-list. Mutate/destructive tools are opt-in. Policy is an in-process hook (no OPA HTTP client here).
| Guardrail | Property | Default (reference) |
|---|---|---|
| Tool allow / deny + readonly | tools_allowed · tools_denied · readonly | read/consume · none · false |
| Namespace scope | allowed_topic_prefixes · allowed_group_prefixes | * (tighten!) |
| Taint / IFC | taint_guard_enabled · ifc_strict | true · false |
| Approval + dry-run | approval_required_tools · dryrun_tools | delete_topic, delete_consumer_group, create_acls · none |
| Policy engine | in-process callable (KIP: optional URL) | none (fail-closed) |
| Bounded output | hard_max_records · hard_max_bytes · max_output_bytes | 100 · 1 MiB · 256 KiB |
| DLP + secret masking | dlp_mode · dlp_block_categories | redact · key/JWT/AWS |
| Rogue-agent kill-switch | max_destructive_per_minute | 10 |
| Resilience + identity | circuit_breaker_enabled · identity_propagation | true · false |
| Bearer audience/issuer | oauth_expected_audience · .issuer | none (no OAuth server) |
| OWASP risk | KIP-1318 control | Code |
|---|---|---|
| LLM01 Prompt Injection | Taint guard / IFC, sensitive-topic gating on consume | -32040 |
| LLM02 Sensitive Information Disclosure | DLP redact/block, config-secret masking, bounded output | -32045 |
| LLM03 Supply Chain | Prefer first-party / reviewed MCP; reference is stdlib-only core (Java track: zero new core deps) | - |
| LLM05 Improper Output Handling | Post-execute DLP scrub, MCP content + isError wrapping | - |
| LLM06 Excessive Agency | Allow/deny + readonly, prefix scope, approval gate, dry-run, kill-switch | -32041 / -32042 / -32047 |
| LLM10 Unbounded Consumption | Rate limits, circuit breakers, hard record/byte ceilings | -32029 / -32043 |
Defenses also target named MCP attack classes, shown next.
| Attack class | What it does | Guardrail that stops it |
|---|---|---|
| Tool poisoning / rug-pull | Hidden instructions in tool metadata that change after approval | Pinned tool schemas, fixed protocolVersion, approval bound to tool + resource + principal, audit |
| Confused-deputy / token pass-through | Caller rides the server's privileges or forwards a stolen token | Identity only from transport (_identity args rejected), OAuth audience/issuer validation |
| Indirect prompt injection | Consumed record text tries to drive a destructive tool | Taint / IFC marks the session untrusted, blocks mutate/destructive (-32040), sensitive-topic gating |
| Context flooding | Oversized responses exhaust the model's context | Bounded reads: hard record + byte ceilings, cumulative output cap |
| Rogue / runaway agent | Burst of destructive calls | Per-identity kill-switch + quarantine (-32047), rate limits, circuit breakers |
First denial wins at every step; broker ACLs remain the load-bearing control underneath.
Every security control, run as a pass/fail test.
A declarative, multi-language test tool: one mcp-suite.yaml is compiled onto the mcp-test-harness engine and run from Python or a native runner (JUnit5, Jest, xUnit, Go). It calls the server over MCP JSON-RPC and checks results, schemas, latency, and exact error codes. Below is the live HTML dashboard from this server's run.
| Security control | Test (negative unless noted) | Expected | Result |
|---|---|---|---|
| Resource scope (prefix allow-list) | create prod-payments | deny -32041 | PASS |
| Approval gate (destructive) | delete_topic without token | deny -32042 | PASS |
| Approval gate (ACL admin) | create_acls without token | deny -32042 | PASS |
| Domain error correctness | describe / produce unknown topic | UnknownTopic | PASS |
| MCP content shape + schema (positive) | describe_cluster, list_topics, create_topic | content + schema OK | PASS |
A denial that returns the correct error code is the feature. The suite verifies the code, not just that "something threw." Broader coverage: the repo's own conformance suite (302 checks) exercises every control.
Validated with a declarative, multi-language MCP test suite.
mcp-suite run → 9 / 9 passed in ~0.5s, against the native server (no shim).
JUnit5 adapter → runSuite 9, call("create") 3, call("approval") 2. All green.
This codebase is a Python reference implementation. It is not Java and not the official Kafka MCP server.
tools/mcp-server).KIP-1318 security control model · Python conformance reference
KIP-1318 · KAFKA-20436 · github.com/vaquarkhan/kafka-mcp-enterprise-server