SIVARO
MCP (Model Context Protocol)

A2A Agent2Agent Protocol Example: A Practical Field Guide for 2026

You're staring at a multi-agent system where every agent speaks a different dialect of JSON. Sound familiar? The Agent2Agent (A2A) protocol is the answer. It...

agent2agentprotocolexamplepracticalfieldguide2026
By Nishaant Dixit
A2A Agent2Agent Protocol Example: A Practical Field Guide for 2026

A2A Agent2Agent Protocol Example: A Practical Field Guide for 2026

Free Technical Audit

Expert Review

Get Started →
A2A Agent2Agent Protocol Example: A Practical Field Guide for 2026

You're staring at a multi-agent system where every agent speaks a different dialect of JSON. Sound familiar?

The Agent2Agent (A2A) protocol is the answer. It's an open standard from the Linux Foundation that lets autonomous agents discover each other, negotiate capabilities, and exchange work — regardless of the underlying framework. I've spent the last eighteen months deploying A2A in production environments at SIVARO, and I've got the scars to prove it.

Here's the thing most tutorials get wrong: A2A isn't about building agents. It's about building the conversation layer between them. This guide shows you a working a2a agent2agent protocol example, explains the architecture in plain terms, and walks through a real-world setup you can adapt today.

What A2A Actually Solves

Before I show you code, let's kill a misconception.

A2A isn't MCP. I keep seeing people conflate the two. Model Context Protocol (MCP) connects an agent to tools and data. A2A connects agents to other agents. Different problem entirely.

Think of it this way — MCP is your agent's hands. A2A is its phone.

The protocol defines four core message types: Card, Message, Task, and Event. Agents exchange these over HTTP using JSON-RPC-style semantics. The magic is in the agent card — a public manifest that describes what an agent can do, its authentication requirements, and its capabilities.

When we deployed this at scale for a financial services client in April 2026, the interoperability gains were immediate. Two agents built on completely different stacks (LangGraph and a custom Rust runtime) were talking within an hour. No middleware. No custom adapters.

The Architecture: Agents, Cards, and Tasks

Here's the mental model that finally clicked for me.

Every A2A interaction starts with discovery. Agent A fetches Agent B's card — essentially a JSON file describing B's skills. This happens over a standard /.well-known/agent.json endpoint. If B claims it can handle "invoice processing" or "fraud scoring," Agent A can initiate a task.

The task lifecycle is where the protocol gets interesting.

You send a task, receive a task ID, then poll for updates — or subscribe to streaming events if latency matters. Tasks have states: submitted, working, input-required, completed, failed, and canceled. That input-required state is the killer feature. It enables true interactive collaboration, where agents pause and ask each other questions mid-execution.

Let me show you a concrete example.

python
import requests
import json

# Step 1: Fetch the agent card
card_response = requests.get("https://claims-processor.internal:8080/.well-known/agent.json")
agent_card = card_response.json()

print(f"Agent capabilities: {agent_card['capabilities']}")
# Output: Agent capabilities: ['claims.adjudicate', 'documents.extract', 'risk.assess']

# Step 2: Create a task
task_payload = {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tasks/send",
    "params": {
        "id": "task-2026-091",
        "message": {
            "role": "user",
            "parts": [
                {
                    "type": "text",
                    "text": "Adjudicate claim #34451 against policy #POL-8821"
                }
            ]
        }
    }
}

response = requests.post(
    "https://claims-processor.internal/",
    json=task_payload,
    headers={"Content-Type": "application/json"}
)
task_state = response.json()

Notice the jsonrpc: "2.0" framing. A2A rides on JSON-RPC 2.0, which is nice because it's dead simple and widely understood. No SOAP. No GraphQL. Just method calls with params.

Setting Up Your First A2A Agent-to-Agent Communication

The a2a agent to agent communication setup requires roughly four components. I'll walk through each because getting any one wrong causes silent failures.

Component 1: The Agent Card Endpoint

