What mq9 SDK Is Trying to Do
We recently got clarity on the design of the mq9 SDK. This post walks through the whole thing: what problem it solves, where it fits, how it works, and how to use it.
Starting from a Developer's Perspective
Say you're an Agent developer. You want to write a translation Agent that other Agents can call.
With the current official A2A protocol implementation, your code looks roughly like this:
from a2a.server.agent_execution import AgentExecutor, RequestContext
from a2a.server.events import EventQueue
from a2a.server.apps import A2AStarletteApplication
from a2a.server.request_handlers import DefaultRequestHandler
from a2a.server.tasks import InMemoryTaskStore
from a2a.types import (
AgentCard, AgentSkill, AgentCapabilities, AgentAuthentication
)
from a2a.utils import new_agent_text_message
import uvicorn
class TranslatorAgent(AgentExecutor):
async def execute(self, context, event_queue):
text = context.message.parts[0].text
result = await llm.translate(text)
await event_queue.enqueue_event(
new_agent_text_message(result)
)
async def cancel(self, context, event_queue):
pass
skill = AgentSkill(
id="translate",
name="Translation",
description="Translate between Chinese and English",
tags=["translation"],
examples=["translate to Chinese", "翻译成英文"]
)
agent_card = AgentCard(
name="Translator",
description="A translator agent",
url="http://localhost:9999",
version="1.0",
defaultInputModes=["text"],
defaultOutputModes=["text"],
capabilities=AgentCapabilities(streaming=True),
authentication=AgentAuthentication(schemes=["public"]),
skills=[skill]
)
handler = DefaultRequestHandler(
agent_executor=TranslatorAgent(),
task_store=InMemoryTaskStore()
)
app_builder = A2AStarletteApplication(
agent_card=agent_card,
http_handler=handler
)
uvicorn.run(app_builder.build(), host="0.0.0.0", port=9999)That's over 60 lines. Of everything this code does, only the llm.translate(text) call is business logic. Everything else is protocol and transport glue.
And this is just the synchronous, single-machine case. If the caller's network blips while calling your Agent, or your Agent process happens to be restarting, the call fails. A2A's default HTTP transport requires both sides to be online at the same time.
What mq9 SDK is trying to do is simple: turn those 60 lines into 15, and make Agent communication work even when both sides aren't online simultaneously.
The Goal
The mq9 SDK's goal is to be a genuinely useful foundational component for Agent communication.
"Genuinely useful" isn't an adjective — it's a concrete developer experience. We narrow it down to three things.
Light: minimum code to integrate. A 60-line A2A Agent becomes 15 lines. Developers write business logic; the SDK handles the rest. Install one package, start one broker, run one example — complete end-to-end in under 30 minutes.
Solid: foundational components can't drag down the business when things go wrong. The broker doesn't lose messages. The SDK doesn't block the main thread. Protocol upgrades are backward-compatible. Error messages let people debug themselves. Foundation engineers hold stability to a much higher standard than application engineers. One production incident is enough to make people abandon a dependency.
Open: being easy to use can't come at the cost of being closed. An A2A Agent written on mq9 must be callable by a pure a2a-sdk client. The mq9 registry must be interoperable with A2A standards. The mq9 broker must coexist with existing Kafka/RabbitMQ deployments. Closed convenience is fake convenience.
These three together — Light, Solid, Open — are our concrete definition of "a genuinely useful foundational component." The opposite is also clear: a heavy, closed "all-in-one suite" is not what we're building; a "prototype that runs but isn't stable" isn't either.
This goal is more controllable than "become the de facto standard." De facto standards are outcomes, decided by the market; a useful foundational component is a cause, determined by the quality of daily work. Get the usefulness solid and the standard follows. Chase the standard directly and the usefulness suffers.
Where It Fits
Before settling on positioning, look at what the A2A ecosystem is currently doing. Scanning the dozens of projects collected in awesome-a2a, the landscape looks like this:
| Area | Project count | Density |
|---|---|---|
| Official SDK (5 languages) + community SDKs | Dozens | Extremely crowded |
| Framework integrations (LangGraph, CrewAI, AG2, etc.) | All major frameworks | Crowded |
| Platform / Runtime (Bindu, Aira, Inai, etc.) | 5–6 in parallel | Crowded, all doing "all-in-one" |
| Agent Discovery / Registry | A few incomplete attempts | Vacuum |
| Reliable async transport infrastructure | Nobody working on it | Vacuum |
| Monitoring / Tracing adapters | Nobody working on it | Vacuum |
| Protocol-agnostic communication pipe | Nobody working on it | Vacuum |
The awesome-a2a README itself explicitly writes "Community contributions welcome" in the "Tools & Utilities" section, actively recruiting work on registries, tracing adapters, and similar directions. The ecosystem itself has noticed these infrastructure gaps aren't being filled.
mq9 doesn't enter the SDK, framework, or platform Runtime space — all three are crowded. It targets the vacuum: transport infrastructure, registry, and protocol-neutral pipe.
So where exactly does it fit? The mq9 SDK is not trying to replace the A2A SDK or any existing protocol SDK.
Its role is protocol wrapper + transport pipe. Specifically:
Protocol wrapper layer. The mq9 SDK wraps existing Agent protocol SDKs so users can integrate with minimal code. For example, mq9.a2a wraps a2a-sdk; in the future mq9.mcp will wrap mcp-sdk.
Transport pipe layer. All protocol messages are transmitted through the mq9 broker pipe. This pipe has persistence, a registry, key-based compaction, and N-to-N topology. Agent communication no longer requires both sides to be online at the same time, and neither side needs to manage connections.
The relationship between the two layers:

The mq9 SDK and the A2A SDK are not peers — they're layers. The A2A SDK is always the protocol entry point; the mq9 SDK is a wrapper layer on top of it.
A few judgments worth making explicit.
Judgment 1: Don't reinvent the protocol layer.
How A2A defines Message, Task, and AgentCard — mq9 doesn't reinvent any of that. a2a-sdk already handles everything at the protocol layer (type definitions, state machines, serialization, AgentCard signing, etc.). This is the product of years of investment by Google's engineering team. Rewriting it would be both unnecessary and worse.
The mq9 SDK depends directly on a2a-sdk and uses its native types. The Message a user gets is a2a.types.Message. The handler they write sends and receives standard objects. That means an Agent written with the mq9 SDK can be called by any A2A-standard-compliant client. Interoperability is preserved.
Judgment 2: The wrapper layer only does engineering simplification — not protocol extension.
This is a strict discipline. The wrapper can make APIs simpler (decorators, sensible defaults, auto-registration), but it cannot add fields beyond the A2A spec, change Task state machine behavior, or modify Message serialization format.
Once you add something outside the A2A spec in the wrapper layer, mq9 effectively forks from the standard. An Agent written with mq9 won't work when called by a pure a2a-sdk client. That kind of "wrapper" splinters the ecosystem — absolutely not acceptable.
Judgment 3: The broker is the main body; the SDK completes the last mile.
In the mq9 project, the SDK and the broker are not equals.
The mq9 broker is the product of years of engineering accumulated through the RobustMQ project. What it solves is engineering depth: broker stability, mailbox persistence, registry semantic search, N-to-N topology engineering. These took years to build and can't be copied by open-sourcing a wrapper.
The mq9 SDK is different. An SDK is essentially a wrapper — roughly 2,000 lines of Python, buildable in 4–6 weeks. Any engineer who knows a2a-sdk could write something similar.
| Dimension | mq9 broker | mq9 SDK |
|---|---|---|
| Engineering investment | Years of accumulation | Weeks to build |
| Complexity | Distributed system, storage engine, protocol design | Mainly decorators and wrappers |
| Replication difficulty | Extremely hard | Easy |
| Time share in the mq9 project | 3+ years | Planned |
| Role | Main body | Companion |
But the broker alone as a product has a problem: the user-facing barrier is too high. Businesses want "Agent communication" — not "a broker." Making them write connection code, define mailboxes, serialize messages, and integrate A2A is making them build middleware themselves.
The SDK completes the last mile of the broker: from "product capability" to "user can actually use it." It lets businesses integrate in 15 lines of code, lets a2a-sdk-standard Agents run naturally on mq9, and lets the broker's capabilities truly reach users.
The broker is the source of product value; the SDK is the release of product value. Together they make mq9 a complete usable product. This isn't "equal collaboration" — it's "main body + last mile." The broker is the real moat; the SDK is the key that lets the moat's value be accessed.
Judgment 4: Future packages wrap multiple protocols with the same structure.
Following this pattern, the mq9 SDK can wrap any Agent protocol:
mq9.a2a(A2A protocol wrapper — done first)mq9.mcp(when MCP expands to Agent-Agent)mq9.anp(ANP protocol wrapper, as needed)mq9.custom(user-defined protocols, via base class)
Each protocol namespace has the same structure — Agent / Client / Server classes, all going through the mq9 transport via the mq9 broker. Switching protocols has a low learning curve.
This design means mq9 doesn't need to bet on any single protocol. If A2A wins long-term, mq9 wins with it. If MCP expands to Agent-Agent and displaces A2A, mq9 adds a mq9.mcp package and pivots. Protocol changes don't threaten mq9's survival. With the protocol ecosystem still unsettled, this is the most important strategic safety net mq9 has.
How It Works
With the goal and positioning clear, here's the core implementation approach.
The mq9 SDK is functionally divided into four layers. These aren't just stacked vertically — they simultaneously answer two questions: how the SDK is modularized internally (vertical layering), and how users choose to integrate (horizontal selection).
Layer 1: mq9 native protocol wrapper. Maps directly to mq9 broker protocol commands (MAILBOX.CREATE, MSG.SEND, MSG.FETCH, MSG.ACK, MSG.QUERY, AGENT.REGISTER, AGENT.DISCOVER, etc.). Each API corresponds one-to-one with a protocol subject. This layer exposes all of mq9's native capabilities: mailboxes, key-based compaction, message-level TTL, N-to-N topology, and registry semantic search. It's the foundation everything else builds on.
Layer 2: A2A protocol wrapper. Wraps a2a-sdk so A2A-compliant Agents can run on the mq9 pipe. Internally composes a2a-sdk's AgentExecutor, DefaultRequestHandler, ClientFactory, and other standard components, plus an mq9 transport plugin that routes A2A messages through the mq9 broker. Users get standard A2A objects and write standard A2A business logic, but the underlying transport switches from HTTP to mq9 mailboxes.
Layer 3: Other protocol wrappers (future). Wraps MCP, ANP, and other Agent protocols using exactly the same pattern as mq9.a2a. Each protocol namespace provides a structurally consistent API. Not built on day 1, but day 1's engineering structure makes room for it: mq9.a2a's implementation can't hardcode "only wraps A2A" — it must extract reusable infrastructure.
Layer 4: Direct use of native API. This is an independent path parallel to the first three layers. Users don't have to use mq9.a2a or mq9.mcp — they can use Layer 1's native API directly and define their own Agent communication schema. Using mq9 as "an Agent-friendly messaging component" without binding to any upper-layer protocol.
The first three layers are "vertical," the fourth is "horizontal choice." The overall shape:

