What Is the Agent2Agent (A2A) Protocol? A Developer Guide

Divya Lath
What Is the Agent2Agent (A2A) Protocol? A Developer Guide
Building an agent that needs the live web? Get a free TinyFish API key: TinySearch and TinyFetch are free, and new accounts get $8 for TinyAgent and TinyBrowser.

The A2A protocol (Agent2Agent) is an open standard that lets one AI agent find another agent, ask it to do a job, and get the result back, even when the two agents were built by different teams, on different frameworks, running on different servers. Each agent publishes an Agent Card that says what it can do and how to reach it. A client agent sends it a message, the remote agent tracks the work as a task, and the results come back as artifacts. Google introduced A2A in April 2025, the Linux Foundation has hosted it since June 2025, and the current specification is version 1.0.

TL;DR

  • What it is: an open protocol for agent-to-agent communication. Agents collaborate as peers without sharing their memory, prompts or tools.
  • Discovery: every A2A agent publishes an Agent Card, usually at https://{domain}/.well-known/agent-card.json, listing its skills, endpoints and auth requirements.
  • Work: a client sends a message. The remote agent answers directly or creates a task that moves through states like TASK_STATE_WORKING and TASK_STATE_COMPLETED, and returns artifacts.
  • Transport: JSON-RPC 2.0, gRPC or HTTP+JSON over HTTPS, with streaming over Server-Sent Events and push notifications to a webhook for long jobs.
  • A2A vs MCP: MCP connects one agent to its tools and data. A2A connects agents to other agents. Most real systems use both, and plain APIs sit underneath both.

This guide is for developers who are new to agent protocols. We're TinyFish, and we build the web layer that agents call to search, read and use websites, so the worked example at the end uses our API as the web layer of a remote agent. The protocol details apply whatever you build with.

At a glance: A2A, MCP and plain APIs

A2A protocolModel Context Protocol (MCP)Plain API
ConnectsAn agent to another agentAn agent (AI app) to tools and dataAny program to a service
Who's on the other sideAn autonomous system that reasons, plans and keeps stateA tool, resource or prompt with defined inputsFixed endpoints written for developers
DiscoveryAgent Card at a well-known URL, a registry or direct configserver/discover and tools/listDocs, OpenAPI file
Unit of workTask with a lifecycle (submitted, working, input required, completed)Tool call with a resultRequest and response
Long-running workBuilt in: streaming, polling, push notificationsOptional Tasks extensionUp to each API
Wire formatJSON-RPC 2.0, gRPC or HTTP+JSONJSON-RPC 2.0 over stdio or Streamable HTTPUsually REST or gRPC
GovernanceLinux Foundation (contributed by Google)Agentic AI Foundation under the Linux Foundation (contributed by Anthropic)The API's owner

Where A2A came from

Google announced the Agent2Agent protocol on 9 April 2025, with more than 50 technology partners backing it. The problem it set out to solve was simple to describe: companies were building agents on different frameworks, and those agents had no common way to talk to each other. Every pairing needed custom glue.

On 23 June 2025, at Open Source Summit North America, the Linux Foundation launched the Agent2Agent project to give the protocol vendor-neutral governance. The specification and SDKs live on GitHub under the Apache 2.0 licence.

By its first anniversary, the project reported more than 150 supporting organisations, including AWS, Cisco, Google, IBM, Microsoft, Salesforce, SAP and ServiceNow. Microsoft built A2A into Azure AI Foundry and Copilot Studio, and AWS added support through Amazon Bedrock AgentCore Runtime. The same update highlighted version 1.0, the first stable specification, which added multi-protocol support, multi-tenancy, modernised security flows and signed Agent Cards.

If you read older tutorials, keep the version in mind. Pre-1.0 posts describe JSON-RPC methods like message/send and parts named TextPart and FilePart. In 1.0 the operations are SendMessage, GetTask and so on, task states are written as TASK_STATE_COMPLETED, and a part is a single object holding one of text, raw, url or data. The examples in this guide follow the current specification.

How A2A works, in one picture

There are two roles:

  • A2A client (client agent): the app or agent that needs help. It finds a remote agent, sends it work and reads the results.
  • A2A server (remote agent): the agent that does the work. It exposes an HTTP endpoint that speaks A2A and publishes an Agent Card.

