A2A Protocol Versions
Choose which version of the A2A protocol your agent card advertises. A²D supports 0.3.0, 1.0, and dual (advertise both at the same time).
Why this matters
The A2A spec changed shape between 0.3.0 and 1.0. A card that picks the wrong version will fail discovery for clients that only speak the other one. A dual card gives you a smooth migration path — old and new clients both work — without forcing you to maintain two separate endpoints.
What changed between versions
Card envelope:
0.3.0cards exposeurlandprotocolVersionas top-level fields.1.0cards wrap them in asupportedInterfaces[]array, with one entry per(url, protocolBinding, protocolVersion)triple.
Message shape on message/send / SendMessage:
0.3.0usesrole: "user"and parts shaped as{ kind: "text", text: "..." }.1.0usesrole: "ROLE_USER"and unified parts shaped as{ text: "...", mediaType: "text/plain" }.1.0also renames the JSON-RPC method frommessage/sendtoSendMessage.
Result / artifact shape:
0.3.0returnsTaskandMessageresults withkinddiscriminators.1.0returns the same logical shape withROLE_AGENTand unified part objects.
Response envelope on SendMessage (v1.0):
0.3.0returns theTask(orMessage) directly as the JSON-RPCresult—contextId,status, andartifactssit at the top ofresult.1.0wraps it in aSendMessageResponse, a protooneof { Task task; Message message; }. The task is nested underresult.task, not returned flat. Strict protojson consumers (for example the MuleSoft Agent Broker) reject a flat task becauseSendMessageResponsehas no top-levelcontextId.
// 0.3.0 — Task returned flat
{ "jsonrpc": "2.0", "id": 1, "result": { "contextId": "ctx-1", "status": { "state": "completed" }, "artifacts": [] } }
// 1.0 — Task nested under `task`
{ "jsonrpc": "2.0", "id": 1, "result": { "task": { "contextId": "ctx-1", "status": { "state": "TASK_STATE_COMPLETED" }, "artifacts": [] } } }Choosing a version
0.3.0 — older clients only
Pick this when you know every consumer of your card runs on the older A2A SDK. The card is the smallest and most compatible with existing tooling.
1.0 — modern clients only
Pick this for new agents where you control the consumers. 1.0 is the spec direction going forward.
dual — advertise both
A dual card uses the 1.0-shaped envelope and lists both versions inside supportedInterfaces:
{
"supportedInterfaces": [
{
"url": "https://example.com/api/platform/abc/a2a",
"protocolBinding": "JSONRPC",
"protocolVersion": "0.3.0"
},
{
"url": "https://example.com/api/platform/abc/a2a",
"protocolBinding": "JSONRPC",
"protocolVersion": "1.0"
}
]
}The agent’s mock endpoint accepts either dialect on the same URL. It routes by JSON-RPC method name (message/send → v0.3.0, SendMessage → v1.0) and by the optional A2A-Version request header.
The builder seeds a scenario template that matches the card’s version (v0.3.0 for 0.3.0/dual cards, v1.0 for 1.0 cards), but the stored shape no longer affects compliance. The runtime executor normalizes each scenario to match the shape of the incoming request — up-converting v0.3.0 → v1.0 and down-converting v1.0 → v0.3.0 on the fly — so a dual card answers either dialect correctly regardless of how its scenarios were authored. Down-conversion is lossless for text; non-text parts (file/data) and any v1.0-only task state map to the nearest v0.3.0 equivalent.
Streaming over SSE (v1.0)
A2A 1.0 support includes streaming responses over Server-Sent Events (SSE). This matters for interop with the MuleSoft Agent Broker / Agent Network 2.0, whose A2A v1.0 support both calls streaming agents and acts as a streaming endpoint.
Streaming is opt-in per card and v1.0-only — it’s available on 1.0 and dual cards, not 0.3.0.
Turning it on: open the card, click Edit, and enable the Streaming (SSE) toggle (it appears only when the protocol version is 1.0 or dual). Saving sets capabilities.streaming: true, which the card’s .well-known/agent-card.json then advertises.
Calling a streaming card: clients POST a JSON-RPC request using a streaming method — SendStreamingMessage (v1.0 style) or message/stream (JSON-RPC style). The mock responds with Content-Type: text/event-stream and emits a synthesized sequence. Each frame’s result is a v1.0 StreamResponse, a proto oneof { task, message, statusUpdate, artifactUpdate }, so the interim event nests under statusUpdate and the terminal event nests under task:
data: {"jsonrpc":"2.0","id":1,"result":{"statusUpdate":{"taskId":"task-1","contextId":"ctx-1","status":{"state":"TASK_STATE_WORKING"},"final":false}}}
data: {"jsonrpc":"2.0","id":1,"result":{"task":{"contextId":"ctx-1","status":{"state":"TASK_STATE_COMPLETED"},"artifacts":[...]}}}The terminal task frame carries the same result your mock scenario would return unary. The interim statusUpdate frame is flagged final: false; the stream closes after the terminal task frame.
The stream is synthesized from the scenario’s single result — you don’t author per-event sequences. The mock is stateless: task continuation (input-required → tasks/resubscribe or a follow-up referencing taskId) is not supported.
If a streaming method is sent to a card that doesn’t advertise streaming, or to a 0.3.0 card, the endpoint returns a JSON-RPC error instead of a stream.
Testing it from the Protocol Tester: after discovering a streaming-capable 1.0 (or dual, with A2A 1.0 selected) card, a Stream response (SSE) checkbox appears next to the message input. Tick it and send — the tester issues SendStreamingMessage and shows the full event sequence (working → final) in the response view. The checkbox only appears when the discovered card advertises capabilities.streaming; unticked, the tester sends the unary SendMessage.
The tester displays the streamed events as a batch, not token-by-token: the request is proxied server-side and the SSE body is buffered before the events are rendered.
Where to set the version
When creating a card manually
- Open Agent Cards in the sidebar.
- Click + New Agent Card.
- In the Protocol version dropdown, pick
0.3.0,1.0, ordual. - Fill in the rest of the card and save.
When generating with AI
- On the Agent Cards list, click Generate with AI.
- Set Protocol version to your target version.
- The AI generator emits mock scenarios in the matching shape — you don’t need to convert them by hand.
When importing from a JSON spec
The importer detects the version automatically:
- Top-level
url+protocolVersion→0.3.0. supportedInterfaceswith one entry →1.0.supportedInterfaceswith two entries (one per version) →dual.
You can override the detected version on the import preview before confirming.
Testing a multi-version card
Open the card’s Test tab (or the Protocol Tester from the sidebar). When the discovered card has more than one entry in supportedInterfaces, a Send messages using picker appears above the message input — toggle between A2A 0.3.0 and A2A 1.0 to send each dialect. The picker rewrites both the URL and the JSON-RPC method/role used for the next request.
For automated suite runs against a dual card, pin the dialect per test with the A2A protocol version dropdown in the Testing Framework — the runner sends the matching envelope and unwraps the response the same way for both versions.
Where the version lives in storage
The card row in agent_cards carries a protocol_version column whose value is one of 0.3.0, 1.0, or dual. The .well-known/agent-card.json endpoint reads this column and emits the right envelope on every request.
Next Steps
- Creating Agent Cards — End-to-end agent card walkthrough
- Signed Agent Cards — Add JWS signing on top of any version
- Protocol Tester — Exercise the card’s endpoints
Pick the version that matches your consumers, or use dual to migrate without breakage.