The left path (Path A) is "protocol-compliant integration": the Agent the business writes conforms to A2A or another standard protocol and can be called by any client that complies with that protocol.
The right path (Path B) is "custom integration": the business has full control over the Agent communication schema and simply uses mq9 as transport infrastructure.
For the mq9 SDK implementation, both paths are the same thing: both depend on Layer 1's native protocol wrapper. Layers 2 and 3 are optional "protocol adapter layers" built on top of Layer 1.
The benefit of this design is that the mq9 SDK's value doesn't depend on any specific protocol. Even if A2A and MCP both disappeared, the Path B option leaves the mq9 SDK as an independently useful product: an Agent-friendly messaging component. That's mq9 SDK's real moat — it doesn't depend on anyone else's survival.
Cutting across all layers is a capability called the mq9 transport plugin. It implements the transport interface defined by a2a-sdk (client side: BaseTransport; server side: a custom server runner) and routes A2A messages through the mq9 broker. This plugin lets the a2a-sdk client side register the mq9 transport via ClientFactory.register('MQ9', ...). It's the core mechanism when Layer 2 wraps the A2A protocol, and there'll be equivalent transport plugins for other protocols in the future.
A few key implementation details.
What Mq9Agent.run() does
The user writes an Agent and calls await agent.run(). What happens automatically:
1. Connect to mq9 broker (using Layer 1 native API)
2. Create own mailbox
3. Register AgentCard to the mq9 registry
4. Start the mq9 transport server runner
5. Server runner continuously FETCHes messages from own mailbox
6. Deserialize each message to a2a.types.Message
7. Process with a2a-sdk's DefaultRequestHandler
8. Handler calls the user's @handler function
9. Serialize the return value and send it to the callback mailbox
10. ACK the message to advance the consumption offsetThe user only sees step 8: their own business logic. The other 9 steps are handled by the SDK. That's what "genuinely useful" means concretely — not eliminating these steps, but hiding them inside the SDK so users don't have to rewrite them every time.
What Mq9Client.send_message() does
The user calls await client.send_message(target_agent, msg). What happens:
1. Extract the mq9 mailbox address from target_agent's AgentCard
2. Serialize Message to bytes (using a2a-sdk's standard serialization)
3. Send to the recipient's mailbox via mq9 broker (using Layer 1 native API)
4. Include the callback mailbox address in the request header
5. Long-poll the callback mailbox for a response
6. Deserialize the response to a2a.types.Message
7. Return to the userThe whole process is transparent to the user. The calling pattern is identical to using a2a-sdk with HTTP transport — the only difference is the URL scheme changes from https:// to mq9://.
What direct Layer 1 usage looks like
Path B users skip the protocol wrapper layer and call the mq9 native API directly:
from mq9 import Mq9NativeClient
client = Mq9NativeClient(broker="mq9://broker.company.internal")
# Create own mailbox
await client.create_mailbox(name="my.team.inbox")
# Send to another party (payload is arbitrary bytes — business defines the schema)
await client.send(
mail_address="other.team.inbox",
payload=json.dumps({"task": "do_something"}).encode()
)
# Fetch messages from own mailbox
messages = await client.fetch(
mail_address="my.team.inbox",
group_name="my-team-group"
)
for msg in messages:
handle(msg.payload)
await client.ack(
mail_address="my.team.inbox",
msg_id=msg.msg_id,
group_name="my-team-group"
)In this mode, mq9 provides reliable transport + mailbox abstraction + registry. It doesn't impose any Agent protocol spec and doesn't parse message content. The business uses whatever schema it wants.
Suitable scenarios: internal team Agent communication (no need to conform to external protocols); protocol transition periods (when A2A is still at 1.x and the business wants schema flexibility); writing tests or ops tools for mq9 (no need to go through the full A2A protocol).
Registry semantics
The mq9 broker's built-in registry is a stronger capability than A2A's standard. A2A's well-known URL mechanism only solves "how to get an AgentCard once you know the domain" — it doesn't solve "how to know the domain in the first place." mq9 provides complete discovery via AGENT.REGISTER + AGENT.DISCOVER, supporting tag search, text search, and semantic search.
The discovery interface is exposed directly at Layer 1; Layers 2 and 3 (mq9.a2a / mq9.mcp) simply surface it. Users write:
agents = await client.discover(query="anomaly detection")The mq9 broker internally uses vector search to find the best-matching Agents and returns their registration content. Users don't need to know domains, maintain Agent lists, or do their own matching.
This is a key differentiator for mq9 relative to a pure A2A solution. The "registry" gap that A2A leaves for the ecosystem to fill — mq9 fills it natively, and it's available regardless of whether you take Path A or Path B.
How to Use It
Goal, positioning, and implementation covered — here's what the actual code looks like.
Server side: writing an A2A Agent with mq9.a2a
from mq9.a2a import Mq9Agent
from a2a.types import AgentSkill
from a2a.utils import new_agent_text_message
agent = Mq9Agent(
name="Translator",
description="A translator agent",
mailbox="agent.translator.001.inbox",
skills=[
AgentSkill(
id="translate",
tags=["translation"],
examples=["translate to Chinese"]
)
]
)
@agent.handler
async def handle(message, context):
text = message.parts[0].text
result = await llm.translate(text)
return new_agent_text_message(result)
await agent.run()That's the mq9 equivalent of the 60 lines at the top — 15 lines, same functionality.
Everything underneath is the same: AgentCard is still an AgentCard, Message is still a standard Message, AgentExecutor is still an AgentExecutor. The difference is that mq9 handles all the engineering glue — starting the server, exposing the well-known endpoint, managing ports, constructing the AgentCard, registering to the registry. Users only write business logic.
Client side: calling another Agent with mq9.a2a
from mq9.a2a import Mq9Client
from a2a.utils import new_user_text_message
client = Mq9Client(broker="mq9://broker.company.internal")
# Discover an Agent via the mq9 registry
agents = await client.discover(query="Chinese-English translation")
# Send a message (underlying transport uses mq9 mailbox)
response = await client.send_message(
agents[0],
new_user_text_message("Hello world")
)
# response is a2a.types.Message — standard A2A object
print(response.parts[0].text) # 你好,世界A few things to note:
discoveris a mq9-native capability — find an Agent that can do the job using natural languagesend_messageaccepts and returns a2a-sdk nativeMessageobjects- The caller's code doesn't know whether the underlying transport is HTTP or mq9 — that's the compatibility with a2a-sdk direct calls
Alternative: direct mq9 native API
Not every scenario needs the full A2A standard protocol. If you just need internal team Agents to communicate, or the business has already defined its own message schema, use the mq9 native API directly — no protocol wrapper:
from mq9 import Mq9NativeClient
client = Mq9NativeClient(broker="mq9://broker.company.internal")
# Create own mailbox
await client.create_mailbox(name="team.fraud.detector.inbox")
# Register to mq9 registry (any schema to describe own capabilities)
await client.register_agent({
"mailbox": "mq9://broker/team.fraud.detector.inbox",
"name": "Fraud Detector",
"tags": ["fraud", "risk"],
"internal_version": "v2.3" # any business-defined field
})
# Send to another party (payload is arbitrary bytes)
await client.send(
mail_address="team.alert.handler.inbox",
payload=json.dumps({"event": "fraud_detected", "score": 0.92}).encode()
)
# Fetch and handle own mailbox messages
messages = await client.fetch(
mail_address="team.fraud.detector.inbox",
group_name="fraud-detector-workers"
)
for msg in messages:
handle(msg.payload)
await client.ack(
mail_address="team.fraud.detector.inbox",
msg_id=msg.msg_id,
group_name="fraud-detector-workers"
)In this mode, the user has full control over message content and communication patterns. mq9 provides reliable transport + mailbox abstraction + registry and doesn't parse message content or impose protocol specs.
Coexisting with a2a-sdk
The mq9 SDK doesn't hide a2a-sdk. When you need lower-level control, you can access it directly:
agent = Mq9Agent(...)
# Normally use the mq9 facade
@agent.handler
async def simple_handle(message, context):
return new_agent_text_message("...")
# But for lower-level control, get the a2a-sdk EventQueue for streaming
@agent.handler
async def stream_handle(message, context):
queue = context.event_queue # a2a-sdk's EventQueue
async for token in llm.stream(message.parts[0].text):
await queue.enqueue_event(new_agent_text_message(token))
# Or fully customize the AgentExecutor
from a2a.server.agent_execution import AgentExecutor
class MyCustomExecutor(AgentExecutor):
async def execute(self, context, event_queue):
# fully custom protocol handling logic
...
agent.with_executor(MyCustomExecutor())Simple cases use the mq9 facade. Complex cases dig into the a2a-sdk layer. Special cases use the mq9 native API directly. Three options, pick what fits — no forcing.
This is a key design judgment in the mq9 SDK: provide a friendly facade, but don't let the facade block the path.
The SDK's Role in the mq9 Project
Having covered all of this, it's worth stepping back to address what role the SDK actually plays in the mq9 project as a whole.
The core of the mq9 project is the broker — years of engineering depth accumulated through RobustMQ. The broker addresses the real pain points of Agent communication: what happens when both sides aren't online at the same time, how long-running tasks recover, how multiple Agents collaborate, how messages don't get lost. None of this is being done by anyone else in the A2A ecosystem. These are genuine vacuums.
But the broker alone as a product has a problem: the barrier for users is too high. Businesses face "I want Agent communication" — not "I want a broker." Making them write code to connect to the broker, define mailboxes, serialize messages, and integrate A2A protocols is making them write middleware themselves.
| Broker alone | SDK alone | Broker + SDK together |
|---|---|---|
| Engineering depth exists, but users can't reach it | Just another a2a-sdk wrapper | 15 lines of code for reliable Agent communication |
| Like having a gold mine with no road to it | Like building a road that leads to nothing | Business can actually use it |
The SDK completes this last mile. It lets businesses write 15 lines of code to get all the broker's capabilities, lets a2a-sdk-standard Agents run naturally on mq9. Without the SDK, users can't feel the broker's engineering depth; with the SDK, the broker's value truly reaches users.
This judgment has direct implications for how the mq9 project allocates effort. The broker is always the core — engineering energy goes to the broker first. The SDK follows the broker's pace. An SDK done before the broker is solid doesn't help; once the broker is solid, the SDK makes its value immediately tangible to users. The SDK engineering effort is also relatively small: one engineer, 4–6 weeks to ship the Python version.
Understanding this non-equal relationship makes the SDK's position clear: not the main body of the mq9 project, but the last mile that makes mq9 actually usable by users.
One-Line Summary
If there's only one sentence to describe what the mq9 SDK is:
The mq9 SDK is a foundational component for Agent communication. Want standard protocols — use our A2A wrapper. Want flexibility — use the mq9 native API directly. Either way, everything goes through the mq9 broker's persistent, reliable pipe.
It doesn't compete with the A2A SDK — it's a facade layer on top of a2a-sdk. It doesn't compete with LangGraph — it's the communication infrastructure underneath them. It doesn't compete with Kafka — Kafka handles general message streams; mq9 handles Agent communication. Are engineers using mq9 today having a smoother experience than they did yesterday?