A typical exchange has three steps:

  1. Discover. The client fetches the remote agent's Agent Card and checks its skills, endpoints and auth requirements.
  2. Authenticate. The client gets credentials out of band, following the security schemes the card declares, and sends them with each request.
  3. Communicate. The client sends a message. The remote agent replies with a message, or creates a task and reports progress until it finishes, fails or needs more input.
How the A2A protocol works: the client agent discovers the remote agent's Agent Card, authenticates, sends a message, and gets back task status and artifacts
How A2A works: discover, authenticate, communicate

The key design choice is opacity. The remote agent never exposes its prompts, memory or tools. The client only sees the Agent Card, the task status and the artifacts. That lets a company offer an agent to partners without handing over its internals, which is exactly why A2A treats the other side as an agent and not as a tool.

Agent Cards: how agents discover each other

An Agent Card is a JSON document that works like a business card for an agent. In version 1.0 the required fields are name, description, version, supportedInterfaces, capabilities, defaultInputModes, defaultOutputModes and skills. Optional fields include provider, documentationUrl, securitySchemes, securityRequirements, signatures and iconUrl.

The specification lists three ways to find a card:

  • Well-known URI: https://{server_domain}/.well-known/agent-card.json
  • Registries or catalogs: curated lists of agents your organisation trusts
  • Direct configuration: you hard-code the card URL or its contents

Here's a card for a hypothetical web research agent. It follows the 1.0 field names:

json
{
  "name": "Web Research Agent",
  "description": "Finds, reads and summarises current information from the public web, with sources.",
  "version": "1.0.0",
  "provider": {
    "organization": "Example Co",
    "url": "https://example.com"
  },
  "supportedInterfaces": [
    {
      "url": "https://research.example.com/a2a/v1",
      "protocolBinding": "JSONRPC",
      "protocolVersion": "1.0"
    },
    {
      "url": "https://research.example.com/a2a/json",
      "protocolBinding": "HTTP+JSON",
      "protocolVersion": "1.0"
    }
  ],
  "capabilities": {
    "streaming": true,
    "pushNotifications": true
  },
  "securitySchemes": {
    "apiKey": {
      "apiKeySecurityScheme": {
        "location": "header",
        "name": "X-Agent-Key"
      }
    }
  },
  "securityRequirements": [{ "schemes": { "apiKey": { "list": [] } } }],
  "defaultInputModes": ["text/plain"],
  "defaultOutputModes": ["text/markdown", "application/json"],
  "skills": [
    {
      "id": "live-web-research",
      "name": "Live web research",
      "description": "Searches the web, reads the most relevant pages and returns a sourced brief.",
      "tags": ["research", "web", "citations"],
      "examples": ["What changed in the EU AI Act implementation timeline this month?"]
    },
    {
      "id": "site-task",
      "name": "Interactive site task",
      "description": "Operates a website to collect information that sits behind filters, forms or pagination.",
      "tags": ["browser", "web automation"],
      "examples": ["List the five cheapest flights from SFO to JFK on 4 February."]
    }
  ]
}

A few things worth knowing about cards:

  • `supportedInterfaces` is ordered. The first entry is the preferred interface, and clients pick the first one they support.
  • Skills are descriptive. They tell a client agent (or the model inside it) what this agent is good at, so it can pick the right agent for a job. They are not function signatures.
  • Cards can be signed. Version 1.0 supports JSON Web Signatures over the card so a client can verify who published it before trusting it.
  • There can be an extended card. If capabilities.extendedAgentCard is true, an authenticated client can call GetExtendedAgentCard and see skills or details that the public card leaves out.

Messages, parts, tasks and artifacts

Four objects carry almost everything in A2A.

Message. One turn of communication. It has a role (ROLE_USER when the client sends it, ROLE_AGENT when the server does), a messageId, and one or more parts.

Part. A piece of content. In version 1.0 a part holds exactly one of:

  • text: a string
  • raw: file bytes, base64-encoded in JSON
  • url: a link to a file
  • data: any structured JSON value

Each part can also carry a mediaType, a filename and metadata.

