Skip to content

mq9 MCP Server — Technical Design

Background

The mq9 protocol ($mq9.AI.*) is finalized. It provides the core primitives for asynchronous Agent communication: mailbox management, message send/fetch/ack (SEND/FETCH/ACK), querying (QUERY), and Agent registration and discovery (REGISTER/DISCOVER).

The protocol is NATS-style request/reply. To use mq9 today, a client must:

  • Integrate a NATS client library
  • Understand subject naming such as $mq9.AI.MSG.SEND.{mail_address}
  • Manage the semantics of group_name, deliver, force_deliver, and related fields
  • Assemble JSON request bodies by hand

For a software engineer this is straightforward — a few lines of code and you know the pattern. But an AI Agent is not a software engineer. An LLM does not inherently understand NATS, does not know the subject naming convention, and does not know what a deliver policy is. Asking an LLM to call the mq9 protocol directly requires stuffing a large amount of protocol documentation into the system prompt, with uncertain results.

MCP (Model Context Protocol) exists precisely for this problem — exposing tool capabilities to AI Agents in an LLM-friendly way. MCP is already the de facto standard for AI tool integration; Claude, Cursor, Cline, and most mainstream Agent tools support it natively.

The goal of mq9 MCP is to wrap the mq9 protocol as MCP tools so that AI Agents can use mq9's communication capabilities through the MCP protocol, without needing to understand the underlying protocol.

Position in the RobustMQ MCP Ecosystem

mq9 MCP is not a standalone project. It is one concrete protocol implementation within the broader RobustMQ MCP ecosystem.

RobustMQ is a multi-protocol message infrastructure that supports MQTT, Kafka, AMQP, NATS, and mq9. Each protocol has its own semantics and typical users:

  • MQTT: IoT devices, sensors, low-bandwidth connectivity
  • Kafka: stream processing, event sourcing, log aggregation
  • AMQP: enterprise business messaging, order workflows
  • NATS: real-time notifications, microservice communication
  • mq9: asynchronous communication between Agents

As AI Agents become ubiquitous, every protocol may face the need to be used directly by an LLM. For example:

  • IoT engineers letting an LLM control devices over MQTT
  • Data engineers letting an LLM query Kafka topic state
  • Business engineers letting an LLM process AMQP queue messages
  • Agent developers letting an LLM send messages over mq9

Each scenario requires a corresponding MCP tool set. RobustMQ's design is to bundle all protocol MCP tool sets into the broker's HTTP endpoint, so that AI Agents can access every protocol's tools through a single MCP endpoint.

mq9 is the priority for this phase. MCP tool sets for the other protocols are future work and outside the scope of this document.

Why mq9 MCP First

Several concrete driving factors:

First: mq9's target users are AI Agents, not ordinary backend services.

mq9 is designed for asynchronous communication between Agents. Most Agents are LLM-based, and the standard way for an LLM to call tools is MCP. Without a MCP interface, using mq9 from an Agent requires a workaround — writing NATS integration code directly, or relaying through a custom Tool — which defeats the purpose of mq9 serving Agents.

Second: MCP is already the de facto standard.

Claude, ChatGPT, Cursor, Cline, Hermes, OpenClaw, and other mainstream Agent tools all support MCP natively. Providing an MCP interface means mq9 integrates with all of these ecosystems at once.

Third: let mq9's capabilities be used naturally by LLMs.

An LLM does not need to know the NATS protocol or the subject naming convention. It only needs to see a few tool descriptions ("send_message: send a message to an Agent", "discover_agents: find Agents with a specific capability") and it can call them based on task requirements. This is MCP's core value.

Fourth: complete the ecosystem together with mq9-hermes-plugin and mq9-langchain adapters.

The framework adapters discussed previously (mq9-hermes, mq9-langchain, etc.) wrap mq9 as the native Tool format of each framework. MCP is a more universal entry point — any MCP-capable tool can use mq9 without a per-framework adapter.

Design Principles

Several principles to establish before implementation:

Principle 1: MCP is part of the broker's existing HTTP endpoint, not a standalone project.

RobustMQ broker already exposes HTTP service on port 8080 (admin, management, etc.). The MCP endpoint lives under a path of this HTTP server (e.g. /mcp). No new port, no new process, no new project. Starting the broker gives you MCP — zero configuration.

Principle 2: Remote MCP (Streamable HTTP) only — no stdio.

MCP has two transports: stdio and Streamable HTTP. RobustMQ only supports the latter.

