MQTT.Agent
A protocol bundle for AI-agent communication. A2A semantics. MCP semantics. On MQTT 5.
Why this exists
MQTT.Agent is a transport substrate for AI agents. It carries Anthropic's Model Context Protocol (MCP) semantics for tool calls and Google's Agent2Agent (A2A) semantics for peer-to-peer messaging on top of MQTT 5. It sits within the broader MQTT for AI direction - initiatives like EMQX's MQTT.AI frame the category at the workload level; MQTT.Agent is narrower, focused specifically on the wire format for agent-to-agent and agent-to-tool communication.
Multi-agent systems are no longer one Python script with three function calls. Real deployments have agents on different machines, tool servers running as network services, long-running tasks that survive reconnects, and identity boundaries that audit teams can answer for.
Today every team builds that plumbing themselves. Message routing on REST. Presence on heartbeats. Recovery on retry libraries. Identity on shared API keys. None of it ports across stacks.
MQTT.Agent standardises the wire format. The substrate is MQTT 5. The semantics on top are A2A (agent-to-agent) and MCP (model-to-tool). The result is an open spec any broker, any SDK, any framework can implement.
MCP and A2A: what they are, what they leave open
MCP (Model Context Protocol, Anthropic) is how an LLM agent calls tools. Its reference transport is stdio: the tool runs as a subprocess of its caller, communication is line-delimited JSON over pipes. That fits editor-local tools, CLI helpers, anything shipping next to its caller.
A2A (Agent2Agent, Google / Linux Foundation) is how agents talk to other agents. Its reference transport is HTTP: each agent hosts an endpoint, peers POST messages with correlation IDs, replies come back synchronously or via webhook. That fits service-to-service calls when both ends have stable addresses and short-lived requests.
The gap shows up when:
- Tool servers are network services, not subprocesses. Stdio assumes co-location.
- Agents disconnect and reconnect. HTTP request/response loses the in-flight task.
- Tasks run for minutes, streaming partials. Long-poll is an anti-pattern.
- Multiple replicas serve one logical tool. Stdio has no notion of replica fan-out.
- Each agent has its own identity. Sharing one HTTP credential collapses the audit trail.
You can paper over each gap with libraries: a session manager, a retry queue, a subscription layer, a websocket shim. By the third project you have rebuilt what a message broker already gives you.
That is what MQTT.Agent fills. Same MCP semantics, same A2A semantics, on a transport that natively carries the missing primitives.
For the detailed wire format and conformance language, see the v0.1 specification.
Why MQTT
MQTT 5 is not a generic message bus. Several of its features map almost one-to-one onto the gaps above.
| Need | MQTT 5 feature |
|---|---|
| Agents on different hosts, no service discovery | Pub/sub via broker. No DNS, no hardcoded URLs. |
| Detect when a peer crashes or disconnects | Last Will and Testament (LWT). Broker publishes the will when the client drops. |
| Tolerate brief network blips | Will Delay Interval. Will fires only after N seconds; reconnect inside the window suppresses it. |
| Recover state after disconnect | Persistent sessions. Broker queues messages while the client is offline, replays on reconnect. |
| New subscribers see current state | Retained messages. Broker stores the last value per topic, delivers on subscribe. Used here for agent and tool discovery cards. |
| Request/response on a message bus | Response Topic and Correlation Data. Native MQTT 5 properties, no custom envelope needed. |
| Replicas behind one logical name | Shared subscriptions ($share/group/topic). Broker load-balances messages across subscribers. |
| Per-identity audit | Identity in the topic path. Brokers that understand claims can match topic segments to the connecting client. |
None of those are exotic. All are baseline MQTT 5 any conforming broker supports. MQTT.Agent's contribution is standardising the agent-comms shape so SDKs, brokers, and tool servers interoperate cleanly.
Why it matters in agentic conversation
Recoverability
Agent tasks are not millisecond RPCs. They run for seconds, minutes, sometimes hours. The agent that issued the call can go offline mid-task. Without persistent sessions and partial-result streaming, every reconnect resets the work. With them, the conversation survives the network. See Substrate Section 1.5 Session and presence for the wire-level details.
Presence
Coordination depends on knowing who is online. LWT gives presence at the broker level: when a client drops, the broker (not the client) announces it. With Will Delay Interval, brief blips do not generate false offline events. Discovery cards stay accurate without polling. See Substrate Section 1.5 Session and presence for the wire-level details.
Auditability
Every published message carries the connecting client's identity. Topic patterns include the identity claim, so logs are per-agent by construction. There is no shared service account masking individual behaviour. See Substrate Section 1.2 Identity claims for the wire-level details.
Operability
A hot tool gets replicated by adding subscribers to a share group. No load balancer. No service mesh. No code changes on the caller side. See MCP Section 3.3 Replicas and load balancing for the wire-level details.
Identity binding
Every connection presents a JWT. Claims include agent_id, tool_id, server_id, user_id, org_id, depending on role. Topic shapes embed the relevant claim:
- myapp/agents/{agent_id}/card
- myapp/agents/{agent_id}/inbox
- myapp/mcp/tools/{tool_id}/call
A broker that understands those claims can match the segment against the connecting client's token. agent-a may publish to agents/agent-a/* but not to agents/agent-b/*. That gives identity-bound enforcement at the wire level, not at an application layer that has to be coded into every agent.
The wire format works on any conforming MQTT 5 broker without claim enforcement. You retain pub/sub semantics, presence, sessions. You only lose the impersonation-resistance guarantee. The companion identity-bound ACL profile (forthcoming) describes the enforcement rules in normative form.
The multi-agent stack
A typical multi-agent system stacks four layers:
Each layer is independently swappable. Switch brokers, the agents do not change. Switch a tool server's implementation, the broker and other agents do not change. Identity travels in JWT claims, the same shape across all four layers.
Status
| Track | Status |
|---|---|
| MQTT.Agent specification | v0.1 draft, public on GitHub. Breaking changes possible during the v0.x window. |
| Reference SDKs (Node) | Published on npm at v0.1.x, tracking spec v0.1. Python parity on the roadmap. |
| Submission to MCP working group (Anthropic) | Drafted. Submission planned alongside this site launch. |
| Submission to A2A working group (Linux Foundation) | Drafted. Submission planned alongside this site launch. |
| Companion identity-bound ACL profile | In progress as a separate document. Targeted for v0.2. |
| Multi-broker / regional failover | Out of scope for v0.1. |
A public spec repository with issue tracker and RFC process is being prepared. In the meantime, send feedback to efi@cloudsignal.io.
Example: with a claim-enforcing broker
The two reference SDKs connect to a broker that ships the identity-bound ACL profile - CloudSignal MQTT is one such implementation. The client passes a JWT, and the broker enforces that each topic segment matches the matching claim in the token.
import { MCPClient } from '@cloudsignal/mcp-over-mqtt';
const client = new MCPClient({
clientId: 'agent-a',
broker: 'mqtts://broker.cloudsignal.app:8883',
credentials: {
orgId: process.env.ORG_ID!,
tokenServiceUrl: 'https://tokens.cloudsignal.app',
externalToken: process.env.AGENT_JWT,
},
});
await client.start();
const result = await client.call('echo', { text: 'hello' });The JWT carries agent_id=agent-a. A misconfigured client trying to publish as agent-b is rejected at the broker, not by application code. The wire format itself is the same regardless of broker; the difference is what the broker enforces.
Example: standalone with an open-source broker
⚠️ Future direction. This example shows the plannedstandalone experience. Today's published@cloudsignal/agentv0.1.1 and@cloudsignal/mcp-over-mqttpackages require CloudSignal-style credentials (orgId+tokenServiceUrl). A future minor release will add a credentials variant for vanilla MQTT brokers (anonymous and username/password); this example shows what it will look like once that lands. For working-today code, see Example: with a claim-enforcing broker above.
A complete end-to-end testbed runs on a local Mosquitto broker with two reference SDK packages - no account, no external service. The caller code is the smallest moving part:
import { MCPClient } from '@cloudsignal/mcp-over-mqtt';
const client = new MCPClient({
clientId: 'agent-a',
broker: 'mqtt://localhost:1883',
credentials: { anonymous: true }, // planned: see callout above
});
await client.start();
const result = await client.call('echo', { text: 'hello' });
console.log(result);Replace Mosquitto with EMQX, HiveMQ, VerneMQ, NanoMQ, or any other conforming MQTT 5 broker without code changes - once the vanilla-MQTT credentials variant lands in the SDK. See the full Run MQTT.Agent on a local Mosquitto broker guide for the broker setup, the tool server, and the bring-it-up commands.
Adoption and collaboration
For implementers, broker vendors, and framework authors interested in adopting MQTT.Agent or contributing to the spec:
- Spec issues, RFC comments, PRs: a public spec repository is being prepared. Until it lands, send feedback to efi@cloudsignal.io.
- Broker vendors: if you maintain an MQTT 5 broker and want to support claim-enforced topic ACL, open an issue or get in touch - the v0.2 companion ACL profile is being designed with broker implementation in mind.
- SDK authors in other languages: Python, Go, and Rust ports are welcome. The wire spec is sufficient to implement against without reading the TypeScript reference.
- Adoption, partnership, broker integrations: efi@cloudsignal.io
The specification is licensed CC-BY-4.0. Reference SDKs are MIT.