Back to all posts
Guide
9 min read

A2A Protocol Explained: 150+ Companies Backed It in a Year, Here's What It Actually Solves

DevToolLab Team

DevToolLab Team

July 19, 2026

A2A Protocol Explained: 150+ Companies Backed It in a Year, Here's What It Actually Solves

Google open-sourced the Agent2Agent protocol in April 2025, handed it to the Linux Foundation two months later, and by its first anniversary in April 2026 the numbers looked like this: 150+ supporting organizations (up from just over 50 a year earlier), 22,000+ stars on the core repo, and SDKs shipping in five languages: Python, JavaScript, Java, Go, and .NET. It's baked into Azure AI Foundry, Amazon Bedrock AgentCore, and Google Cloud's Agent Development Kit.

Those are real numbers, but "150 companies signed a support letter" and "developers actually reach for this instead of a REST call" are two different claims. If you've been building agents this year, you've probably heard A2A mentioned in the same breath as MCP and weren't sure if it's a protocol you need or a press-release fixture. This post covers what A2A actually does, where it stops overlapping with MCP, and a working Python example so you can decide for yourself.

What A2A Actually Is

MCP connects an agent to tools and data. A2A connects an agent to other agents, ones that might run on a different vendor's stack, in a different language, owned by a different team entirely. The core problem it solves: agent A doesn't need to know how agent B is built, only what it can do and how to hand it a task.

Four concepts do most of the work:

ConceptWhat it is
Agent CardA JSON document, served at /.well-known/agent-card.json, describing an agent's skills, supported input/output modes, and auth requirements
TaskA unit of work with a lifecycle: submittedworking → (input-required if it needs more from the caller) → completed / failed / canceled
MessageOne turn in the exchange between a client agent and a remote agent
ArtifactThe actual output a task produces, made of one or more typed Parts (text, file, or structured data)

Transport is JSON-RPC 2.0 over HTTP by default, with Server-Sent Events for streaming and push notifications for tasks that outlive a single request. Version 0.3, released in August 2025, added gRPC as an alternate transport and signed Agent Cards (JWS) so a client can verify a card wasn't tampered with in transit, which matters more than it sounds like the first time someone points out an Agent Card is just an unauthenticated JSON file sitting at a well-known URL.

A2A vs MCP: Different Layers, Not Competitors

The framing that actually holds up: MCP is the tool-integration layer, A2A is the agent-collaboration layer. MCP handles "give my agent a function to call." A2A handles "hand this task to an agent I don't control and get a result back." A serious multi-agent system usually needs both, not one instead of the other.

MCPA2A
ConnectsAgent → tool/data sourceAgent → agent
Unit of workTool callTask (stateful, can span multiple turns)
DiscoveryServer lists its toolsAgent Card lists its skills
Typical ownerYou, for your own toolsOften a different team or vendor

If you're building an MCP server yourself, our Python MCP server guide and the OAuth 2.1 security walkthrough cover that side. A2A picks up where those leave off: once your agent has tools, how does it delegate a sub-task to someone else's agent instead of reimplementing what they already built?

