A2A Protocol

The Agent-to-Agent (A2A) protocol enables agents to communicate with each other using a standardized JSON-RPC 2.0 interface. It defines how agents are discovered, how tasks are created and managed, and how messages flow between client and server agents.

Protocol Foundation

A2A is built on JSON-RPC 2.0 over HTTP. Every request is a JSON-RPC call with a method name and params, and every response contains a result or error.

{
  "jsonrpc": "2.0",
  "method": "message/send",
  "id": "req-001",
  "params": {
    "message": {
      "role": "user",
      "parts": [{ "kind": "text", "text": "Analyze this repository" }]
    }
  }
}

Key protocol properties:

  • Transport: HTTP POST
  • Format: JSON-RPC 2.0
  • Streaming: Server-Sent Events (SSE) via message/stream
  • Protocol Version: 0.3.0

Agent Card (Discovery)

Every A2A agent publishes an Agent Card at /.well-known/agent.json. This is the entry point for discovery — clients fetch the Agent Card to learn what the agent does, how to authenticate, and what capabilities it supports.

GET https://my-agent.fly.dev/.well-known/agent.json
{
  "name": "GitHub Repo Analyzer",
  "description": "Analyzes GitHub repositories for code complexity, dependencies, and security vulnerabilities.",
  "protocolVersion": "0.3.0",
  "version": "1.0.0",
  "url": "https://my-agent.fly.dev/api/a2a",
  "skills": [
    {
      "id": "analyze-repo",
      "name": "Analyze Repository",
      "description": "Analyzes a GitHub repository and returns a structured report.",
      "tags": ["github", "analysis", "security", "dependencies"],
      "inputModes": ["text/plain"],
      "outputModes": ["text/plain"]
    }
  ],
  "capabilities": {
    "streaming": true,
    "extensions": [
      {
        "uri": "https://github.com/google-agentic-commerce/a2a-x402/blob/main/spec/v0.2",
        "required": true
      }
    ]
  }
}

The Agent Card contains:

FieldDescription
nameHuman-readable agent name
descriptionWhat the agent does
protocolVersionA2A protocol version (e.g., "0.3.0")
urlThe A2A endpoint URL
skillsArray of capabilities the agent offers
capabilitiesStreaming support and extensions
securitySchemesAuthentication methods

For complete Agent Card configuration, see the Agent Card Guide.

Task States

A Task is the central unit of work in A2A. It tracks the lifecycle of a request from creation to completion.

StateDescription
submittedTask has been created and is queued
workingAgent is actively processing
completedTask finished successfully
failedTask encountered an error
input-requiredAgent needs more information from the client (used for X402 payment requests)
canceledTask was canceled by the client

The input-required state is particularly important for X402 payments. When an agent requires payment, it sets the task state to input-required with payment requirements in the metadata. The client responds with a payment submission, and the task transitions to working then completed.

JSON-RPC Methods

message/send

Send a message and receive a complete task response.

Request:

{
  "jsonrpc": "2.0",
  "method": "message/send",
  "id": "req-001",
  "params": {
    "message": {
      "role": "user",
      "parts": [{ "kind": "text", "text": "Analyze https://github.com/example/repo" }]
    }
  }
}

Response:

{
  "jsonrpc": "2.0",
  "id": "req-001",
  "result": {
    "kind": "task",
    "id": "task-abc-123",
    "contextId": "ctx-456",
    "status": {
      "state": "completed",
      "timestamp": "2025-01-15T10:30:00Z",
      "message": {
        "kind": "message",
        "role": "agent",
        "parts": [{ "kind": "text", "text": "Here is the analysis report..." }]
      }
    }
  }
}

message/stream

Send a message and receive a streaming response via Server-Sent Events.

Request: Same as message/send.

Response: SSE stream with status-update and message events:

data: {"kind":"status-update","taskId":"task-123","status":{"state":"working"}}

data: {"kind":"message","role":"agent","parts":[{"kind":"text","text":"Analyzing..."}]}

data: {"kind":"status-update","taskId":"task-123","status":{"state":"completed"}}

tasks/get

Retrieve the current state of an existing task.

{
  "jsonrpc": "2.0",
  "method": "tasks/get",
  "id": "req-002",
  "params": {
    "id": "task-abc-123"
  }
}

tasks/cancel

Cancel an in-progress task.

{
  "jsonrpc": "2.0",
  "method": "tasks/cancel",
  "id": "req-003",
  "params": {
    "id": "task-abc-123"
  }
}

Response Structure

