Module 5
24 min read

Agent-to-Agent Communication and A2A

A tool is a function your agent controls. Another agent is a colleague with its own mind, memory, and schedule. This module covers how agents talk to each other as peers: the A2A protocol, how it models work, how agents find and trust one another, and how to build an agent that plays well with others.

Why agents need to talk to agents

In the previous module, your agent reached out to the world through tools, usually exposed over MCP. A tool is predictable: you send arguments, it runs some code, it returns a result. The agent decides everything; the tool just executes.

Now picture a travel-booking agent that needs a visa check. Another company has already built a visa agent. It reasons about edge cases, asks follow-up questions, keeps its own case history, and sometimes takes hours because a human reviewer is involved. Wrapping that as a "tool" breaks down quickly. It isn't a function. It's an opaque agent: it has its own reasoning, its own state, its own tools and data you never see, and its own timeline.

Calling a tool (MCP)Delegating to an agent (A2A)
Who decides howYour agentThe remote agent
What you see insideA schema for inputs and outputsOnly a public description of skills; internals stay private
DurationUsually one request and one responseCan run for minutes, hours or days, with pauses
ConversationRarely; mostly one-shotMulti-turn: the remote agent can ask for more input
StateMostly stateless from the caller's viewA stateful task with a lifecycle
Shared memory or toolsNot applicableNone. Agents exchange messages and artifacts only
Tools are things your agent uses. Agents are peers your agent works with.

A common mental model in 2026: MCP is vertical (an agent reaching down to its tools and data) and A2A is horizontal (an agent reaching sideways to another agent). Most serious systems use both. Your agent uses MCP to read your calendar, and A2A to hand a sub-problem to a specialist agent run by another team or company.

Why opacity is a feature

Agents that don't share memory or internals can be built by different vendors, on different frameworks and models, and still cooperate. The remote agent keeps its proprietary prompts, data and tools private. You get its results without needing to trust or understand its implementation, which is how most human businesses work with each other too.

A short history of A2A

The Agent2Agent (A2A) protocol moved quickly from one company's proposal to a neutrally governed standard. Knowing the timeline helps you read older tutorials, which often describe pre-1.0 field names.

  1. 1

    April 2025: Google announces A2A

    Launched with more than 50 partners as an open protocol for agents to collaborate across vendors and frameworks.

  2. 2

    June 2025: moved to the Linux Foundation

    Google transferred the spec and SDKs to the Linux Foundation, so no single company controls the protocol.

  3. 3

    Late summer 2025: IBM's ACP merges in

    IBM Research's Agent Communication Protocol (ACP, from the BeeAI project) merged into A2A rather than competing with it. ACP users got a migration path: an Agent Card replaces the ACP manifest, and A2A task methods replace ACP endpoints. Sources differ on whether this was August or September.

  4. 4

    Early 2026: v1.0, the first stable spec

    After 0.1, 0.2.x and 0.3, the spec reached 1.0.0, adding signed Agent Cards, multi-tenancy, a Protocol Buffers type system and three official bindings. In April 2026 the Linux Foundation reported 150+ supporting organizations and native support in Azure AI Foundry, Copilot Studio, Amazon Bedrock AgentCore and Google Cloud.

  5. 5

    August 27, 2026: A2A joins the Agentic AI Foundation

    A2A became a Growth Stage project of the Linux Foundation's Agentic AI Foundation (AAIF), which already hosted MCP, goose and AGENTS.md. A2A keeps its own Technical Steering Committee. The protocols sit under one roof but were not merged.

Two different ACPs

IBM's Agent Communication Protocol (merged into A2A) is unrelated to the Agentic Commerce Protocol from OpenAI and Stripe, which you'll meet in Module 7. Same acronym, different jobs.

The Agent Card: an agent's business card

Before two agents can work together, the client agent needs to know what the remote agent can do, where to reach it, and how to authenticate. A2A puts all of this in one JSON document called the Agent Card. By convention it is published at https://{domain}/.well-known/agent-card.json.

