Related Documentation:
The Agent-to-Agent (A2A) protocol is an open standard for enabling communication between opaque agentic systems. Here's a comprehensive technical overview to help you get oriented:
A2A follows a client-server model with three key actors:
- User: The end-user (human or service) using an agentic system
- Client: The entity requesting action from an agent on behalf of the user
- Remote Agent (Server): The "blackbox" agent implementing the A2A server
- Uses HTTP for transport with JSON-RPC 2.0 as the data exchange format
- Supports Server-Sent Events (SSE) for streaming updates
- Push notifications for disconnected operation
interface AgentCard {
name: string; // Human-readable name
description: string; // Optional description
url: string; // Base URL for the agent
provider?: { // Optional provider info
organization: string;
url: string;
};
version: string; // Agent version
documentationUrl?: string; // Optional documentation URL
capabilities: { // Supported features
streaming?: boolean; // SSE support
pushNotifications?: boolean; // Push notification support
stateTransitionHistory?: boolean; // Status change history
};
authentication: { // Auth requirements (OpenAPI-compatible)
schemes: string[]; // e.g., "Basic", "Bearer", "OAuth2"
credentials?: string; // For private cards
};
defaultInputModes: string[]; // Supported input MIME types
defaultOutputModes: string[]; // Supported output MIME types
skills: AgentSkill[]; // Available capabilities
}interface AgentSkill {
id: string; // Unique skill identifier
name: string; // Human-readable name
description?: string; // Optional description
tags?: string[]; // Categorization tags
examples?: string[]; // Example prompts/queries
inputModes?: string[]; // Override default input modes
outputModes?: string[]; // Override default output modes
}interface Task {
id: string; // Unique task identifier
sessionId: string; // Session grouping multiple tasks
status: TaskStatus; // Current state
history?: Message[]; // Previous messages
artifacts?: Artifact[]; // Results generated by the agent
metadata?: Record<string, any>; // Extension metadata
}
interface TaskStatus {
state: TaskState;
message?: Message; // Optional status message
timestamp?: string; // ISO datetime
}
type TaskState = "submitted" | "working" | "input-required" |
"completed" | "canceled" | "failed" | "unknown";interface Message {
role: "user" | "agent"; // Who sent the message
parts: Part[]; // Content pieces
metadata?: Record<string, any>; // Extension metadata
}Represents a piece of content, which can be:
// Text part
interface TextPart {
type: "text";
text: string;
metadata?: Record<string, any>;
}
// File part
interface FilePart {
type: "file";
file: {
name?: string;
mimeType?: string;
// One of:
bytes?: string; // base64 encoded content
uri?: string; // reference to content
};
metadata?: Record<string, any>;
}
// Data part (structured)
interface DataPart {
type: "data";
data: Record<string, any>;
metadata?: Record<string, any>;
}interface Artifact {
name?: string; // Optional name
description?: string; // Optional description
parts: Part[]; // Content pieces
metadata?: Record<string, any>; // Extension metadata
index: number; // Position in result set
append?: boolean; // For streaming updates
lastChunk?: boolean; // Final chunk indicator
}interface PushNotificationConfig {
url: string; // Callback URL
token?: string; // Unique task/session token
authentication?: { // Auth requirements
schemes: string[];
credentials?: string;
};
}- Agents host their AgentCard at
https://{base-url}/.well-known/agent.json - Clients can use DNS resolution and HTTP GET to retrieve the card
- Enterprise environments may use private registries/catalogs
// Request
{
"jsonrpc": "2.0",
"id": 1,
"method": "tasks/send",
"params": {
"id": "de38c76d-d54c-436c-8b9f-4c2703648d64",
"message": {
"role": "user",
"parts": [{
"type": "text",
"text": "tell me a joke"
}]
},
"metadata": {}
}
}// Request
{
"jsonrpc": "2.0",
"id": 1,
"method": "tasks/get",
"params": {
"id": "de38c76d-d54c-436c-8b9f-4c2703648d64",
"historyLength": 10,
"metadata": {}
}
}// Request
{
"jsonrpc": "2.0",
"id": 1,
"method": "tasks/cancel",
"params": {
"id": "de38c76d-d54c-436c-8b9f-4c2703648d64",
"metadata": {}
}
}// Request
{
"jsonrpc": "2.0",
"id": 1,
"method": "tasks/pushNotification/set",
"params": {
"id": "de38c76d-d54c-436c-8b9f-4c2703648d64",
"pushNotificationConfig": {
"url": "https://example.com/callback",
"authentication": {
"schemes": ["jwt"]
}
}
}
}// Request
{
"jsonrpc": "2.0",
"id": 1,
"method": "tasks/pushNotification/get",
"params": {
"id": "de38c76d-d54c-436c-8b9f-4c2703648d64"
}
}// Request
{
"method": "tasks/sendSubscribe",
"params": {
"id": "de38c76d-d54c-436c-8b9f-4c2703648d64",
"message": {
"role": "user",
"parts": [{
"type": "text",
"text": "write a long paper"
}]
}
}
}
// Streaming responses
data: {
"jsonrpc": "2.0",
"id": 1,
"result": {
"id": "de38c76d-d54c-436c-8b9f-4c2703648d64",
"status": {
"state": "working",
"timestamp": "2025-04-02T16:59:25.331844"
},
"final": false
}
}
data: {
"jsonrpc": "2.0",
"id": 1,
"result": {
"id": "de38c76d-d54c-436c-8b9f-4c2703648d64",
"artifact": {
"parts": [
{"type": "text", "text": "<content chunk 1>"}
],
"index": 0,
"append": false,
"lastChunk": false
}
}
}// Request
{
"method": "tasks/resubscribe",
"params": {
"id": "de38c76d-d54c-436c-8b9f-4c2703648d64",
"metadata": {}
}
}A2A supports complex multi-turn conversations through its task state management:
- Client sends initial task request
- Agent responds with
input-requiredstatus when more input is needed - Client sends additional input using the same task ID
- Process repeats until task is completed
// Response with input-required
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"id": "de38c76d-d54c-436c-8b9f-4c2703648d64",
"sessionId": "c295ea44-7543-4f78-b524-7a38915ad6e4",
"status": {
"state": "input-required",
"message": {
"role": "agent",
"parts": [{
"type": "text",
"text": "Select a phone type (iPhone/Android)"
}]
}
},
"metadata": {}
}
}A2A supports requesting and receiving structured data:
// Request for structured output
{
"jsonrpc": "2.0",
"id": 9,
"method": "tasks/send",
"params": {
"id": "de38c76d-d54c-436c-8b9f-4c2703648d64",
"message": {
"role": "user",
"parts": [{
"type": "text",
"text": "Show me a list of my open IT tickets",
"metadata": {
"mimeType": "application/json",
"schema": {
"type": "array",
"items": {
"type": "object",
"properties": {
"ticketNumber": { "type": "string" },
"description": { "type": "string" }
}
}
}
}
}]
}
}
}Standard JSON-RPC error codes plus A2A-specific codes:
| Error Code | Message | Description |
|---|---|---|
| -32700 | JSON parse error | Invalid JSON was sent |
| -32600 | Invalid Request | Request payload validation error |
| -32601 | Method not found | Not a valid method |
| -32602 | Invalid params | Invalid method parameters |
| -32603 | Internal error | Internal JSON-RPC error |
| -32001 | Task not found | Task not found with the provided id |
| -32002 | Task cannot be canceled | Task cannot be canceled by the remote agent |
| -32003 | Push notifications not supported | Push Notification is not supported by the agent |
| -32004 | Unsupported operation | Operation is not supported |
| -32005 | Incompatible content types | Incompatible content types between client and an agent |
Error response format:
interface ErrorMessage {
code: number;
message: string;
data?: any;
}- Authentication is handled at the HTTP level, not in A2A payloads
- Follows OpenAPI Authentication specification
- Supports OAuth, JWT, Basic Auth, API keys, etc.
- Uses standard HTTP response codes (401, 403) for auth failures
For secure push notifications:
- Challenge Verification: Agents should verify push notification URLs by issuing a GET challenge with a validation token
- Authentication: Use JWT, OAuth, or symmetric key signing for notification authenticity
- Replay Prevention: Use timestamps in push notifications to prevent replay attacks
- Key Rotation: Implement key rotation for long-lived notification channels
- Opaque Execution: Agents don't share internal thoughts/plans/tools
- Enterprise Ready: Design for auth, security, privacy, tracing, monitoring
- Async First: Support for very long-running tasks
- Modality Agnostic: Handle different content types appropriately
- Extensibility: Use metadata fields for custom extensions
- Model Context Protocol (MCP) is complementary to A2A
- Use MCP for connecting agents to tools (function calling)
- Use A2A for agent-to-agent communication
- Model A2A agents as MCP resources represented by their AgentCard
- Implementation Discovery: Support standard URL patterns (/.well-known/agent.json)
- Proper Status Updates: Keep clients informed with appropriate task states
- Secure Authentication: Implement industry-standard authentication
- Robust Error Handling: Provide meaningful error messages
- Proper Content Negotiation: Honor client's requested input/output modes
- Clean Task Management: Implement retention policies for completed tasks
- Streaming Efficiently: Use chunked responses efficiently
- Push Notification Verification: Always verify push notification endpoints
- (Advanced) Task Decomposition: For complex tasks, consider implementing internal planning logic to break down the request into smaller sub-tasks that can be executed sequentially or in parallel, potentially involving multiple tools or remote agents. Synthesize the results before responding to the original client.
- (Advanced) Intent Clarification: Before committing to complex execution plans, consider adding a step where the agent verifies its understanding of an ambiguous request by asking the client for clarification (e.g., using the
input-requiredstate).
Sample implementations are available in the A2A GitHub repository for:
- Google Agent Developer Kit (ADK)
- CrewAI
- LangGraph
- Genkit
Each sample demonstrates different aspects of the A2A protocol and can serve as a reference for your implementation.