Task. The unit of work. When a request needs more than a quick reply, the remote agent creates a task with an id, a contextId that groups related tasks and messages, and a status. The client can check it, list it, subscribe to it or cancel it.

Artifact. The output of a task, such as a report, a JSON dataset or an image. Artifacts are made of parts, have an artifactId, and can be streamed in pieces.

The task lifecycle

Version 1.0 defines these task states:

StateWhat it meansTerminal?
TASK_STATE_SUBMITTEDAccepted and acknowledgedNo
TASK_STATE_WORKINGBeing processedNo
TASK_STATE_INPUT_REQUIREDThe agent needs more information from the clientInterrupted
TASK_STATE_AUTH_REQUIREDThe agent needs authentication to continueInterrupted
TASK_STATE_COMPLETEDFinished successfullyYes
TASK_STATE_FAILEDFinished with an errorYes
TASK_STATE_CANCELEDCanceled before completionYes
TASK_STATE_REJECTEDThe agent decided not to do itYes

The two interrupted states are what make A2A feel like working with a colleague. A remote agent can stop and ask "which date did you mean?" and the client answers by sending another message on the same task.

How agents communicate

Three protocol bindings

The core operations are the same whichever binding you use. Version 1.0 defines three:

OperationJSON-RPC methodHTTP+JSON (REST) endpoint
Send a messageSendMessagePOST /message:send
Send and stream updatesSendStreamingMessagePOST /message:stream
Get a taskGetTaskGET /tasks/{id}
List tasksListTasksGET /tasks
Cancel a taskCancelTaskPOST /tasks/{id}:cancel
Resubscribe to a task's streamSubscribeToTaskPOST /tasks/{id}:subscribe
Register a webhook for a taskCreateTaskPushNotificationConfigPOST /tasks/{id}/pushNotificationConfigs
Get the extended Agent CardGetExtendedAgentCardGET /extendedAgentCard

gRPC uses the same method names. An agent declares which bindings it supports in supportedInterfaces, and a client can send an A2A-Version header so both sides agree on the protocol version.

A basic request and response

Using the HTTP+JSON binding, a client asks a question:

text
POST /message:send HTTP/1.1
Host: research.example.com
Content-Type: application/a2a+json
X-Agent-Key: <your key>

{
  "message": {
    "role": "ROLE_USER",
    "parts": [{ "text": "Summarise this week's announcements about A2A adoption, with sources." }],
    "messageId": "9f1c2a7e-4b6d-4e2f-9a51-1d2c3b4a5e6f"
  }
}

And gets back a completed task with an artifact:

json
{
  "task": {
    "id": "c1a7f0d2-6b9e-4a8f-b3c2-5e4d6f7a8b9c",
    "contextId": "7e2d9b1a-3c4f-4d5e-8f6a-9b0c1d2e3f4a",
    "status": { "state": "TASK_STATE_COMPLETED" },
    "artifacts": [
      {
        "artifactId": "a2b3c4d5-e6f7-4a8b-9c0d-1e2f3a4b5c6d",
        "name": "Research brief",
        "parts": [{ "text": "## A2A adoption this week\n\n1. ...\n\nSources: ..." }]
      }
    ]
  }
}

With the JSON-RPC binding, the same call is a standard JSON-RPC 2.0 request with "method": "SendMessage" and the same object in params.

Streaming, polling and push notifications

A2A is built for work that takes time. The client has three ways to follow a task:

  • Streaming: call SendStreamingMessage (or POST /message:stream) and read Server-Sent Events. You get the task, then status updates and artifact chunks as they arrive, ending with a terminal status.
  • Polling: call GetTask with the task ID until it reaches a terminal state.
  • Push notifications: give the agent a webhook URL and a token in the request's configuration. The agent posts status updates to your webhook, which suits jobs that run for minutes or hours, or clients that can't hold a connection open.

A streamed response looks like this:

text
data: {"task": {"id": "task-1", "contextId": "ctx-1", "status": {"state": "TASK_STATE_WORKING"}}}

data: {"artifactUpdate": {"taskId": "task-1", "contextId": "ctx-1", "artifact": {"parts": [{"text": "## Findings\n\n"}]}}}