Identity

name, description, version, and an optional provider with the organization behind the agent.

Interfaces

supportedInterfaces lists each endpoint URL with its protocolBinding and protocolVersion, in order of preference.

Capabilities

Flags such as streaming, pushNotifications and extendedAgentCard, plus any declared extensions.

Skills

What the agent is good at: each skill has an id, name, description, tags, example prompts, and accepted input and output media types.

Security

securitySchemes describes how to authenticate, and securityRequirements says which schemes and scopes are needed.

Signatures

New in v1.0: optional JWS signatures let a client verify that the card really comes from the claimed provider and hasn't been altered.

{
  "name": "Visa Requirements Agent",
  "description": "Checks entry and visa requirements for a traveler's itinerary and asks follow-up questions when details are missing.",
  "supportedInterfaces": [
    { "url": "https://visa.example.com/a2a/v1", "protocolBinding": "JSONRPC", "protocolVersion": "1.0" },
    { "url": "https://visa.example.com/a2a/json", "protocolBinding": "HTTP+JSON", "protocolVersion": "1.0" }
  ],
  "provider": {
    "organization": "Example Travel Compliance Inc.",
    "url": "https://www.example.com"
  },
  "version": "2.1.0",
  "capabilities": {
    "streaming": true,
    "pushNotifications": true,
    "extendedAgentCard": true
  },
  "securitySchemes": {
    "corpOidc": {
      "openIdConnectSecurityScheme": {
        "openIdConnectUrl": "https://login.example.com/.well-known/openid-configuration"
      }
    }
  },
  "securityRequirements": [{ "schemes": { "corpOidc": { "list": ["openid", "visa.read"] } } }],
  "defaultInputModes": ["text/plain", "application/json"],
  "defaultOutputModes": ["text/plain", "application/json"],
  "skills": [
    {
      "id": "visa-check",
      "name": "Visa requirement check",
      "description": "Given a passport country and an itinerary, reports which visas or entry permits are required.",
      "tags": ["travel", "visa", "compliance"],
      "examples": ["Do I need a visa to visit Japan for 10 days on a Canadian passport?"],
      "inputModes": ["text/plain", "application/json"],
      "outputModes": ["application/json"]
    }
  ],
  "signatures": [
    { "protected": "eyJhbGciOiJFUzI1NiIs...", "signature": "QFdkNLNszlGj3z3u..." }
  ]
}
An example v1.0 Agent Card, modeled on the sample card in the A2A specification. The signature values are truncated placeholders.

Notice what the card doesn't contain: no system prompt, no list of internal tools, no model name. It is a public contract, not a description of internals. Agents can also offer an extended Agent Card that is only returned to authenticated clients (the GetExtendedAgentCard operation), for example to reveal premium skills to paying customers.

Write skills for a model to read

The client deciding whether to call your agent is often an LLM reading your card. Clear skill descriptions and realistic examples matter as much as a good tool description does in MCP. Vague skills lead to wrong delegations.

Tasks, messages, parts and artifacts

A2A models work with four core objects. Once you understand how they fit together, the rest of the protocol is mostly plumbing.

Task

A stateful unit of work with a server-generated id, a current status, any output artifacts, and optional history. Tasks are how A2A handles long-running work.

Message

One turn of communication, with a role (ROLE_USER from the client, ROLE_AGENT from the server), a messageId, and one or more parts. Messages carry instructions, questions and status updates.

Part

The content inside a message or artifact. A part holds text, a file (inline bytes as raw, or a url), or structured data (any JSON value), with an optional mediaType and filename.

Artifact

A task's output, made of parts and identified by an artifactId. Reports, images and JSON results go here, separate from the conversation.

