<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type="text/xsl" href="rss.xsl"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>KafkaMCP Blog</title>
        <link>https://josedab.github.io/kafkamcp/blog</link>
        <description>KafkaMCP Blog</description>
        <lastBuildDate>Fri, 01 Aug 2025 00:00:00 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <item>
            <title><![CDATA[The Schema Blindness Problem: Why Your Agent Hallucinates Field Names]]></title>
            <link>https://josedab.github.io/kafkamcp/blog/schema-blindness</link>
            <guid>https://josedab.github.io/kafkamcp/blog/schema-blindness</guid>
            <pubDate>Fri, 01 Aug 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[I watched an agent produce a message to a payments topic with a field called totalprice. The schema expected totalamount. The message was accepted — no validation, no error, no warning — serialized as JSON, and dropped into the topic. A downstream consumer tried to deserialize it, failed on the missing total_amount field, and routed it to the dead-letter queue. Thirty thousand messages later, someone noticed.]]></description>
            <content:encoded><![CDATA[<p>I watched an agent produce a message to a payments topic with a field called <code>total_price</code>. The schema expected <code>total_amount</code>. The message was accepted — no validation, no error, no warning — serialized as JSON, and dropped into the topic. A downstream consumer tried to deserialize it, failed on the missing <code>total_amount</code> field, and routed it to the dead-letter queue. Thirty thousand messages later, someone noticed.</p>
<p>The agent didn't make a mistake in reasoning. It made a mistake in vocabulary. It had no way to know that the field was called <code>total_amount</code> and not <code>total_price</code>, because nothing told it the schema. The agent was schema-blind.</p>
<p>This is the default state of every AI agent interacting with Kafka today.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-schema-blindness-actually-costs-you">What schema blindness actually costs you<a href="https://josedab.github.io/kafkamcp/blog/schema-blindness#what-schema-blindness-actually-costs-you" class="hash-link" aria-label="Direct link to What schema blindness actually costs you" title="Direct link to What schema blindness actually costs you" translate="no">​</a></h2>
<p>Schema blindness manifests in three ways, and all of them are worse than they sound.</p>
<p><strong>1. Agents hallucinate field names.</strong> Large language models are autocomplete machines. When an agent needs to produce a message to a topic called <code>orders.created</code>, it guesses what the fields should be. Sometimes it guesses correctly. Sometimes it produces <code>order_id</code> when the schema says <code>orderId</code>. Without the actual schema definition, the agent is operating on vibes.</p>
<p><strong>2. Agents can't validate what they read.</strong> When an agent consumes from a Kafka topic, it receives raw bytes. If the topic uses Avro, those bytes are Avro-encoded. If the agent doesn't know the schema, it can't decode the message. Most ad-hoc integrations skip Avro entirely and configure the consumer to treat everything as JSON — which works until someone changes the serialization format.</p>
<p><strong>3. Schema changes break agents silently.</strong> Schema evolution is the norm in production Kafka. Fields get added, defaults change, optional fields become required. If your agent doesn't know the registry exists, it can't detect that a schema changed, can't verify backward compatibility, and can't adapt its behavior. The agent is the last to know.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-concrete-damage">The concrete damage<a href="https://josedab.github.io/kafkamcp/blog/schema-blindness#the-concrete-damage" class="hash-link" aria-label="Direct link to The concrete damage" title="Direct link to The concrete damage" translate="no">​</a></h2>
<p>Consider a data quality agent that monitors a <code>user_events</code> topic. Its job: consume recent messages, validate field presence, and alert on anomalies.</p>
<p>Without schema awareness, the agent is checking fields by guessing. If the team adds a new required field — say, <code>session_id</code> — the agent doesn't know. It continues reporting everything is fine. Meanwhile, 5% of producers haven't upgraded yet and are sending messages without <code>session_id</code>, which fail downstream.</p>
<p>With schema awareness, the agent reads the schema from the Schema Registry, sees that <code>session_id</code> was added in v3 with no default value, and immediately flags: "New required field <code>session_id</code> added to <code>user_events</code> schema v3. Checking producer compliance."</p>
<p>Same agent. Same Kafka topic. Radically different outcomes based entirely on whether the agent knows the schema.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-kafkamcp-solves-this">How KafkaMCP solves this<a href="https://josedab.github.io/kafkamcp/blog/schema-blindness#how-kafkamcp-solves-this" class="hash-link" aria-label="Direct link to How KafkaMCP solves this" title="Direct link to How KafkaMCP solves this" translate="no">​</a></h2>
<p>KafkaMCP integrates schema awareness into every relevant operation, not as an add-on.</p>
<p><strong>Schema discovery.</strong> <code>kafka_list_schemas</code> returns all Schema Registry subjects with their latest version, type (AVRO/PROTOBUF/JSON), and compatibility level. <code>kafka_get_schema</code> returns the full schema definition with a generated field summary:</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"subject"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"orders.created-value"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"version"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">3</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"schema_id"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">42</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"schema_type"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"AVRO"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"compatibility_level"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"BACKWARD"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"field_summary"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"OrderCreated { order_id: string, customer_id: string, total_amount: double, currency: string (default: USD), items: array&lt;OrderItem&gt;, created_at: timestamp-millis }"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>That <code>field_summary</code> field is key. It gives the agent a single-line mental model of what the message looks like. The agent doesn't need to parse nested Avro JSON — it reads a type signature.</p>
<p><strong>Compatibility checking.</strong> Before a team adopts a proposed producer schema, an
agent can call <code>kafka_check_schema_compatibility</code> against the registry's actual
policy.</p>
<p><strong>Schema evolution workflow.</strong> The agent can retrieve the current definition,
construct a concrete candidate schema, and check that proposal before
registration.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-difference-in-practice">The difference in practice<a href="https://josedab.github.io/kafkamcp/blog/schema-blindness#the-difference-in-practice" class="hash-link" aria-label="Direct link to The difference in practice" title="Direct link to The difference in practice" translate="no">​</a></h2>
<p><strong>Without (schema-blind):</strong></p>
<ol>
<li class="">Agent samples a DLQ payload and sees plausible field names</li>
<li class="">It guesses that the payload is valid</li>
<li class="">The mismatch with the registered schema is missed</li>
<li class="">A human later compares the payload and schema manually</li>
</ol>
<p><strong>With KafkaMCP (schema-aware):</strong></p>
<ol>
<li class="">Agent calls <code>kafka_analyze_dlq</code> and <code>kafka_get_schema</code></li>
<li class="">It compares the sampled payload with the field summary</li>
<li class="">It identifies the likely producer/schema mismatch</li>
<li class="">It reports concrete evidence and a remediation path</li>
</ol>
<p>Schema blindness is the difference between agents that work in staging and agents that survive production.</p>
<p>KafkaMCP exposes schema evidence; it does not silently validate or
wire-serialize every produced payload.</p>
<hr>
<p><em>KafkaMCP is open source under the Apache 2.0 license. <a href="https://github.com/josedab/kafkamcp" target="_blank" rel="noopener noreferrer" class="">GitHub</a> · <a href="https://josedab.github.io/kafkamcp/" target="_blank" rel="noopener noreferrer" class="">Docs</a> · <a href="https://github.com/josedab/kafkamcp/discussions" target="_blank" rel="noopener noreferrer" class="">Discussions</a></em></p>]]></content:encoded>
            <category>kafka</category>
            <category>schema-registry</category>
            <category>ai-agents</category>
            <category>data-quality</category>
        </item>
        <item>
            <title><![CDATA[Connect Claude to Your Kafka Cluster in 5 Minutes]]></title>
            <link>https://josedab.github.io/kafkamcp/blog/connect-claude-to-kafka</link>
            <guid>https://josedab.github.io/kafkamcp/blog/connect-claude-to-kafka</guid>
            <pubDate>Tue, 15 Jul 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[I'm going to show you how to go from "Claude has no idea my Kafka cluster exists" to "Claude lists topics, consumes messages, and inspects consumer groups" in under five minutes. No Python scripts. No REST wrappers. No Docker Compose stack. One binary, one YAML file.]]></description>
            <content:encoded><![CDATA[<p>I'm going to show you how to go from "Claude has no idea my Kafka cluster exists" to "Claude lists topics, consumes messages, and inspects consumer groups" in under five minutes. No Python scripts. No REST wrappers. No Docker Compose stack. One binary, one YAML file.</p>
<p>Here's what we're building:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">Claude Desktop ←→ MCP (stdio) ←→ KafkaMCP ←→ Your Kafka Cluster</span><br></div></code></pre></div></div>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="prerequisites">Prerequisites<a href="https://josedab.github.io/kafkamcp/blog/connect-claude-to-kafka#prerequisites" class="hash-link" aria-label="Direct link to Prerequisites" title="Direct link to Prerequisites" translate="no">​</a></h2>
<p>You need two things:</p>
<ul>
<li class="">A running Kafka cluster (local <code>localhost:9092</code> is fine)</li>
<li class="">Go 1.22+ installed (for <code>go install</code>)</li>
</ul>
<p>If you're running Kafka locally and don't have one handy, the fastest path:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">docker</span><span class="token plain"> run </span><span class="token parameter variable" style="color:#36acaa">-d</span><span class="token plain"> </span><span class="token parameter variable" style="color:#36acaa">--name</span><span class="token plain"> kafka </span><span class="token parameter variable" style="color:#36acaa">-p</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">9092</span><span class="token plain">:9092 </span><span class="token punctuation" style="color:#393A34">\</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token parameter variable" style="color:#36acaa">-e</span><span class="token plain"> </span><span class="token assign-left variable" style="color:#36acaa">KAFKA_CFG_NODE_ID</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">0</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">\</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token parameter variable" style="color:#36acaa">-e</span><span class="token plain"> </span><span class="token assign-left variable" style="color:#36acaa">KAFKA_CFG_PROCESS_ROLES</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">controller,broker </span><span class="token punctuation" style="color:#393A34">\</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token parameter variable" style="color:#36acaa">-e</span><span class="token plain"> </span><span class="token assign-left variable" style="color:#36acaa">KAFKA_CFG_CONTROLLER_QUORUM_VOTERS</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">0</span><span class="token plain">@localhost:9093 </span><span class="token punctuation" style="color:#393A34">\</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token parameter variable" style="color:#36acaa">-e</span><span class="token plain"> </span><span class="token assign-left variable" style="color:#36acaa">KAFKA_CFG_LISTENERS</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">PLAINTEXT://:9092,CONTROLLER://:9093 </span><span class="token punctuation" style="color:#393A34">\</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token parameter variable" style="color:#36acaa">-e</span><span class="token plain"> </span><span class="token assign-left variable" style="color:#36acaa">KAFKA_CFG_ADVERTISED_LISTENERS</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">PLAINTEXT://localhost:9092 </span><span class="token punctuation" style="color:#393A34">\</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token parameter variable" style="color:#36acaa">-e</span><span class="token plain"> </span><span class="token assign-left variable" style="color:#36acaa">KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT </span><span class="token punctuation" style="color:#393A34">\</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token parameter variable" style="color:#36acaa">-e</span><span class="token plain"> </span><span class="token assign-left variable" style="color:#36acaa">KAFKA_CFG_CONTROLLER_LISTENER_NAMES</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">CONTROLLER </span><span class="token punctuation" style="color:#393A34">\</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  bitnami/kafka:3.7</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="minute-1-install-kafkamcp">Minute 1: Install KafkaMCP<a href="https://josedab.github.io/kafkamcp/blog/connect-claude-to-kafka#minute-1-install-kafkamcp" class="hash-link" aria-label="Direct link to Minute 1: Install KafkaMCP" title="Direct link to Minute 1: Install KafkaMCP" translate="no">​</a></h2>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">go </span><span class="token function" style="color:#d73a49">install</span><span class="token plain"> github.com/josedab/kafkamcp/cmd/kafkamcp@latest</span><br></div></code></pre></div></div>
<p>Verify it's working:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">kafkamcp version</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># kafkamcp 0.1.0</span><br></div></code></pre></div></div>
<p>That's it. Single binary, no dependencies.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="minute-2-write-the-config">Minute 2: Write the config<a href="https://josedab.github.io/kafkamcp/blog/connect-claude-to-kafka#minute-2-write-the-config" class="hash-link" aria-label="Direct link to Minute 2: Write the config" title="Direct link to Minute 2: Write the config" translate="no">​</a></h2>
<p>Create a file called <code>kafkamcp.yaml</code> in a location you'll remember (I use <code>~/.config/kafkamcp/kafkamcp.yaml</code>):</p>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token key atrule" style="color:#00a4db">server</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">transport</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> stdio</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">log_level</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> info</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">clusters</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> local</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">bootstrap_servers</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"localhost:9092"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">security_protocol</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> PLAINTEXT</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">default</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean important" style="color:#36acaa">true</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">audit</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">enabled</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean important" style="color:#36acaa">true</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">max_entries</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">10000</span><br></div></code></pre></div></div>
<p>Eight lines of meaningful config. That's the entire setup.</p>
<p>Validate it:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">kafkamcp validate </span><span class="token parameter variable" style="color:#36acaa">--config</span><span class="token plain"> ~/.config/kafkamcp/kafkamcp.yaml</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># Configuration is valid.</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="using-confluent-cloud">Using Confluent Cloud?<a href="https://josedab.github.io/kafkamcp/blog/connect-claude-to-kafka#using-confluent-cloud" class="hash-link" aria-label="Direct link to Using Confluent Cloud?" title="Direct link to Using Confluent Cloud?" translate="no">​</a></h3>
<p>Replace the cluster block:</p>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token key atrule" style="color:#00a4db">clusters</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> confluent</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">bootstrap_servers</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"${CONFLUENT_BOOTSTRAP_SERVERS}"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">security_protocol</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> SASL_SSL</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">sasl_mechanism</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> PLAIN</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">sasl_username</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"${CONFLUENT_API_KEY}"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">sasl_password</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"${CONFLUENT_API_SECRET}"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">schema_registry</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">url</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"${CONFLUENT_SR_URL}"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">auth</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">username</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"${CONFLUENT_SR_API_KEY}"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">password</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"${CONFLUENT_SR_API_SECRET}"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">default</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean important" style="color:#36acaa">true</span><br></div></code></pre></div></div>
<p>KafkaMCP expands <code>${VAR}</code> and <code>${VAR:-default}</code> patterns from your environment. Set the variables, run <code>kafkamcp validate</code>, and you're done.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="minute-3-connect-to-claude-desktop">Minute 3: Connect to Claude Desktop<a href="https://josedab.github.io/kafkamcp/blog/connect-claude-to-kafka#minute-3-connect-to-claude-desktop" class="hash-link" aria-label="Direct link to Minute 3: Connect to Claude Desktop" title="Direct link to Minute 3: Connect to Claude Desktop" translate="no">​</a></h2>
<p>Open your Claude Desktop configuration file:</p>
<ul>
<li class=""><strong>macOS:</strong> <code>~/Library/Application Support/Claude/claude_desktop_config.json</code></li>
<li class=""><strong>Windows:</strong> <code>%APPDATA%\Claude\claude_desktop_config.json</code></li>
</ul>
<p>Add the KafkaMCP entry:</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"mcpServers"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"kafkamcp"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"command"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"kafkamcp"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"args"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">"--config"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"/Users/you/.config/kafkamcp/kafkamcp.yaml"</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>Use the full path to your config file. Restart Claude Desktop.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="minute-4-verify-the-connection">Minute 4: Verify the connection<a href="https://josedab.github.io/kafkamcp/blog/connect-claude-to-kafka#minute-4-verify-the-connection" class="hash-link" aria-label="Direct link to Minute 4: Verify the connection" title="Direct link to Minute 4: Verify the connection" translate="no">​</a></h2>
<p>In Claude, you should see the MCP server indicator showing KafkaMCP is connected. If it doesn't appear, check Claude's MCP logs (Help → MCP Logs) for connection errors.</p>
<p>Now ask Claude:</p>
<blockquote>
<p>List all Kafka topics in my cluster</p>
</blockquote>
<p>Claude calls <code>kafka_list_topics</code> and returns your topics with partition counts, replication factors, and estimated message counts.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="minute-5-do-something-useful">Minute 5: Do something useful<a href="https://josedab.github.io/kafkamcp/blog/connect-claude-to-kafka#minute-5-do-something-useful" class="hash-link" aria-label="Direct link to Minute 5: Do something useful" title="Direct link to Minute 5: Do something useful" translate="no">​</a></h2>
<p><strong>Read recent messages:</strong></p>
<blockquote>
<p>Show me the last 5 messages from orders.created</p>
</blockquote>
<p><strong>Inspect a consumer group:</strong></p>
<blockquote>
<p>Describe the consumer group order-processor and show me the lag per partition</p>
</blockquote>
<p><strong>Produce a message:</strong></p>
<blockquote>
<p>Publish a test message to the test-events topic with key "test-1" and value <code>{"event": "hello", "source": "claude"}</code></p>
</blockquote>
<p><strong>Search messages:</strong></p>
<blockquote>
<p>Search for messages in orders.created where the value contains "refund"</p>
</blockquote>
<p>That's five minutes. Your AI agent now has native, authenticated, schema-aware access to your Kafka cluster — and you didn't write a single line of integration code.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="adding-access-control">Adding access control<a href="https://josedab.github.io/kafkamcp/blog/connect-claude-to-kafka#adding-access-control" class="hash-link" aria-label="Direct link to Adding access control" title="Direct link to Adding access control" translate="no">​</a></h2>
<p>If you don't want Claude (or other agents) to have full access, add a policy:</p>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token key atrule" style="color:#00a4db">policies</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">default_deny</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean important" style="color:#36acaa">true</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">agents</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">id</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"anonymous"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">topics</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">pattern</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"orders.*"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token key atrule" style="color:#00a4db">permissions</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">read</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">pattern</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"test-*"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token key atrule" style="color:#00a4db">permissions</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">read</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> write</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">consumer_groups</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">permissions</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">describe</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">schemas</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">permissions</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">read</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">rate_limit</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token key atrule" style="color:#00a4db">requests_per_minute</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">60</span><br></div></code></pre></div></div>
<p>Now Claude can read from <code>orders.*</code> topics and read/write <code>test-*</code> topics, but nothing else. Rate-limited to 60 requests per minute.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="next-steps">Next steps<a href="https://josedab.github.io/kafkamcp/blog/connect-claude-to-kafka#next-steps" class="hash-link" aria-label="Direct link to Next steps" title="Direct link to Next steps" translate="no">​</a></h2>
<ul>
<li class=""><a href="https://josedab.github.io/kafkamcp/docs/guides/access-control" target="_blank" rel="noopener noreferrer" class="">Access Control Guide</a> — restrict what agents can do</li>
<li class=""><a href="https://josedab.github.io/kafkamcp/docs/guides/multi-cluster" target="_blank" rel="noopener noreferrer" class="">Multi-Cluster Setup</a> — connect to multiple Kafka clusters</li>
<li class=""><a href="https://josedab.github.io/kafkamcp/docs/api-reference/tools" target="_blank" rel="noopener noreferrer" class="">API Reference</a> — full tool catalog</li>
</ul>
<hr>
<p><em>KafkaMCP is open source under the Apache 2.0 license. <a href="https://github.com/josedab/kafkamcp" target="_blank" rel="noopener noreferrer" class="">GitHub</a> · <a href="https://josedab.github.io/kafkamcp/" target="_blank" rel="noopener noreferrer" class="">Docs</a> · <a href="https://github.com/josedab/kafkamcp/discussions" target="_blank" rel="noopener noreferrer" class="">Discussions</a></em></p>]]></content:encoded>
            <category>kafka</category>
            <category>claude</category>
            <category>mcp</category>
            <category>tutorial</category>
            <category>getting-started</category>
        </item>
        <item>
            <title><![CDATA[Your AI Agents Are Blind to Kafka — And That's Costing You Weeks]]></title>
            <link>https://josedab.github.io/kafkamcp/blog/agents-blind-to-kafka</link>
            <guid>https://josedab.github.io/kafkamcp/blog/agents-blind-to-kafka</guid>
            <pubDate>Tue, 01 Jul 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[Last month I watched a senior data engineer at a Series C fintech spend eleven days building a pipeline so their incident response agent could read from a single Kafka topic.]]></description>
            <content:encoded><![CDATA[<p>Last month I watched a senior data engineer at a Series C fintech spend eleven days building a pipeline so their incident response agent could read from a single Kafka topic.</p>
<p>Eleven days. One topic.</p>
<p>She wrote a Python consumer that subscribed to <code>orders.dlq</code>, deserialized Avro messages using a hand-managed schema cache, dumped the results into a REST endpoint, wrote an MCP tool definition that called the REST endpoint, added error handling for when the consumer fell behind, and then spent two more days debugging a memory leak in the consumer process. When she was done, the agent could sample dead-letter queue messages. Read-only. No schema awareness. No consumer group inspection. And when the team wanted the agent to also read from <code>payments.failed</code>, the whole process started over.</p>
<p>This is the default experience for every team that wants AI agents to interact with Kafka. It's a hidden tax that compounds with every new topic and every new agent, and it's entirely unnecessary.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-three-layer-wrapper-pattern">The three-layer wrapper pattern<a href="https://josedab.github.io/kafkamcp/blog/agents-blind-to-kafka#the-three-layer-wrapper-pattern" class="hash-link" aria-label="Direct link to The three-layer wrapper pattern" title="Direct link to The three-layer wrapper pattern" translate="no">​</a></h2>
<p>Here's what the integration looks like for most teams today:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">1. Human writes Python/Go consumer → dumps to file or REST API</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">2. Human writes MCP tool wrapper around the REST API  </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">3. Agent gets stale, batch-mode, schema-blind access to one topic</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">4. Repeat for every additional topic</span><br></div></code></pre></div></div>
<p>I've seen this pattern at companies running anywhere from 50 to 2,000+ Kafka topics. Each integration takes non-trivial engineering time, produces multiple layers of bespoke code, and delivers an agent that can read but not write, can't discover new topics, has zero understanding of message schemas, and requires its own monitoring and on-call coverage independent of Kafka itself.</p>
<p>Multiply that by the 5-15 agents a typical platform team deploys, and you're looking at a full-time headcount consumed by wrapper maintenance.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-existing-alternatives-dont-solve-this">Why existing alternatives don't solve this<a href="https://josedab.github.io/kafkamcp/blog/agents-blind-to-kafka#why-existing-alternatives-dont-solve-this" class="hash-link" aria-label="Direct link to Why existing alternatives don't solve this" title="Direct link to Why existing alternatives don't solve this" translate="no">​</a></h2>
<p>The obvious question: why not use Confluent's REST Proxy, or ksqlDB, or embed a Kafka client directly in the agent?</p>
<p><strong>Kafka REST Proxy</strong> is a fine HTTP adapter. I've operated it at scale. But it was designed for human-built services, not AI agents. It's not MCP-compatible, so you still need an MCP tool wrapper. It has no schema introspection — your agent receives raw bytes. It has no topic discovery — the agent must be told which topics exist. And every new agent needs its own integration, because REST Proxy has no concept of per-agent access control.</p>
<p><strong>ksqlDB</strong> is a stream processing engine. Using it for ad-hoc agent reads is like using a forklift to pick up a pen. It requires a persistent deployment, ongoing operational investment, and still doesn't speak MCP. It solves a different problem.</p>
<p><strong>Embedding a Kafka client directly</strong> (kafka-python, librdkafka) creates a tight coupling between the agent framework and Kafka internals. Every agent now needs to manage connections, handle rebalances, negotiate SASL credentials, and deserialize wire-format schemas. This violates separation of concerns and turns every agent developer into a Kafka specialist.</p>
<p><strong>LangChain's Kafka integration</strong> exists, but it's a community-contributed wrapper with 5 basic tools, no schema support, no consumer group management, and maintenance that has stalled. It's a starting point, not a solution.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-gap-that-shouldnt-exist">The gap that shouldn't exist<a href="https://josedab.github.io/kafkamcp/blog/agents-blind-to-kafka#the-gap-that-shouldnt-exist" class="hash-link" aria-label="Direct link to The gap that shouldn't exist" title="Direct link to The gap that shouldn't exist" translate="no">​</a></h2>
<p>Apache Kafka processes trillions of messages daily and is used across a broad range of production deployments. MCP adoption is growing rapidly. These are two enormous, converging ecosystems.</p>
<p>Existing open-source Kafka MCP servers provide basic produce/consume with a handful of tools. No schema awareness. No access control. No consumer group operations. No multi-cluster support. Most are starter projects suitable for experimentation, not production governance.</p>
<p>The result: data engineering teams at companies operating hundreds of Kafka topics are individually building the same three-layer wrapper, with the same blind spots.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-a-real-solution-looks-like">What a real solution looks like<a href="https://josedab.github.io/kafkamcp/blog/agents-blind-to-kafka#what-a-real-solution-looks-like" class="hash-link" aria-label="Direct link to What a real solution looks like" title="Direct link to What a real solution looks like" translate="no">​</a></h2>
<p>I've been operating Kafka at scale for years — 47-broker clusters, controller failovers, ZooKeeper-to-KRaft migrations, thousands of topics across multiple clusters. I built KafkaMCP to be the bridge I wished existed.</p>
<p>It's a single Go binary. You write 8 lines of YAML, point it at your Kafka cluster, and your agent gets MCP tools covering:</p>
<ul>
<li class=""><strong>Discovery:</strong> list topics and schemas, inspect consumer groups, and retrieve cluster metadata</li>
<li class=""><strong>Data access:</strong> consume with offset/timestamp/latest positioning, produce with delivery confirmation, search by key/header/value/time range</li>
<li class=""><strong>Operations:</strong> create/alter/delete topics, reset consumer group offsets, analyze dead-letter queues</li>
<li class=""><strong>Governance:</strong> schema compatibility checks, approvals, policy evaluation, and live Kafka ACL reconciliation</li>
</ul>
<p>Every tool call goes through a middleware chain: verified identity → rate
limiting → per-agent policy enforcement → execution → audit logging →
Prometheus metrics. Guarded packs require production-safe policy and approval
configuration.</p>
<p>It's Apache 2.0 licensed, pure Go (no CGO, no JVM, no native deps), and runs on Linux, macOS, and Windows.</p>
<hr>
<p><em>KafkaMCP is open source under the Apache 2.0 license. <a href="https://github.com/josedab/kafkamcp" target="_blank" rel="noopener noreferrer" class="">GitHub repository</a> · <a href="https://josedab.github.io/kafkamcp/" target="_blank" rel="noopener noreferrer" class="">Documentation</a> · <a href="https://github.com/josedab/kafkamcp/discussions" target="_blank" rel="noopener noreferrer" class="">Discussions</a></em></p>]]></content:encoded>
            <category>kafka</category>
            <category>mcp</category>
            <category>ai-agents</category>
            <category>data-engineering</category>
        </item>
    </channel>
</rss>