Event server
A Kafka bridge over MCP: publish messages to a topic, consume them back through a durable consumer group, and manage topics on Confluent Cloud.
Publish and consume Kafka messages over MCP. Produce to a topic, poll it back through a durable consumer group, and manage topics on Confluent Cloud.
Wire an agent into your event stream. Call event_publish to emit a record to a Kafka topic, then event_consume from a durable group so a later call picks up only the new messages. Confluent Cloud credentials are all it needs.
Connect
Point your MCP client at the event route:
Every request must carry an X-API-Key header. Sign in to create one.
https://go-mcp-server-latest.onrender.com/event/mcpDrop this into your client’s config and swap in the key you mint on the Keys page:
{
"mcpServers": {
"event": {
"type": "http",
"url": "https://go-mcp-server-latest.onrender.com/event/mcp",
"headers": {
"X-API-Key": "<your-api-key>"
}
}
}
}Every request carries your X-API-Key header — mint one on the Keys page. That single key admits the whole server.
Mounts even without credentials: every tool reports the config problem instead of failing the server. Call event_capabilities first to check status. event_publish and event_consume fall back to KAFKA_DEFAULT_TOPIC when no topic is given. Topic create and delete stay disabled until KAFKA_ALLOW_TOPIC_ADMIN=true.
Tools
event_capabilitiestoolReport this event server's configuration and readiness: whether a broker and Confluent Cloud credentials are set, the default consumer group and topic, whether topic admin is enabled, and the tool catalogue. Call this first if other tools error.
event_publishtoolPublish one message to a Kafka topic and return the partition and offset the record was written to.
valuerequired- stringThe message payload as a string. JSON is fine.
topic- string · default KAFKA_DEFAULT_TOPICTopic to publish to.
key- stringOptional partition key. The same key always routes to the same partition.
headers- objectOptional string headers attached to the record.
event_consumetoolRead up to max messages from a Kafka topic, returning within timeout_ms. This is a bounded poll, not a live stream, so call it again to read more.
topic- string · default KAFKA_DEFAULT_TOPICTopic to read.
from- string · default groupWhere to read from: group (durable offsets that advance across calls), earliest, or latest.
group- string · default KAFKA_CONSUMER_GROUPConsumer group. Only used when from is group.
max- int · default 10Max messages to return, capped at 100.
timeout_ms- int · default 5000Overall poll budget in milliseconds.
event_topicstoolList the topics on the Kafka cluster with their partition counts. Read-only.
event_create_topictoolCreate a Kafka topic. Mutating; requires KAFKA_ALLOW_TOPIC_ADMIN=true. Confluent Cloud requires a replication factor of 3.
topicrequired- stringThe topic name to create.
partitions- int · default 1Partition count.
replication_factor- int · default 3Replication factor. Confluent Cloud requires 3.
event_delete_topictoolDelete a Kafka topic. Mutating; requires KAFKA_ALLOW_TOPIC_ADMIN=true.
topicrequired- stringThe topic name to delete.
Worked example: a task queue for agents
The two tools above compose into something more useful than message plumbing: a durable inbox for an agent. A publisher — CI, a cron job, another agent, or you — drops a task on the topic. An agent polls the topic and carries the task out. Neither side has to be running at the same time, which is the whole point of putting a log between them.
- 1Publish a taskEmit a structured envelope rather than a sentence. Anything the worker needs to act without asking a follow-up question belongs in the payload: what to do, why, and what is still undecided.
- 2Poll with a consumer group
from: "group"commits offsets as it reads, so each task is handed out once and a restarted agent resumes where it left off.earliestandlatestpeek without disturbing the group — useful for debugging, wrong for work. - 3Act, then poll again
event_consumeis a bounded poll, not a live stream. An agent loop is: poll → do the work → poll again. There is no socket to keep open and nothing to reconnect.
{
"type": "task",
"id": "auth-x-api-key-all-namespaces",
"title": "Require X-API-Key auth verification on every MCP namespace",
"priority": "high",
"source": "go-mcp-server audit",
"summary": "Only the memory namespace verifies X-API-Key, and it does so per-tool inside handlers. skills, event, gsc and producthunt accept unauthenticated calls. Enforce the key centrally so every server verifies auth before executing any action.",
"findings": [
{
"namespace": "memory",
"key_required": true
},
{
"namespace": "event",
"key_required": false,
"detail": "Kafka publish reachable unauthenticated."
}
],
"plan": [
{
"step": 1,
"action": "Add RequireAPIKey middleware validating X-API-Key against the api_keys table."
},
{
"step": 2,
"action": "Add it to the Chain in internal/mcpx/registry.go so it covers every namespace."
}
],
"open_questions": [
"Should /healthz remain unauthenticated?"
]
}event_publish({
topic: "go-mcp-events",
key: "auth-x-api-key", // same key -> same partition -> ordered
headers: {
"event-type": "task.created",
"domain": "security",
"producer": "ci-audit"
},
value: JSON.stringify(task) // value is a string; stringify your JSON
})
// -> { "topic": "go-mcp-events", "partition": 3, "offset": 1 }event_consume({
topic: "go-mcp-events",
from: "group", // durable: offsets advance across calls
max: 20,
timeout_ms: 20000
})
// -> { "count": 1, "group": "go-mcp-server", "messages": [ ... ] }
// Call it again and count is 0 — the offset was committed.That envelope is the real message that drove this server’s authentication change. It was published to go-mcp-events, an agent polling the topic picked it up, verified every claim against the source, asked the two open questions, and shipped the RequireAPIKey middleware described on the Authentication page. The audit and the fix were connected by nothing but this topic.
Anyone with produce access can write to the topic, so a message is a request, not a command from a trusted operator. A worker should verify a payload’s claims before acting on them, and stop and escalate rather than execute anything destructive, irreversible, or outward-facing on a message’s say-so. Partition keys and headers are equally caller-supplied — never route privilege off them.