data: {"statusUpdate": {"taskId": "task-1", "contextId": "ctx-1", "status": {"state": "TASK_STATE_COMPLETED"}}}

Authentication and security

A2A doesn't invent its own auth. Security schemes in the Agent Card follow the OpenAPI model, and each scheme is exactly one of:

  • API key (apiKeySecurityScheme), sent in a header, query parameter or cookie
  • HTTP auth (httpAuthSecurityScheme), such as Basic or Bearer
  • OAuth 2.0 (oauth2SecurityScheme)
  • OpenID Connect (openIdConnectSecurityScheme)
  • Mutual TLS (mtlsSecurityScheme)

The flow is:

  1. Read securitySchemes and securityRequirements from the Agent Card.
  2. Get credentials out of band, through whatever process the provider uses (a developer console, an OAuth flow, a signed contract).
  3. Send the credentials on every request using standard HTTP mechanisms.

The remote agent then decides what that caller is allowed to do. If a task hits something that needs more permission, it can move to TASK_STATE_AUTH_REQUIRED and wait.

Some practical habits:

  • Verify Agent Card signatures before trusting a card from someone else's domain.
  • Treat remote agents as untrusted input. Text in an artifact can contain prompt injection, the same as any web page. Don't let a remote agent's output trigger actions on your side without checks.
  • Scope credentials per agent. Give each remote agent its own key so you can revoke one without breaking the rest.
  • Log task IDs and context IDs. Agent-to-agent chains are hard to debug without a trail.

Remote agents vs local agents

A2A was designed for remote agents: agents that live behind someone else's HTTP endpoint, possibly in another company. That's where its features earn their keep, because you need discovery, auth, async tasks and opacity across an organisational boundary.

Inside one application, you often don't need A2A at all. If your planner, researcher and writer agents are functions in the same codebase, an agent framework's own handoff mechanism is simpler and faster. A useful rule of thumb:

  • Same process, same team: use your framework's internal handoffs.
  • Different service, different team or vendor: expose an A2A server and publish an Agent Card.
  • A capability with fixed inputs and outputs: expose it as an MCP tool or a plain API, not as an agent.

The official SDKs make exposing an agent straightforward. They exist for Python (pip install a2a-sdk), JavaScript (npm install @a2a-js/sdk), Go, Java, .NET and Rust, and frameworks such as Google's ADK, LangGraph and BeeAI can expose their agents as A2A servers.

A2A vs MCP

The A2A project describes the difference with a nice image: MCP is vertical, A2A is horizontal.

Diagram: an orchestrator agent delegates a task over A2A to a web research agent, which calls TinyFish (TinySearch, TinyFetch, TinyAgent, TinyBrowser) over MCP or the API to work on the live web
A2A connects agents to agents. MCP and APIs connect an agent to its tools.
  • MCP deepens one agent. Every MCP server you connect hands the agent another tool, resource or prompt. A coding assistant with GitHub, a database and a browser connected over MCP can do more on its own.
  • A2A connects agents across a boundary. The other agent might belong to another team or another company. Your agent asks it for help, and it works on the request with its own tools, which you never see.
QuestionUse MCPUse A2A
Is the other side a tool with defined inputs and outputs?YesNo
Does the other side reason, plan and keep state across turns?NoYes
Do you control the other side's code and tools?OftenOften not
Does the work take seconds or a single call?UsuallySometimes
Can the work take minutes or need follow-up questions?Possible with the Tasks extensionBuilt in

They are complementary, not competing. The A2A docs use an auto repair shop as the example: a customer's agent talks to the "shop manager" agent over A2A, the mechanic agent uses MCP to call its diagnostic scanner and repair manual, and the mechanic orders a part from a supplier's agent over A2A again. A2A connects the agents to each other, and MCP connects each agent to its own tools.

Both projects now sit under the Linux Foundation. Anthropic introduced MCP in November 2024 and donated it to the Agentic AI Foundation in December 2025, and the Linux Foundation's own A2A update describes the two as complementary layers.

A quick primer on MCP

If you're newer to the Model Context Protocol: an MCP host (an AI app like Claude Code or Cursor) creates an MCP client for each MCP server it connects to. Servers expose three core primitives:

  • Tools: functions the model can call
  • Resources: data the app can read for context
  • Prompts: reusable templates