Rationale:

  • The broker is a service process; it should not be launched as a child process by an AI tool (which is how stdio mode works)
  • HTTP mode natively supports remote access and multiple Agents sharing a single broker
  • Users who need stdio compatibility can bridge using the community tool mcp-remote

No multi-transport selection, no stdio bridge command. RobustMQ exposes an HTTP endpoint only.

Principle 3: MCP tools are thin wrappers, not a new protocol.

The mq9 protocol is the core. MCP tools are simply an LLM-friendly wrapping of the mq9 protocol. MCP tool semantics correspond one-to-one with mq9 protocol commands — no new concepts, no new abstraction at the protocol layer.

If a capability does not exist in the mq9 protocol, the MCP tool will not provide it. If the mq9 protocol gains a new capability, the corresponding MCP tool is added. MCP tools are not an alternative interface to mq9 — they are an LLM-friendly view of mq9.

Principle 4: Tool granularity matches how LLMs think.

LLMs handle too many parameters poorly and do not understand implicit semantics well. Therefore:

  • Each tool has a single responsibility (one tool does one thing)
  • Parameters are straightforward (no "if X is true then field Y takes effect" implicit dependencies)
  • Errors are explicit (the LLM knows what to do next)

Some fields in the mq9 protocol are engineer-friendly but not LLM-friendly (e.g. force_deliver as an implicit behavior switch). The MCP tool layer must consider how to present these so the LLM uses them correctly.

Principle 5: Sensible defaults, minimal required fields.

When an LLM calls a tool, it will omit any parameter it can. Defaults must be the most common and safest choice. For example:

  • FETCH deliver policy defaults to latest (only fetch new messages, avoids reprocessing history)
  • num_msgs defaults to 100 (sufficient, not too large)
  • TTL default should be chosen based on typical use

Principle 6: Error messages must be LLM-friendly.

An LLM reading "mailbox xxx does not exist" knows what to do (create the mailbox first). Reading "err code 4001" leaves it stuck. MCP errors must be natural-language descriptions that help the LLM decide the next action.

Principle 7: Keep the number of tools small.

Too many MCP tools pollute the LLM's context (each tool description enters the system prompt). mq9's MCP tool set should be lean — merge what can be merged, remove what can be removed. Target: no more than 10 core tools.

MCP Tool Design

Full tool list, grouped by mq9 protocol capability:

Toolmq9 ProtocolPurposeExposed to LLM
create_mailboxMAILBOX.CREATECreate a mailboxYes
send_messageMSG.SEND.{addr}Send a message to a mailboxYes
fetch_messagesMSG.FETCH.{addr}Fetch messages from a mailboxYes
ack_messageMSG.ACK.{addr}Acknowledge message processingYes
query_mailboxMSG.QUERY.{addr}Inspect mailbox (non-consuming)Yes
delete_messageMSG.DELETE.{addr}.{id}Delete a specific messageNo (avoid accidental deletion)
register_agentAGENT.REGISTERRegister an Agent to the registryYes
discover_agentsAGENT.DISCOVERFind Agents with a specific capabilityYes
unregister_agentAGENT.UNREGISTERDeregister an AgentYes
report_statusAGENT.REPORTReport Agent status (heartbeat)No (internal)

10 tools total, 8 exposed to the LLM. Details below.

Mailbox Management

create_mailbox

  • Parameters: name (mailbox name), ttl (optional, seconds)
  • Purpose: let an Agent create its own inbox or a temporary communication mailbox
  • Default behavior: idempotent (no error if the mailbox already exists)

Design note: mailbox names have strict format (lowercase, dot-separated). The description field must clearly document this so the LLM generates valid names.

Message Send / Fetch

send_message

  • Parameters: mail_address (target mailbox), payload (message body), priority (optional: normal/urgent/critical, default normal)
  • Purpose: send a message to an Agent

Design note: the MCP tool internally translates priority into the subject suffix. The LLM never sees the subject structure.

fetch_messages

  • Parameters: mail_address, group_name (use a stable identifier such as the Agent ID), max_messages (default 100), reset_to (optional, overrides default resume behavior)
  • Purpose: pull messages from your inbox

Design note: the underlying protocol has four fields — deliver, from_time, from_id, force_deliver. That's too many for an LLM. The MCP tool simplifies them into a single reset_to field:

  • Omitted: resume from the last acked position (default)
  • "earliest": reset to the beginning of the mailbox
  • "latest": skip history, only new messages
  • "time:<unix_seconds>": start from a specific timestamp, e.g. "time:1746000000"
  • "id:<msg_id>": start from a specific message, e.g. "id:42"