All responses follow the JSON-RPC 2.0 format. Successful responses contain a result field; errors contain an error field.

Task Response

{
  "jsonrpc": "2.0",
  "id": "req-001",
  "result": {
    "kind": "task",
    "id": "task-abc-123",
    "contextId": "ctx-456",
    "status": {
      "state": "completed",
      "timestamp": "2025-01-15T10:30:00Z",
      "message": {
        "kind": "message",
        "messageId": "msg-789",
        "role": "agent",
        "taskId": "task-abc-123",
        "contextId": "ctx-456",
        "parts": [{ "kind": "text", "text": "Response content" }],
        "metadata": {}
      }
    },
    "artifacts": []
  }
}

Message Parts

Messages contain an array of parts, each with a kind:

KindDescription
textPlain text content
dataStructured data (JSON)
fileFile attachment with MIME type

Error Response

{
  "jsonrpc": "2.0",
  "id": "req-001",
  "error": {
    "code": -32600,
    "message": "Invalid Request"
  }
}

Standard JSON-RPC 2.0 error codes:

CodeMeaning
-32700Parse error
-32600Invalid request
-32601Method not found
-32602Invalid params
-32603Internal error

@a2a-js/sdk Implementation

The @a2a-js/sdk package provides a complete server-side implementation of the A2A protocol.

Core Server Components

import type { AgentCard } from '@a2a-js/sdk';
import {
  DefaultRequestHandler,
  InMemoryTaskStore,
  JsonRpcTransportHandler,
} from '@a2a-js/sdk/server';
ClassRole
JsonRpcTransportHandlerParses JSON-RPC requests and routes to handler methods
DefaultRequestHandlerManages task lifecycle with Agent Card + Task Store + Executor
InMemoryTaskStoreIn-memory persistence for tasks and their message history

The AgentExecutor Interface

Your agent implements the AgentExecutor interface:

import type { AgentExecutor, ExecutionEventBus, RequestContext } from '@a2a-js/sdk/server';

export class MyExecutor implements AgentExecutor {
  async execute(requestContext: RequestContext, eventBus: ExecutionEventBus): Promise<void> {
    // Your logic here
  }

  async cancelTask(taskId: string, eventBus: ExecutionEventBus): Promise<void> {
    // Handle cancellation
  }
}

The RequestContext provides:

  • userMessage— The incoming message
  • taskId— The task identifier
  • contextId— The conversation context
  • task— The full task object (with history, if resuming)

EventBus Publishing Pattern

The Executor communicates back to the client through the ExecutionEventBus. This is an event-driven pattern — you publish events and the SDK handles serialization and transport.

Publishing a Task Event

const taskEvent: Task = {
  kind: 'task',
  id: taskId,
  contextId,
  status: { state: 'submitted', timestamp: new Date().toISOString() },
};
eventBus.publish(taskEvent);

Publishing a Status Update

const statusUpdate: TaskStatusUpdateEvent = {
  kind: 'status-update',
  taskId,
  contextId,
  final: true,
  status: {
    state: 'completed',
    timestamp: new Date().toISOString(),
    message: {
      kind: 'message',
      messageId: crypto.randomUUID(),
      role: 'agent',
      taskId,
      contextId,
      parts: [{ kind: 'text', text: 'Done!' }],
    },
  },
};
eventBus.publish(statusUpdate);

Publishing a Message Directly

const reply: Message = {
  kind: 'message',
  messageId: crypto.randomUUID(),
  role: 'agent',
  taskId,
  contextId,
  parts: [{ kind: 'text', text: responseText }],
  metadata: { /* any metadata */ },
};
eventBus.publish(reply);
eventBus.finished();

Important

Call eventBus.finished() when your executor is done. For status updates, set final: true on the last event.

Extensions Mechanism

A2A supports extensions that add capabilities to the base protocol. Extensions are declared in the Agent Card's capabilities.extensions array.

{
  "capabilities": {
    "extensions": [
      {
        "uri": "https://github.com/google-agentic-commerce/a2a-x402/blob/main/spec/v0.2",
        "description": "Supports payments using the x402 protocol for on-chain settlement.",
        "required": true
      }
    ]
  }
}

Clients activate extensions by including the URI in the X-A2A-Extensions HTTP header:

X-A2A-Extensions: https://github.com/google-agentic-commerce/a2a-x402/blob/main/spec/v0.2

Setting required: true means the client must understand and implement this extension to interact with the agent. The X402 payments extension is the primary extension used in the A2X ecosystem.

For full X402 payment protocol details, see X402 Payments.

Further Reading