Your agent must expose a card. Without it, no other agent will know you exist. Here's a minimal implementation using FastAPI:

python
from fastapi import FastAPI, Response
import json

app = FastAPI()

@app.get("/.well-known/agent.json")
async def return_card():
    card = {
        "name": "DocExtractor",
        "description": "Specializes in extracting structured data from PDFs and scanned documents",
        "url": "https://doc-extractor.internal:8080/",
        "version": "1.2.0",
        "skills": [
            {
                "id": "extract",
                "name": "Document Extraction",
                "description": "Extracts key-value pairs from unstructured documents",
                "inputModes": ["text", "file"],
                "outputModes": ["json"]
            }
        ],
        "capabilities": {
            "streaming": True,
            "pushNotifications": False,
            "stateTransitionHistory": True
        },
        "security": {
            "authentication": {
                "schemes": ["bearer"],
                "credentials": "none_presented_externally"
            }
        }
    }
    return Response(content=json.dumps(card), media_type="application/json")

Critical detail: The card's url field must point to your main A2A endpoint — the one that receives tasks/send calls. I've seen teams spend days debugging why their card looks right but tasks mysteriously fail. It's almost always a mismatched URL.

Component 2: The Task Handler

This is where your agent actually does work. Here's where you handle incoming requests and return the task state:

python
@app.post("/")
async def handle_a2a_request(request: dict):
    method = request.get("method")
    
    if method == "tasks/send":
        return await handle_tasks_send(request)
    elif method == "tasks/get":
        return await handle_tasks_get(request)
    elif method == "tasks/cancel":
        return await handle_tasks_cancel(request)
    else:
        return {"jsonrpc": "2.0", "error": {"code": -32601, "message": "Method not found"}}

The implementation of handle_tasks_send should validate the task, kick off processing asynchronously, and immediately return the task state:

python
import asyncio

async def handle_tasks_send(request):
    task_id = request["params"]["id"]
    # Kick off async processing
    asyncio.create_task(process_task(task_id, request["params"]["message"]))
    
    return {
        "jsonrpc": "2.0",
        "id": request["id"],
        "result": {
            "id": task_id,
            "status": "working",
            "stateHistory": [
                {"status": "submitted", "timestamp": "2026-09-02T10:00:00Z"},
                {"status": "working", "timestamp": "2026-09-02T10:00:01Z"}
            ],
            "message": {
                "role": "agent",
                "parts": [
                    {"type": "text", "text": "Task received. Processing claim #34451."}
                ]
            }
        }
    }

Notice the stateHistory array. This isn't optional decoration — it's how other agents track progress and detect stuck tasks. The agent2agent protocol explained in most docs glosses over this, but state history is non-negotiable for production recovery scenarios.

Streaming: When Polling Isn't Fast Enough

Here's a problem we hit immediately in production: long-running tasks make polling miserable.

Our document ingestion pipeline processes 40,000 PDFs daily. Each takes 2-10 seconds. Polling every second across thousands of tasks creates a thundering herd on our backend. Streaming events fix this.

The A2A protocol supports SSE (Server-Sent Events) for task progress. You negotiate this during task creation by setting acceptedOutputModes to include "stream":

python
task_payload = {
    "jsonrpc": "2.0",
    "id": 2,
    "method": "tasks/send",
    "params": {
        "id": "task-2026-092",
        "message": {
            "role": "user",
            "parts": [
                {"type": "text", "text": "Extract fields from contract_8823.pdf"}
            ]
        },
        "acceptedOutputModes": ["stream", "json"],
        "pushNotificationConfig": {
            "url": "https://sivaro-callback.internal/notifications"
        }
    }
}

With push notifications configured, your agent gets a webhook call when the task completes. No polling. No wasted cycles. For an a2a agent2agent protocol example in high-throughput environments, this is the pattern that saves your infrastructure.

The Auth Trap You'll Hit

Most internal prototypes skip authentication. That works until your agents handle anything sensitive.

