AI Agent A2A Reference [2026] Interaction Patterns
Bottom Line
Use A2A as the network contract between autonomous agent services, not as a replacement for local handoffs or tool calling. In most production stacks, the winning pattern is local orchestration first, MCP for tools, and A2A only when the other side is a real remote agent.
Key Takeaways
- ›As of May 1, 2026, A2A 1.0.0 is the current released spec baseline.
- ›Latest A2A discovery starts at /.well-known/agent-card.json, not older 0.2.x paths.
- ›Use MCP for tools and resources; use A2A for remote, stateful, multi-turn agent collaboration.
- ›Core A2A ops center on SendMessage, SendStreamingMessage, GetTask, SubscribeToTask, and push configs.
Agent-to-agent architecture got much less hand-wavy in 2026. The current A2A 1.0.0 spec gives you a concrete contract for discovery, long-running tasks, streaming, authenticated capability cards, and update delivery, while MCP stays focused on tools and resources underneath the agent. This reference is the practical map: when to use each boundary, which operations matter, how to wire the page UX, and what to avoid when you want interoperable agents without building a distributed mess.
- May 1, 2026 baseline: A2A 1.0.0 is the current released spec.
- Discovery first: start at
/.well-known/agent-card.jsonand validate capabilities before advanced calls. - Boundary rule: MCP is for tools and data; A2A is for peer agents with task state and negotiation.
- Fastest path: local handoffs first, remote A2A second, push delivery only for genuinely long jobs.
| Pattern | Best For | State Model | Transport | Edge |
|---|---|---|---|---|
| Local handoff | Same-process specialists and prompt routing | Single run, shared app control | In-process SDK calls | Latency |
| MCP | Tool use, resources, prompts, capability exposure | Client-server session | STDIO or Streamable HTTP | Structured tool access |
| Remote A2A | Independent agents owned by another service or team | Task lifecycle with streaming and async delivery | HTTP, JSON-RPC, SSE, REST binding | Interoperability |
Quick Map
Bottom Line
Treat A2A as the contract between autonomous services, not as a fancier function call. Use MCP for tools, use local handoffs for same-process specialists, and only pay the A2A coordination cost when the other side is a real remote agent.
Choose the boundary deliberately
- Use local handoffs when specialists live in the same app and one agent should take over the turn.
- Use agents as tools when the manager should keep ownership of the final answer.
- Use MCP when an agent needs structured access to tools, resources, and prompts.
- Use A2A when the other side is independently deployed, stateful, and expected to negotiate, stream, or run long tasks.
What changed enough to matter in 2026
- The current public discovery path is
/.well-known/agent-card.json. - The latest A2A method surface centers on SendMessage, SendStreamingMessage, GetTask, ListTasks, CancelTask, and SubscribeToTask.
- The REST binding uses endpoints like
POST /message:sendandPOST /tasks/{id}:subscribe. - The Agent Card now exposes optional features in
capabilities, includingstreaming,pushNotifications, andextendedAgentCard.
Live Search JS Filter
For a Type B reference page, the fastest usability win is instant filtering over command cards, tables, and pattern notes. Keep the contract tiny: one search input, one empty state, and one data-ref-item per searchable block.
const search = document.querySelector('[data-ref-search]');
const items = [...document.querySelectorAll('[data-ref-item]')];
const empty = document.querySelector('[data-ref-empty]');
function applyFilter(query) {
const q = query.trim().toLowerCase();
let visible = 0;
for (const item of items) {
const haystack = [
item.dataset.title || '',
item.dataset.tags || '',
item.textContent || ''
].join(' ').toLowerCase();
const match = !q || haystack.includes(q);
item.hidden = !match;
if (match) visible += 1;
}
if (empty) empty.hidden = visible !== 0;
}
search?.addEventListener('input', (e) => {
applyFilter(e.target.value);
});
applyFilter(search?.value || '');Minimal markup contract
<input data-ref-search type='search' placeholder='Filter A2A commands, states, and patterns' />
<section data-ref-item data-title='SendMessage' data-tags='a2a request task blocking'>...</section>
<section data-ref-item data-title='SubscribeToTask' data-tags='a2a sse stream async'>...</section>
<p data-ref-empty hidden>No matches.</p>If you are pasting lots of example payloads, run them through the Code Formatter before publishing so the search surface stays predictable.
Keyboard Shortcuts
Cheat sheets live or die on scan speed. Bind a few memorable keys and stop there.
| Shortcut | Action | Why It Matters |
|---|---|---|
/ | Focus search | Fastest path to any command or pattern |
Esc | Clear search or blur input | Returns the page to full scan mode |
j | Jump to next visible result card | Works well after filtering |
k | Jump to previous visible result card | Completes the scan loop |
g c | Jump to commands | Useful for repeated lookup sessions |
g a | Jump to advanced usage | Good for returning readers |
c | Copy focused code block | Pairs well with copy buttons on <pre> |
document.addEventListener('keydown', (e) => {
if (e.key === '/' && document.activeElement?.tagName !== 'INPUT') {
e.preventDefault();
document.querySelector('[data-ref-search]')?.focus();
}
if (e.key === 'Escape') {
const el = document.activeElement;
if (el?.matches?.('[data-ref-search]')) {
el.value = '';
el.blur();
el.dispatchEvent(new Event('input', { bubbles: true }));
}
}
});Commands Grouped by Purpose
Discovery and negotiation
| Purpose | Operation | REST Binding | Use It When |
|---|---|---|---|
| Public discovery | Agent Card | GET /.well-known/agent-card.json | You need identity, skills, supported interfaces, and capabilities. |
| Extended discovery | GetExtendedAgentCard | GET /extendedAgentCard | You need authenticated details beyond the public card. |
| Capability check | capabilities.streaming, capabilities.pushNotifications, capabilities.extendedAgentCard | Card field | You want to avoid unsupported operations before calling them. |
Starting work
| Purpose | JSON-RPC | REST Binding | Notes |
|---|---|---|---|
| Blocking or polled request | SendMessage | POST /message:send | Default fit for direct response or task creation. |
| Live stream from first token or first task event | SendStreamingMessage | POST /message:stream | Use when the card advertises streaming. |
Monitoring and control
| Purpose | JSON-RPC | REST Binding | Notes |
|---|---|---|---|
| Get current task state | GetTask | GET /tasks/{id} | Polling path; supports history length semantics in the protocol. |
| List tasks | ListTasks | GET /tasks | Useful for context-level views and pagination. |
| Cancel task | CancelTask | POST /tasks/{id}:cancel | Idempotent, but terminal tasks are not cancelable. |
| Resume updates | SubscribeToTask | POST /tasks/{id}:subscribe | First SSE event must be the current Task. |
Async delivery
| Purpose | JSON-RPC | REST Binding | Notes |
|---|---|---|---|
| Create webhook config | CreateTaskPushNotificationConfig | POST /tasks/{id}/pushNotificationConfigs | For long jobs where the client may disconnect. |
| Inspect webhook config | GetTaskPushNotificationConfig | GET /tasks/{id}/pushNotificationConfigs/{configId} | Use in reconciliation flows. |
| Enumerate configs | ListTaskPushNotificationConfigs | GET /tasks/{id}/pushNotificationConfigs | Useful when clients attach multiple callbacks. |
| Delete config | DeleteTaskPushNotificationConfig | DELETE /tasks/{id}/pushNotificationConfigs/{configId} | Clean up after terminal tasks. |
Neighboring patterns you will use with A2A
- MCP discovery:
initialize,notifications/initialized,tools/list,resources/read,prompts/list. - MCP execution:
tools/callplus optional notifications such asnotifications/tools/list_changed. - OpenAI local orchestration: handoffs when the specialist should take over the turn; agent.asTool() when the manager should stay user-facing.
Configuration
Minimal A2A Agent Card
{
"name": "Invoice Review Agent",
"description": "Reviews invoices, flags anomalies, and returns audit notes.",
"supportedInterfaces": [
{
"transport": "HTTP+JSON"
}
],
"version": "1.0.0",
"capabilities": {
"streaming": true,
"pushNotifications": true,
"extendedAgentCard": true
},
"defaultInputModes": ["text/plain", "application/json"],
"defaultOutputModes": ["text/plain", "application/json"],
"skills": [
{
"id": "invoice_audit",
"name": "Invoice audit",
"description": "Validates invoice data and identifies likely issues.",
"tags": ["finance", "audit", "validation"]
}
]
}Local specialist graph with OpenAI Agents SDK
import { Agent, run } from '@openai/agents';
const billing = new Agent({
name: 'Billing Agent',
instructions: 'Handle billing disputes and invoice questions.',
model: 'gpt-5.4'
});
const security = new Agent({
name: 'Security Agent',
instructions: 'Handle auth, access, and privacy issues.',
model: 'gpt-5.4'
});
const triage = Agent.create({
name: 'Triage Agent',
instructions: 'Route users to the right specialist.',
handoffs: [billing, security]
});
const result = await run(triage, 'Why was this account locked after invoice review?');
console.log(result.finalOutput);This is the right default when the specialists are still your code, your process, and your deployment boundary.
MCP bootstrap reminder
{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-06-18",
"capabilities": {
"elicitation": {}
},
"clientInfo": {
"name": "agent-host",
"version": "1.0.0"
}
}
}After initialization, the client sends notifications/initialized, then it can discover tools with tools/list and execute them with tools/call.
Advanced Usage
High-value patterns
- Set returnImmediately when you want SendMessage to create work fast and move status tracking to GetTask, SubscribeToTask, or push delivery.
- Use messageId for dedupe because A2A explicitly allows idempotency handling around duplicate messages.
- Prefer SubscribeToTask over polling if users are actively waiting; the spec requires the current
Taskas the first event, which reduces the state race. - Use ListTasks with context and pagination to build operator views, retry dashboards, or stuck-work sweeps.
- Scrub traces, cards, and payload samples before storing them; the Data Masking Tool is a cheap guardrail for production docs and support exports.
POST /message:send HTTP/1.1
Host: agent.example.com
Content-Type: application/a2a+json
Authorization: Bearer $TOKEN
A2A-Version: 1.0
{
"message": {
"role": "ROLE_USER",
"parts": [{ "text": "Generate an audit summary for invoice batch 42" }],
"messageId": "msg-42"
},
"configuration": {
"returnImmediately": true
}
}Primary sources: A2A Protocol Specification, MCP Architecture Overview, OpenAI Agents SDK Handoffs, and OpenAI Agents SDK Tools.
Frequently Asked Questions
What is the difference between A2A and MCP? +
When should I use A2A instead of local handoffs or tool calling? +
What does an A2A agent card need in 2026? +
name, description, supportedInterfaces, version, capabilities, input and output modes, and skills. The public discovery path is /.well-known/agent-card.json. Clients should inspect capabilities before attempting streaming, push notifications, or extended card retrieval.How do I handle long-running A2A tasks without blocking the client? +
returnImmediately when you want the task created quickly and status handled elsewhere. Then choose one of three follow-ups: poll with GetTask, stream with SubscribeToTask, or register webhooks with push notification config methods. In active UI flows, streaming is usually the cleanest operator experience.Get Engineering Deep-Dives in Your Inbox
Weekly breakdowns of architecture, security, and developer tooling — no fluff.