Messages use JSON-RPC 2.0, over stdio for local servers or Streamable HTTP for remote ones. The MCP architecture docs are the best starting point. For hands-on picks, see our guide to the best MCP servers for Claude Code, and our honest write-up of why our own CLI beat our MCP server for some coding agents.

MCP vs API

People also ask how MCP differs from a normal API, and the answer matters for where A2A fits.

An API is written for developers. You read the docs, write code against fixed endpoints, and handle auth, errors and formats yourself. An MCP server wraps capabilities so an AI application can find and use them at runtime: the model sees a list of tools with names, descriptions and JSON Schema inputs, and decides when to call them.

Plain APIMCP
Built forDevelopers writing codeAI applications and their models
DiscoveryRead the docstools/list at runtime
Integration effortCustom code per APIOne client works with any MCP server
AuthPer APIStandard flows, OAuth recommended for remote servers
Best forDeterministic code paths, high volume, tight controlLetting a model pick tools during a conversation

MCP doesn't replace APIs. Most MCP servers call an API underneath. The same goes for A2A: a remote agent usually calls APIs and MCP tools to do its work. So the layers stack like this:

  1. A2A between agents
  2. MCP between an agent and its tools
  3. APIs underneath, doing the actual work

Worked example: delegating web research to a remote agent

Here's a pattern we see a lot. A company has an internal assistant that answers questions about competitors. It's good at the company's own data, but it can't reliably search the web, read current pages or operate sites with filters and forms. Instead of bolting all that onto the assistant, the team calls a separate web research agent over A2A.

The setup

  • Orchestrator (A2A client): the internal assistant. It decides when a question needs fresh web information.
  • Web research agent (A2A server): publishes the Agent Card shown earlier, with two skills, live-web-research and site-task.
  • Web layer: inside the research agent, every search, page read and browser action goes through one web API. In this example that's TinyFish.

Step 1: discover and check the card

python
import httpx

card = httpx.get("https://research.example.com/.well-known/agent-card.json").json()
skills = {s["id"] for s in card["skills"]}
assert "live-web-research" in skills

interface = card["supportedInterfaces"][0]  # first entry is preferred

Step 2: delegate the task

The orchestrator sends a message, streams progress, and asks for structured output by including a data part:

json
{
  "message": {
    "role": "ROLE_USER",
    "messageId": "3b8f1e2a-9c4d-4e5f-a6b7-c8d9e0f1a2b3",
    "parts": [
      { "text": "Find the current published pricing for the three competitors below and note any change since last month." },
      { "data": { "competitors": ["acme.com", "globex.com", "initech.com"], "format": "table" } }
    ]
  }
}

Step 3: inside the remote agent, the web layer does the work

The research agent's planner turns the task into web steps. Each step maps to one capability behind a single TinyFish API key:

  • TinySearch finds the right pages, such as each competitor's pricing page and recent announcements.
  • TinyFetch reads those pages and returns clean Markdown the model can quote from.
  • TinyAgent handles pages where the data sits behind interaction: a currency switcher, a plan toggle or a "show annual pricing" button.
  • TinyBrowser gives the agent a remote browser over CDP when you want to drive it yourself with Playwright or Puppeteer.
TinySearch returning ranked live results with titles, URLs and snippets
TinySearch: the remote agent's first step is finding the right pages

With the Python SDK, the core of that web layer is short:

python
# pip install tinyfish   |   export TINYFISH_API_KEY=...
from tinyfish import TinyFish

web = TinyFish()

def research(competitor: str) -> dict:
    # 1. Find the pricing page
    hits = web.search.query(f"{competitor} pricing", location="US", language="en")

    # 2. Read it as clean Markdown (top result here; a real agent would rank and check)
    page = web.fetch.get_contents(urls=[hits.results[0].url])

    # 3. If the page hides prices behind a toggle, let TinyAgent operate it
    run = web.agent.run(
        url=f"https://{competitor}/pricing",
        goal="Switch to annual billing and return each plan name with its price as JSON.",
    )
    return {"page": page, "annual_prices": run.result}