The split between messages and artifacts is deliberate. The spec says results should be returned as artifacts, not messages. Messages are for talking about the work ("Which dates?", "Still working, 60% done"), and artifacts are the work. This lets a client store deliverables reliably while treating chatter as disposable.

Related tasks and messages share a contextId, which groups a whole conversation. A client can continue a specific task by sending its taskId, or start a new task in the same conversation by sending only the contextId.

StateKindWhat it means
TASK_STATE_SUBMITTEDActiveThe agent has received and acknowledged the task.
TASK_STATE_WORKINGActiveThe agent is processing it.
TASK_STATE_INPUT_REQUIREDInterruptedThe agent needs more information from the client before it can continue.
TASK_STATE_AUTH_REQUIREDInterruptedThe agent needs an authorization (for example an OAuth token or a human approval) that the client must supply.
TASK_STATE_COMPLETEDTerminalFinished successfully; artifacts hold the results.
TASK_STATE_FAILEDTerminalFinished with an error.
TASK_STATE_CANCELEDTerminalCanceled before completion, usually by the client.
TASK_STATE_REJECTEDTerminalThe agent declined to do the task at all.
Task lifecycle states in A2A v1.0. In JSON they appear as ProtoJSON enum names like these; older docs use lowercase names such as input-required.

The two interrupted states are what make A2A feel like working with a colleague. A tool either succeeds or fails. An agent can stop and say "I need your departure city" or "I need you to authorize access to your calendar," then pick up where it left off once you answer.

A task exchange, step by step

Here is a multi-turn exchange using the HTTP+JSON binding. The travel agent (the client) asks the visa agent (the server) a question, and the visa agent needs one more detail.

POST /a2a/json/message:send HTTP/1.1
Host: visa.example.com
Content-Type: application/a2a+json
A2A-Version: 1.0
Authorization: Bearer <token>

{
  "message": {
    "role": "ROLE_USER",
    "messageId": "msg-1",
    "parts": [{ "text": "Does my traveler need a visa for a 10-day trip to Japan?" }]
  }
}

HTTP/1.1 200 OK
Content-Type: application/a2a+json

{
  "task": {
    "id": "task-42",
    "contextId": "ctx-7",
    "status": {
      "state": "TASK_STATE_INPUT_REQUIRED",
      "message": {
        "role": "ROLE_AGENT",
        "messageId": "msg-2",
        "parts": [{ "text": "Which passport does the traveler hold?" }]
      }
    }
  }
}
Step 1: the client sends a message and gets back a task that is waiting for input. Shapes follow the examples in the A2A v1.0 spec.
POST /a2a/json/message:send HTTP/1.1
Host: visa.example.com
Content-Type: application/a2a+json
A2A-Version: 1.0
Authorization: Bearer <token>

{
  "message": {
    "taskId": "task-42",
    "role": "ROLE_USER",
    "messageId": "msg-3",
    "parts": [{ "data": { "passportCountry": "CA", "durationDays": 10 } }]
  }
}

HTTP/1.1 200 OK
Content-Type: application/a2a+json

{
  "task": {
    "id": "task-42",
    "contextId": "ctx-7",
    "status": { "state": "TASK_STATE_COMPLETED" },
    "artifacts": [{
      "artifactId": "art-1",
      "name": "Visa assessment",
      "parts": [{ "data": { "visaRequired": false, "notes": "Illustrative output only" } }]
    }]
  }
}
Step 2: the client answers on the same taskId, this time with a structured data part, and the task completes with an artifact. The artifact content is illustrative, not real visa guidance.

The same operations exist in every binding. In JSON-RPC, you'd POST {"jsonrpc": "2.0", "method": "SendMessage", "params": {...}} to the JSON-RPC URL from the card instead.