Merging four fields into one reset_to is much more intuitive for an LLM.

ack_message

  • Parameters: mail_address, msg_id, group_name (same value used in fetch)
  • Purpose: acknowledge message processing

Design note: the LLM should explicitly call ack after processing each message. Alternatively, a auto_ack parameter (default false) on fetch_messages can let the LLM opt in.

query_mailbox

  • Parameters: mail_address, key (optional), limit (optional), since (optional)
  • Purpose: inspect the mailbox without advancing the consumer offset

Design note: QUERY and FETCH have different semantics (QUERY does not advance the offset; FETCH does). The description must be clear — "use query_mailbox to peek, use fetch_messages to consume."

Agent Registration and Discovery

register_agent

  • Parameters: name (unique Agent name), payload (capability description — plain text or an A2A AgentCard JSON serialized as a string)
  • Purpose: register yourself in the mq9 registry

Design note: AgentCard is an upper-layer (A2A) concept. The MCP server does not parse its content. The LLM serializes the AgentCard as a string and passes it as payload.

discover_agents

  • Parameters: query (natural language or tag format: tag:xxx), limit (optional)
  • Purpose: find Agents with a specific capability

Design note: the underlying protocol has separate tag and semantic fields. The MCP tool simplifies to a single query field — the MCP layer internally decides whether it is a tag search or a semantic search (e.g. tag:translation is a tag search; natural language is a semantic search). Fewer parameters are more LLM-friendly.

unregister_agent

  • Parameters: name (the Agent name used at registration)
  • Purpose: deregister yourself

Technical Architecture

mq9 MCP is a path under the RobustMQ broker's HTTP endpoint on port 8080. Overall structure:

img

The broker already runs an HTTP server on port 8080 at startup (admin, metrics, health, etc.). The MCP endpoint (/mcp) is exposed as a path of this HTTP server, reusing the same port.

AI Agents connect via http://broker:8080/mcp. Regular clients connect via the native protocol ports (mq9 on 4332, MQTT on 1883, etc.). The two paths are parallel.

Implementation details:

Streamable HTTP transport. The RobustMQ MCP endpoint uses the Streamable HTTP transport introduced in MCP in March 2025, which superseded the older HTTP+SSE dual-endpoint design. A single HTTP endpoint supports POST (for client requests) and GET (for optional server-side streaming responses).

HTTP only, no stdio. The broker is a service process and should not be launched as a child process by an AI tool. stdio is intended for local command-line tools, not for a broker. Users whose AI tools only support stdio (uncommon — most modern tools support HTTP) can bridge using the community tool mcp-remote. This is the user's responsibility; RobustMQ does not provide a bridge.

Zero configuration. The MCP endpoint is built into the broker; no configuration is needed. It is available the moment the broker starts, on the same port 8080 as the HTTP service.

Session state. The broker maintains per-connection session state for each MCP connection:

  • The agent_id bound to this connection (used as the default group_name, etc.)
  • Known mailbox list (for better error messages)
  • Heartbeat timer

Session state is managed in the broker process and cleaned up automatically when the connection closes.

Automatic behaviors. Several behaviors that smooth the user experience:

  • Automatically create a default_inbox for the session at startup (if declared by the client during initialization)
  • Periodically send report_status (keepalive)
  • Automatically call unregister_agent on disconnect
  • Optionally auto-create a mailbox on send_message if it does not exist

These behaviors are declared by the client during the MCP initialization phase; no broker-side configuration is needed.

Error handling. The broker's MCP layer translates internal errors into LLM-friendly descriptions. For example:

  • Internal mailbox_not_found → MCP returns "Error: The mailbox 'xxx' does not exist. You need to create it first using create_mailbox."
  • Internal connection_failed → MCP returns "Error: Internal broker error. Please retry or check broker status."

Error messages include guidance on the next step, enabling the LLM to recover automatically.

Implementation

MCP is a built-in module of the RobustMQ broker, implemented in Rust, naturally reusing the broker's internal APIs with no inter-process communication.

Rust MCP SDK candidates at the time of writing:

  • rmcp (from rust-mcp-stack)
  • mcp-sdk-rs (community-maintained)

The choice depends on SDK maturity and RobustMQ's dependency preferences. The MCP protocol itself is not complex (JSON-RPC over HTTP), so a self-contained implementation is also acceptable if an SDK does not fit — the protocol layer is not a large amount of work.

Boundaries

What mq9 MCP does not do:

No protocol enhancement. MCP tools are a thin wrapper of the mq9 protocol. If a capability does not exist in the mq9 protocol, the MCP tool will not add it. Adding capabilities belongs at the mq9 protocol layer, not here.

No business logic. MCP tools do not make decisions on behalf of the Agent ("should I send this message", "should I ack this"). Those decisions are made by the Agent (LLM). MCP provides capabilities; it does not think for the user.

No protocol adaptation. MCP tools do not parse A2A, do not handle protocols outside MCP, and do not interpret message content formats. Messages are byte arrays flowing in and out unchanged.

No authentication/authorization. MCP tools do not manage permissions. If the broker has authentication enabled, the MCP tool passes it through. MCP does not implement its own permission layer.

Does not replace the mq9 protocol itself. Engineers and backend services still use the mq9 protocol directly (via NATS client). MCP is for LLMs; it is not the only way to access mq9.

No stdio. RobustMQ only supports remote MCP (Streamable HTTP). Users who need stdio can use a community bridge tool.

No standalone project. MCP is part of the broker's HTTP endpoint — not a separate pip package, sidecar process, or installation step. Installing RobustMQ includes MCP.

Open Questions

Honestly, a few questions remain unresolved:

Question 1: long-polling in fetch_messages.

When an LLM calls fetch_messages and there are no messages, should it return immediately (letting the LLM decide whether to retry) or block and wait (broker-side long poll)?

Returning immediately is simple but may cause the LLM to call repeatedly and waste resources. Blocking is unfriendly to the MCP protocol (tool calls are generally expected to return quickly).

A likely solution: default to immediate return, with an optional wait_seconds parameter for the LLM to specify a maximum wait time.

Question 2: streaming responses.

A2A tasks may produce streaming responses (SSE). When the LLM calls fetch_messages, should it receive all accumulated messages or streaming chunks?

Streamable HTTP supports server-side streaming (GET request). The exact mapping from mq9's pull model to MCP streaming needs further design.

Question 3: MCP session and Agent identity.

Conceptually each AI Agent session corresponds to a mq9 Agent identity (its own inbox, group_name). In HTTP mode, multiple connections share the same port; a session concept at the protocol layer is needed to distinguish callers.

The exact approach is TBD — possibly using MCP's built-in session mechanism, or binding an agent_id to each API token in the configuration.

Question 4: wording of tool descriptions.

Each tool's description enters the LLM's context directly; the wording affects whether the LLM uses the tool correctly. This requires extensive testing and iteration — trying with different models (Claude, GPT, Llama) to find descriptions that work best.

Short-term: use plain, direct descriptions. Long-term: refine based on user feedback.

Summary

Core conclusions for mq9 MCP:

1. It is part of the broker's HTTP endpoint, not a standalone project. No separate pip package, sidecar process, or separate port. Mounted at /mcp under the broker's existing port 8080 HTTP service.

2. Remote MCP (Streamable HTTP) only — no stdio. The broker is a service process; stdio is inappropriate. stdio users can bridge with mcp-remote.

3. Zero configuration. The MCP endpoint is available as soon as the broker starts. No [mcp] section needed in any config file.

4. It is the first protocol implementation in the RobustMQ MCP ecosystem. mqtt, kafka, amqp, and nats can each add their own MCP tool sets later, all under the same /mcp endpoint.

5. It is mq9's entry point into the AI Agent ecosystem. MCP is the de facto standard; without an MCP interface, mq9 is isolated in the LLM era.

6. It is a thin wrapper, not a new protocol. The mq9 protocol is the core; MCP tools only provide an LLM-friendly view.

7. Tool design must match how LLMs think. Single responsibility, straightforward parameters, sensible defaults, natural-language errors.

8. Tool count is kept small (10 tools, 8 exposed to the LLM). Avoids polluting the LLM's context; Agents use them correctly.

9. Rust implementation, built into the broker. Same language as the broker; reuses internal APIs directly; zero external dependencies.

10. Clear boundaries. No protocol enhancement, no business logic, no replacement of the direct interface, no replacement of other protocols, no stdio, no standalone project.

The recommended starting point is a PoC of the five most critical tools — create_mailbox, send_message, fetch_messages, ack_message, discover_agents — connected end-to-end with any HTTP-MCP-capable AI tool to validate a multi-agent demo. Once that runs, mq9's place in the AI Agent ecosystem becomes concrete. Everything else — additional tools, polish, edge cases — follows naturally.

🎉 既然都登录了 GitHub,不如顺手给我们点个 Star 吧!⭐ 你的支持是我们最大的动力 🚀