The remote agent's model writes the brief from those results, and the agent returns it to the orchestrator as an artifact: a Markdown table plus a data part with the raw numbers and source URLs. If a site needs a login the agent wasn't given, it moves the task to TASK_STATE_INPUT_REQUIRED or TASK_STATE_AUTH_REQUIRED instead of guessing.

Exact response fields vary by SDK version, so check the TinyFish docs when you wire this up. The shape of the workflow (search, then fetch, then act only when needed) stays the same.

Why split it this way

  • The orchestrator stays simple. It knows how to delegate and read artifacts. It doesn't need browsers, proxies or anti-bot handling.
  • The research agent owns web reliability. Search, fetch and browser sessions are one dependency with one key, instead of a scraper, a search API and a browser farm wired together by hand.
  • Costs stay predictable. TinySearch and TinyFetch are free within their rate limits (TinySearch at 30 requests a minute and 500 an hour, TinyFetch at 150 URLs a minute and 1,000 a day). TinyAgent costs $0.016 per step and TinyBrowser $0.002 per browser-minute, so you only pay when the job needs a real browser. Current rates are on our pricing page.
  • You can swap either side. Another team can call the same research agent over A2A from a different framework, and the orchestrator could switch to a different research agent by reading a different Agent Card.

If your agent runs inside an MCP host instead, the same web layer is available as an MCP server at https://agent.tinyfish.ai/mcp, with tools such as search, fetch_content, run_web_automation and create_browser_session. TinyFish doesn't ship an A2A server itself. It's the web infrastructure a remote agent calls. For more on choosing between the four, see which TinyFish API you should use.

Want to give your remote agent the live web? Start free with TinyFish: one API key for search, fetch, browser sessions and web agents.

When A2A is the wrong tool

A2A adds real moving parts: discovery, auth, task state and async delivery. Skip it when:

  • All your agents live in one service. Use your framework's handoffs.
  • The other side is really a function. A pricing lookup with fixed inputs is a tool. Expose it over MCP or a plain API.
  • You need hard latency guarantees. An agent-to-agent chain adds a model's thinking time at every hop.
  • You can't verify who the other agent is. Without signed cards or a trusted registry, you're sending work and data to an unknown party.

Common mistakes when starting with A2A

  1. Following pre-1.0 tutorials. Method names, part types and state names changed in 1.0. Check the spec version an SDK targets.
  2. Treating skills like function signatures. Skills describe what an agent is good at. Put strict input and output contracts in data parts and document them.
  3. Holding a connection open for long jobs. Use push notifications or polling for anything that can take minutes.
  4. Trusting artifacts blindly. Output from another agent is untrusted input. Validate it before acting on it.
  5. One credential for every agent. Scope keys per remote agent so you can rotate or revoke them independently.
  6. Rebuilding web access in every agent. Put search, fetch and browser work behind one web layer and let agents share it.

Getting started

  1. Read the A2A specification sections on the data model and your chosen binding.
  2. Install an SDK, for example pip install a2a-sdk, and run one of the official samples.
  3. Expose one agent with one clear skill and publish its Agent Card at /.well-known/agent-card.json.
  4. Call it from a second agent using SendMessage, then switch to streaming.
  5. Give the remote agent the tools it needs over MCP or APIs. For live web work, a free TinyFish key covers search and fetch from day one.

The short DeepLearning.AI course on A2A, built with Google Cloud and IBM Research, is a good next step if you prefer video. And if you're new to agents in general, start with what an AI agent is and how to build one.

Building multi-agent systems on the live web? Get your free TinyFish API key: TinySearch and TinyFetch are free, with $8 to start on TinyAgent and TinyBrowser.
AI disclosure

Content on this website may be created or refined with the assistance of AI tools and is subject to human editorial review.

FAQ

Questions, answered.

What is the A2A protocol?

Who owns the Agent2Agent protocol?

What is the difference between A2A and MCP?

Does A2A replace APIs?

Where is the Agent Card hosted?

What transports does A2A use?

How does authentication work in A2A?

Can an A2A agent browse the web?

Get started

Start building.

No credit card. No setup. Run your first operation in under a minute.

Get $8 in Wallet fundsRead the docs