OperationWhat it doesHTTP+JSON route
SendMessageStart or continue a task; returns a Task or a direct MessagePOST /message:send
SendStreamingMessageSame, but streams updates as they happenPOST /message:stream
GetTaskFetch a task's current state and artifacts (polling)GET /tasks/{id}
ListTasksList tasks, filterable by context or stateGET /tasks
CancelTaskAsk the agent to stop workPOST /tasks/{id}:cancel
SubscribeToTaskRe-attach a stream to an existing taskPOST /tasks/{id}:subscribe
Push notification configCreate, get, list and delete webhook configs/tasks/{id}/pushNotificationConfigs
GetExtendedAgentCardFetch the authenticated, more detailed cardGET /extendedAgentCard
Core A2A v1.0 operations. Routes are relative to the interface URL in the Agent Card.

Note that a remote agent may also reply with a plain Message instead of a Task, for quick answers that don't need tracking. Your client should handle both.

Streaming, push notifications and bindings

Because agent work can take a long time, A2A gives clients three ways to follow a task. Pick based on how long the work runs and whether the client can stay connected.

Polling

Call GetTask periodically. Simplest to build and works everywhere, but adds latency and wasted requests.

Streaming (SSE)

SendStreamingMessage or SubscribeToTask returns Server-Sent Events: the task first, then status and artifact updates in order. Best for interactive UIs. Requires capabilities.streaming.

Push notifications

The client registers a webhook URL, and the agent POSTs updates there. Best for server-to-server work that runs for hours. Requires capabilities.pushNotifications.

HTTP/1.1 200 OK
Content-Type: text/event-stream

data: {"task": {"id": "task-77", "contextId": "ctx-9", "status": {"state": "TASK_STATE_WORKING"}}}

data: {"artifactUpdate": {"taskId": "task-77", "contextId": "ctx-9", "artifact": {"artifactId": "a1", "parts": [{"text": "## Visa summary\n"}]}}}

data: {"statusUpdate": {"taskId": "task-77", "contextId": "ctx-9", "status": {"state": "TASK_STATE_COMPLETED"}}}
A streaming response. In v1.0 the task must be the first event, and the state itself (not a separate flag) tells you the stream is finished.

Streams are independent of the task. If a connection drops, the task keeps running, and the client can reconnect with SubscribeToTask. Several clients can watch the same task at once. One caveat from the spec: a reconnecting client may miss some status messages, so anything important should end up in artifacts or task history, not only in transient updates.

Bindings are how the abstract operations map to wire formats. v1.0 defines three official ones, all functionally equivalent, plus rules for custom bindings:

BindingCard valueGood fit
JSON-RPC 2.0 over HTTPJSONRPCThe original style; easy to proxy and debug
gRPCGRPCHigh-throughput internal services, strong typing from the .proto files
HTTP+JSON (REST)HTTP+JSONFamiliar resource-style URLs, plays well with API gateways

A server lists the bindings it supports in supportedInterfaces, in preference order. The client picks the first one it also supports. Clients send an A2A-Version header so the server can reject versions it doesn't speak.

Security schemes and what v1.0 changed

A2A doesn't invent its own auth. It reuses standard web security, declared in the Agent Card using an OpenAPI-like structure. The supported security schemes are:

  • API key, sent in a header, query parameter or cookie.
  • HTTP authentication, such as Basic or Bearer tokens.
  • OAuth 2.0, including authorization code, client credentials and device code flows.
  • OpenID Connect, pointing at a provider's discovery document.
  • Mutual TLS, where both sides present certificates.

Credentials are obtained out of band (for example, through a normal OAuth flow) and sent with each request. Inside a task, an agent can ask for more authorization by moving to TASK_STATE_AUTH_REQUIRED, which hands the job of getting a token or human approval back to the client.

If you learned A2A from 2025 tutorials, these are the v1.0 changes to watch for:

ChangeWhy it matters
Signed Agent Cards using JWS (RFC 7515) over a JCS-canonicalized card (RFC 8785)A client can cryptographically check that a card came from the claimed provider and wasn't tampered with in transit or in a registry.
Native tenant field on each interfaceOne endpoint can host many agents or customers. Clients copy the tenant value from the card into every request.
Protocol Buffers as the source of truth, with ProtoJSON as the canonical JSONOne schema generates JSON-RPC, gRPC and REST types consistently. Enums look like TASK_STATE_COMPLETED, and JSON fields are camelCase.
The kind discriminator was removedPolymorphism now uses oneof-style fields: a part simply has text, raw, url or data; a response has task or message.
TaskSubscription renamed to SubscribeToTask; extended card RPC is GetExtendedAgentCardUpdate method names when migrating.
The final flag was removed from status update events, and the task must be the first event in a streamClients decide a stream is done by looking at the task state.
Modernized OAuth flowsBrings the OAuth options in line with current practice.
Key v1.0 changes, per the spec and the AAIF builder's guide.

How card signing works

The provider removes the signatures field and default values, canonicalizes the JSON with JCS so every implementation produces identical bytes, then signs it. The protected header carries alg, kid and optionally a jku URL for the public key set. The client repeats the canonicalization and verifies. Canonicalization is the subtle part: without it, harmless differences such as key order or whitespace would break signatures.

Discovery and trust

How does an agent find another agent in the first place? The spec describes three mechanisms:

Well-known URI

Fetch /.well-known/agent-card.json from a domain you already know. Simple and decentralized, and it ties the agent to a domain.

Registries and catalogs

Query a curated directory, often run inside a company or by a platform, to search agents by skill or tag.

Direct configuration

Hard-code the card URL or content. Common for tightly controlled partnerships and internal systems.

Finding an agent is the easy part. Trusting it is harder. A card is a claim, and a remote agent is an opaque system whose output your agent will read and act on. Think about trust in layers:

  1. 1

    Is this card authentic?

    Fetch over HTTPS and verify card signatures where present. Pin or allow-list the keys and providers you expect.

  2. 2

    Is this the agent I meant?

    Domain, provider and signature together tell you who stands behind the agent. A registry listing alone is not proof.

  3. 3

    Am I authorized, and is it?

    Use the declared security schemes. Give each remote agent the narrowest credentials it needs, and authenticate the agents that call you.

  4. 4

    Can I trust what it sends back?

    Treat every message and artifact from another agent as untrusted input, just like web content. It may contain prompt injections meant to hijack your agent.

  5. 5

    What happens if it misbehaves?

    Set timeouts, cancel runaway tasks, validate structured outputs against a schema, and require human confirmation before acting on high-stakes results.

A signed card is not a safe agent

Signatures prove who published a card, not that the agent behaves well or that its outputs are clean. The OWASP Top 10 for Agentic Applications lists insecure inter-agent communication and cascading failures as distinct risks: one compromised or confused agent can pass bad instructions down a chain. Module 11 covers defenses in depth.

Caching matters too. Cards change rarely, so servers should send Cache-Control and ETag headers, and clients should make conditional requests rather than re-downloading the card before every call.

A2A among its neighbors

A2A isn't the only effort to connect agents. The others mostly solve different problems, and several are complementary. Here's how the main ones compare as of October 2026.

ProtocolBacked byMain jobIdentity and discoveryStatus
MCPStarted by Anthropic; now at AAIFAgent to tools and data (vertical)OAuth 2.1 with Client ID Metadata Documents; MCP RegistryWidely adopted; 2026-07-28 spec made the core stateless
A2AStarted by Google; Linux Foundation, now at AAIFAgent to agent (horizontal): tasks, messages, artifactsAgent Cards at well-known URLs, optionally JWS-signed; standard web authv1.0 stable; native in major clouds
ANPOpen-source community founded by Gaowei ChangDecentralized agent networking with meta-protocol negotiationDecentralized identifiers (did:wba) and semantic discoveryDraft; discussed in the W3C AI Agent Protocol Community Group
AGNTCYLaunched by Cisco with LangChain and Galileo; Linux Foundation since July 2025"Internet of Agents" infrastructure: directory, messaging, identity, observabilityOASF schemas for directories; verifiable agent identity; SLIM messagingActive; 75+ contributing organizations
NLWebMicrosoft (Build 2025)Turns a website into a natural-language /ask endpointSite-level; every instance is also an MCP serverAvailable, including a managed offering from Cloudflare
Note that a W3C Community Group is not the W3C standards track, so ANP is not a W3C standard.