The A2A spec supports Bearer tokens and OpenID Connect. For enterprise deployment, you'll want the OIDC path. But here's the trap: every agent must independently validate every other agent's identity. That means key management, token refreshes, and certificate rotation. Tedious doesn't begin to cover it.

At a healthcare client deployment in July 2026, we solved this with a mesh-sidecar pattern. Each agent talks only to a local sidecar that handles mutual TLS and injects the required headers. The agents themselves just assume the sidecar handles auth. This is the pragmatic answer if you have multiple agents behind a service mesh.

For simpler setups, bearer tokens work fine:

python
headers = {
    "Authorization": f"Bearer {api_token}",
    "Content-Type": "application/json"
}

Just don't tell me you're "production ready" with hardcoded tokens in Dockerfiles. I've seen it. It's a breach waiting for a date stamp.

The Contrarian Take: You Probably Don't Need A2A

Now for the unpopular position.

If you have two agents on the same framework, in the same codebase, you don't need A2A. Call the function directly. A2A adds HTTP overhead, serialization latency, and network failure modes to what is logically a local operation. The protocol shines when agents are truly independent — different teams, different languages, different deployment lifecycles.

We made this mistake early on. Our fraud detection system had three agents sharing a Postgres database. They weren't talking over a protocol; they were just reading each other's tables. Forcing A2A between them added nothing but complexity. We ripped it out during a September 2025 refactor and the system got faster with less code.

So when should you use A2A? When boundaries are real:

  • Different vendors built the agents
  • Different security domains (DMZ vs. internal)
  • Different release cadences that shouldn't couple
  • You want to slot in third-party agents later

A2A is a contract for interop, not a framework for intraop.

Multi-Agent Orchestration Patterns

Multi-Agent Orchestration Patterns

Once you have basic communication working, patterns emerge. We've settled on three that solve most problems.

Pattern 1: The Router

A central dispatcher receives all tasks, examines the request, and routes to a specialist agent. This is the simplest orchestration and great for domain boundaries.

Pattern 2: The Pipeline

Work proceeds through stages. Agent A processes, then hands off to B, then C. Each agent knows its successor via configuration. This works brilliantly for document workflows.

Pattern 3: The Market

Agents publish capabilities and bid on tasks. Nobody routes. This is emerging as the pattern of choice for internal tool marketplaces — I'm seeing it in SIEM orchestration platforms and dynamic supply chain agents.

For a working example of multi-agent orchestration, check out the official A2A Python SDK on GitHub. It has client and server implementations that abstract away the wire protocol details.

Latency Reality Check

Let me give you honest numbers.

Round-trip latency for a simple task on our internal network:

  • Same-region, direct A2A call: 12-25ms overhead
  • Through our mesh (with mTLS): 35-50ms
  • Cross-region: 150-300ms

The protocol overhead itself is negligible compared to network locality. If your agents span regions and your tasks need sub-second completion, you're fighting physics before you're fighting protocol. Keep cooperating agents co-located.

Our production rule: if two agents exchange more than 100 tasks per minute, they live in the same VPC. Full stop.

Error Handling and Backoff

Agents crash. Networks partition. Tasks fail. The A2A protocol gives you error codes, but the retry strategy is yours.

Our approach after an embarrassing production incident in February 2026 (a dead consumer agent silently dropped 12,000 queued tasks):

python
def send_task_with_retry(agent_url, task_payload, max_retries=5):
    for attempt in range(max_retries):
        try:
            response = requests.post(agent_url, json=task_payload, timeout=30)
            if response.status_code == 200:
                return response.json()
        except requests.exceptions.Timeout:
            pass  # Agent might be slow - check later
        except requests.exceptions.ConnectionError:
            pass  # Agent is down - back off
            
        wait_time = 2 ** attempt  # Exponential backoff
        time.sleep(wait_time)
    
    raise RuntimeError(f"Failed to deliver task after {max_retries} attempts")