When You Actually Need It (and When You Don't)

The honest criticism circulating this year is fair: a lot of A2A demos show three agents doing what three function calls would do just as well. Standing up an Agent Card, a task store, and JSON-RPC handling for a single in-process call is pure overhead. Reach for it when:

  • The other agent is genuinely out of your control - a different team, a different company, or built on a framework you're not going to rewrite.
  • The interaction is a real task, not a function call - it needs multiple turns, can ask for more input mid-flight, or takes long enough that you want streaming/push updates instead of blocking on one HTTP response.
  • You need to discover capabilities at runtime rather than hardcoding what the other side can do.

Skip it when a direct API call, a shared MCP server, or (if you're using something like LangGraph, CrewAI, or AutoGen) in-process orchestration already does the job. And treat "150 organizations support this" as an interoperability signal, not proof that it's load-bearing in production yet. What actually determines that is whether teams keep it after the first authentication failure and compliance review, which is a much smaller number than 150.

Building a Minimal A2A Agent in Python

The reference implementation is a2a-sdk (compatible with both the 1.0 and 0.3 protocol versions):

pip install "a2a-sdk[http-server]"

First, describe what the agent can do with an AgentSkill, then wrap it in an AgentCard:

Python
from a2a.types import AgentCard, AgentCapabilities, AgentSkill

skill = AgentSkill(
    id="summarize_ticket",
    name="Summarize Support Ticket",
    description="Reads a support ticket thread and returns a one-paragraph summary.",
    input_modes=["text/plain"],
    output_modes=["text/plain"],
    tags=["support", "summarization"],
    examples=["Summarize ticket #4021"],
)

agent_card = AgentCard(
    name="Ticket Summarizer Agent",
    description="Summarizes support tickets on request.",
    url="http://localhost:9999",
    version="1.0.0",
    default_input_modes=["text/plain"],
    default_output_modes=["text/plain"],
    capabilities=AgentCapabilities(streaming=True),
    skills=[skill],
)

Then implement the executor, the part that actually does the work when a task comes in:

Python
from a2a.server.agent_execution import AgentExecutor, RequestContext
from a2a.server.events import EventQueue
from a2a.server.tasks import TaskUpdater
from a2a.types import TaskState
from a2a.utils import new_task_from_user_message, new_text_message, new_text_part


class TicketSummarizerExecutor(AgentExecutor):
    async def execute(self, context: RequestContext, event_queue: EventQueue) -> None:
        task = context.current_task or new_task_from_user_message(context.message)
        updater = TaskUpdater(event_queue, task_id=task.id, context_id=task.context_id)

        await updater.update_status(
            state=TaskState.working,
            message=new_text_message("Reading ticket thread..."),
        )

        summary = summarize(context.message)  # your own logic / LLM call goes here

        await updater.add_artifact(parts=[new_text_part(text=summary)])
        await updater.update_status(state=TaskState.completed)

    async def cancel(self, context: RequestContext, event_queue: EventQueue) -> None:
        raise NotImplementedError("This agent doesn't support cancellation yet.")

Finally, wire it up to a server and run it:

Python
from a2a.server.apps import A2AStarletteApplication
from a2a.server.request_handlers import DefaultRequestHandler
from a2a.server.tasks import InMemoryTaskStore
import uvicorn

handler = DefaultRequestHandler(
    agent_executor=TicketSummarizerExecutor(),
    task_store=InMemoryTaskStore(),
)
app = A2AStarletteApplication(agent_card=agent_card, http_handler=handler).build()

if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=9999)

Confirm the card is being served correctly before wiring up a real client:

Bash
curl -s http://localhost:9999/.well-known/agent-card.json

Run that JSON through the JSON validator or the JSON Schema validator while you're wiring up a new agent, a malformed Agent Card is a surprisingly common reason a client silently fails to discover skills. For the actual task-submission call, the cURL command generator saves you from hand-typing the JSON-RPC envelope every time you tweak a parameter, and a UUID generator is the easiest way to hand out unique task and context IDs if your framework doesn't do it for you.

Security: The Part the Demos Skip

Every serious writeup of A2A this year lands on the same open question: an Agent Card answers "what can this agent do," not "who owns it, and what should it be allowed to know." That's a real gap, not a nitpick. A few things worth doing from day one instead of retrofitting later:

  1. Verify signed cards. v0.3's JWS signing means you can check a card wasn't swapped in transit, don't skip verification just because the request came back over HTTPS.
  2. Scope what a remote agent can request, the same way you would with an OAuth scope on an MCP server, rather than trusting every skill listed in a card.
  3. Decode and check tokens carried between agents with the JWT decoder before assuming an aud or sub claim means what you think it does.
  4. Don't forward a caller's token to a third-party agent unmodified. The same confused-deputy risk we covered in the MCP OAuth guide applies here: if agent A hands its own credential to agent B, B can now act with A's authority on systems it was never meant to touch.

Conclusion

A2A isn't hype in the sense of "doesn't work," the spec is real, the SDKs work, and the adoption numbers are genuine. It's hype in the narrower sense that most projects reaching for it this year don't need it yet. Use MCP to give your agent tools. Reach for A2A only once you actually have a second agent, one you don't control, that needs to accept a task, work on it over multiple turns, and hand back a result. If your current use case is "agent A calls agent B once and gets a string back," you don't have an A2A problem, you have a function call.

Related Posts

9 Supply Chain Security Tools in 2026

One npm dependency pulls in 67 packages. Syft, Grype, Trivy, Cosign, OSV-Scanner, Dependency-Track, Snyk, Chainguard and Socket, with real versions and prices.

By DevToolLab Team

6 Best Opsgenie Alternatives (2026)

Opsgenie shuts down April 5, 2027. PagerDuty, incident.io, Rootly, FireHydrant, Jira Service Management and open-source Keep compared on price and migration.

By DevToolLab Team

Best Uptime Monitoring Tools in 2026

UptimeRobot, Better Stack, Checkly and Cronitor priced from their own pages, plus the open-source options worth self-hosting: Uptime Kuma, Gatus and Upptime.

By DevToolLab Team