A practical reading of the table: use MCP to give your agent tools, A2A when you hand work to another agent, and NLWeb if you want your website to be queryable by agents. ANP and AGNTCY are worth watching for open, decentralized networks of agents and for infrastructure such as directories and secure messaging, but most production agent-to-agent traffic in 2026 runs on A2A.

MCP and A2A together

A common architecture: your agent exposes itself over A2A to other agents, and internally uses MCP servers for its own tools. Callers see one opaque agent with a card. You can swap internal tools freely without changing your public contract.

Designing an agent other agents can use

Most frameworks now speak A2A natively (Google ADK, Microsoft Agent Framework, Amazon Bedrock AgentCore Runtime, and others), and official SDKs exist for Python, JavaScript, Java, Go and .NET. So the hard part isn't the wire format. It's the design. Here's a checklist for building an A2A agent that other agents can rely on.

  1. 1

    Scope skills narrowly and describe them precisely

    Each skill should do one recognizable job. Write descriptions and examples for an LLM reader, and declare accurate input and output media types.

  2. 2

    Return results as artifacts with structure

    Put deliverables in artifacts, use data parts with a documented shape when callers will parse the result, and keep messages for questions and progress.

  3. 3

    Use the interrupted states honestly

    Ask for missing information with TASK_STATE_INPUT_REQUIRED rather than guessing. Use TASK_STATE_REJECTED for requests outside your scope, so the caller can route elsewhere.

  4. 4

    Support the long haul

    If work can take more than a few seconds, return a task early, support streaming and push notifications, and make GetTask and CancelTask work reliably.

  5. 5

    Secure by default

    Require authentication, request minimal scopes, sign your Agent Card, and serve per-customer agents through the tenant field instead of mixing data.

  6. 6

    Treat callers' input as untrusted

    Messages from other agents can carry prompt injections. Keep your agent's own powerful tools behind confirmation or policy checks, and never let a caller's text override your instructions.

  7. 7

    Version your contract

    Bump the card version when skills change, keep old skills working during transitions, and use caching headers so clients notice updates.

  8. 8

    Make it observable

    Log task IDs, context IDs and state transitions end to end. When something goes wrong across three agents and two companies, a shared task ID is how you find it.

Do you even need a second agent?

A2A is the right tool when the other side really is an independent agent, owned by another team or company, or needing its own long-running process. If you control both sides and the work is a simple function, an MCP tool is simpler and cheaper. Module 6 looks at when multi-agent designs pay off.

Key takeaways

  • Tools are functions your agent controls; remote agents are opaque peers with their own reasoning, state and timelines. MCP covers the first, A2A the second.
  • A2A went from a Google proposal (April 2025) to the Linux Foundation, absorbed IBM's ACP, reached a stable v1.0, and joined the Agentic AI Foundation on August 27, 2026.
  • The Agent Card at /.well-known/agent-card.json advertises identity, skills, interfaces and security; v1.0 cards can be signed with JWS over JCS-canonicalized JSON.
  • Work happens in tasks with a clear lifecycle, including the interrupted states INPUT_REQUIRED and AUTH_REQUIRED; results belong in artifacts, while messages carry the conversation.
  • Follow long tasks by polling, SSE streaming or push notifications, over JSON-RPC, gRPC or HTTP+JSON bindings.
  • Discovery is easy and trust is hard: verify cards, use least-privilege auth, and treat everything another agent sends you as untrusted input.

Sources & further reading