Exponential backoff with jitter is boring. It works. Use it.

What's Coming Next in the Protocol

The A2A spec is moving fast. The Linux Foundation's agent2agent announcement outlined the roadmap through 2026. I'm tracking three changes:

First, standardized audit logging. Every enterprise deployment needs tamper-evident task histories for compliance. That's in the roadmap but not in the current spec.

Second, richer capability negotiation. Cards today are JSON blobs with text descriptions. Next iterations include formal input/output schemas per skill. This will enable automatic task decomposition.

Third, and this is my prediction — A2A will absorb most of what we currently call "webhooks." If every agent talks A2A, why would you use arbitrary HTTP callbacks for integration? The protocol naturally becomes the universal API layer for agentic systems.

Testing Your A2A Implementation

Testing agent interactions is the area where tools have lagged behind. We use a combination of:

  1. Contract tests — Validate your card against the official JSON schema
  2. Mock agents — Stand up dummy agents that return canned responses for deterministic testing
  3. Chaos testing — Kill agents mid-task and verify your system recovers

The A2A Python client library makes mocking straightforward:

python
from a2a.client import A2AClient
from a2a.types import TaskStatus

# For testing, you can stub the client's send method
class MockA2AClient(A2AClient):
    async def send_task(self, url, task_payload):
        return {
            "id": "test-task-1",
            "status": "completed",
            "artifacts": {"data": {"status": "approved"}}
        }

FAQ: What People Actually Ask Me

What's the difference between A2A and MCP again?

MCP connects an agent to tools and data sources. A2A connects agents to agents. You use both. MCP gives agents abilities; A2A lets abilities communicate.

Do I need A2A for a single-agent system?

Absolutely not. Skip it.

Which version of the protocol should I use?

You want the current stable release focused on agent cards, task management, and streaming. Avoid pre-release features.

How does A2A handle different agent frameworks?

The whole point — it doesn't care. Your agent internals can be LangChain, CrewAI, Semantic Kernel, or a bash script. If it can speak JSON-RPC over HTTP, it speaks A2A.

Is A2A ready for production?

The protocol is stable enough. The ecosystem of tooling and observability is still catching up. We've run millions of tasks against it successfully — but only after adding our own monitoring layer on top.

The Bottom Line

The Bottom Line

A2A is solving a real problem: autonomous agents operated by different teams, in different languages, on different schedules, coordinating without a central brain. The protocol is lean enough to implement in a weekend. The patterns for reliability are maturing.

A practical ecosystem of specifications (MCP, A2A, and AGNTCY) will define how AI systems interoperate by 2027. A2A owns the agent communication layer. Get familiar with it through testing and pilot projects.

Start with a simple a2a agent2agent protocol example: two agents, one card per agent, single task negotiation. Learn the state machine. Then expand.

Your future platform will involve agents you don't own, talking to agents you own, negotiating work without human intervention. Building the conversation layer now is the difference between running this ecosystem and being run over by it.

I've seen the failure modes of closed, proprietary agent frameworks. They work until the next reorganization — then everything breaks. The open protocol is your hedge. Use it.


Nishaant Dixit — Founder of SIVARO. Building data infrastructure and production AI systems since 2018. Built systems processing 200K events/sec.

Part of our MCP (Model Context Protocol) series — see every guide in this cluster. Fighting this in production? Explore AI Product Development.

Free · No Commitment · 48-Hour Delivery

Get a free infrastructure audit

2-hour remote session. We audit your data infrastructure, identify what's costing you time and money, and deliver a written roadmap with specific, measurable targets. No pitch.

Book Your Free Audit
N
Nishaant Dixit
Founder & Lead Engineer at SIVARO

Building data-intensive systems since 2018. 200K events/sec pipelines, production RAG systems, Kubernetes infrastructure. LinkedIn →

Start a Project
Need help with AI systems?

Production RAG, LLM pipelines, and AI infrastructure — from prototype to production-grade systems.

Explore AI Product Development