A2A Protocol
Discover an agent, send it work, follow the task, read its errors. Pinned to A2A 1.0.1.
- Concepts and terms
- Tasks and commands
- Annotated code
- Diagrams
- Defaults and numbers
- Troubleshooting
- Questions and tips
Tasks over JSON-RPC#
| Task | Code |
|---|---|
| Discover an agent | GET / |
| Send and wait | "method": "SendMessage" |
| Send and return at once | "configuration": {"returnImmediately": true} |
| Poll a task | "method": "GetTask", |
| Stream a task | "method": "SendStreamingMessage" with Accept: text/event-stream |
| Reattach to a stream | "method": "SubscribeToTask", |
| Answer a question | "message": {"contextId": "<ctx>", |
| Register a webhook | "taskPushNotificationConfig": {"url": "<url>", |
From a2a-101 capture: 01-agent-cards.http, a2a-101 capture: 03-blocking-task.http, a2a-101 capture: 04-polling.http, a2a-101 capture: 05-streaming.http, a2a-101 capture: 06-input-required.http, a2a-101 capture: 10-cancel.http, a2a-101 capture: 14-resubscribe.http, a2a-101 capture: 15-push.http
One SendMessage request#
POST /a2a/jsonrpc HTTP/1.1the JSONRPC url from the cardHost: localhost:41241Content-Type: application/jsonA2A-Version: 1.0required on every request{"jsonrpc": "2.0", "id": 1, "method": "SendMessage", "params": { "message": {"messageId": "<uuid>",the client mints it "role": "ROLE_USER", "parts": [{"text": "<request>"}]}, "configuration": {"returnImmediately": true}}}omit to blockFrom a2a-101 capture: 04-polling.http, a2a-101 §5.4, a2a-101 §1.2, a2a-101 §4.1
HTTP+JSON routes#
| Command | What it does |
|---|---|
POST / | SendMessage |
POST / | SendStreamingMessage, a stream of StreamResponse |
GET / | GetTask. historyLength goes in the query |
GET / | ListTasks |
POST / | CancelTask |
POST / | SubscribeToTask. Accept GET too |
POST / | CreateTaskPushNotificationConfig |
GET / | GetExtendedAgentCard |
Capture kit and conformance#
python3 run.pythree agents and a client, writes out/python3 run.py --checkcapture again and comparegit clone --filter=blob:none https://github.com/a2aproject/a2a-tck.gitcd a2a-tckgit checkout 1.0.0.alpha2the TCK tag the manual ranuv venv && source .venv/bin/activateuv pip install -e ../run_tck.py --sut-host http://localhost:9999reads the card, tests each bindingThe capture kit agents#
From a2a-101 capture: README.md, a2a-101 §2.2, a2a-101 §4.6, a2a-101 §7.1
Task states#
- TASK_STATE_SUBMITTED
- active. Wait, poll, or subscribe.
- TASK_STATE_WORKING
- active. As for a submitted task.
- TASK_STATE_INPUT_REQUIRED
- interrupted. Answer with the same
taskIdandcontextId. - TASK_STATE_AUTH_REQUIRED
- interrupted. Approval comes outside A2A. Subscribe or poll.
- TASK_STATE_COMPLETED
- terminal. Read the artifacts.
- TASK_STATE_FAILED
- terminal. Fix the input and start a new task.
- TASK_STATE_CANCELED
- terminal. Start a new task in the same context.
- TASK_STATE_REJECTED
- terminal. Stop and follow the status message.
From a2a-101 §R3
Tips#
- Send
A2A-Version: 1.0on every request, with no patch number. - Set
returnImmediately: truewhen you poll, subscribe, or wait for a webhook. - Take the task id and context id from the first frame.
- Skip any operation whose capability flag is absent or
false. - Answer a task the caller cannot access with
TaskNotFoundError. - Process push notifications idempotently. Duplicates can arrive.
From a2a-101 §5.4, a2a-101 §4.1, a2a-101 §1.2, a2a-101 §2.2, a2a-101 §R4, a2a-101 §4.6
One streamed task#
From a2a-101 §1.2
Error codes#
| Command | What it does |
|---|---|
-32001 TaskNotFoundError | HTTP 404, gRPC NOT_FOUND |
-32002 TaskNotCancelableError | HTTP 400, FAILED_PRECONDITION |
-32003 PushNotificationNotSupportedError | HTTP 400, FAILED_PRECONDITION |
-32004 UnsupportedOperationError | HTTP 400, FAILED_PRECONDITION |
-32005 ContentTypeNotSupportedError | HTTP 400, INVALID_ARGUMENT |
-32009 VersionNotSupportedError | HTTP 400, FAILED_PRECONDITION |
-32601 MethodNotFoundError | JSON-RPC only |
-32602 InvalidParamsError | HTTP 400, INVALID_ARGUMENT |
From a2a-101 §R4
Defaults#
| Setting | Default | Note |
|---|---|---|
returnImmediately | false | A send waits for a terminal or interrupted state |
historyLength | Unset | Server returns its default amount |
includeArtifacts | false | ListTasks omits artifacts |
pageSize in ListTasks | 50 | The maximum is 100 |
Missing A2A-Version | 0.3 | A 1.0 server refuses it |
| JSON-RPC error status | 200 OK | Kit and SDK. The spec sets none |
| Push token header | X-A2A-Notification-Token | Kit and SDK choice |
| Kit request timeout | 15 seconds | The spec sets none |
From a2a-101 §4.1, a2a-101 §4.3, a2a-101 §5.4, a2a-101 §R4, a2a-101 §4.6, a2a-101 §7.1
Troubleshooting#
| Symptom | Cause | Fix |
|---|---|---|
-32009 Protocol version not supported | No A2A-Version header, read as 0.3 | Send A2A-Version: 1.0 |
-32601 Method not found | A 0.3 name such as message/send | Use SendMessage |
-32602 Invalid parameters | The message has no messageId | Mint a messageId per message |
-32005 Content type not supported | An image/png part | Send a mode the card accepts |
-32004 on a message or a subscribe | The task is terminal | Start a new task |
-32002 Task cannot be canceled | The task already ended | Read it with GetTask |
| HTTP 401 on GetExtendedAgentCard | No bearer token | Send Authorization: Bearer <token> |
| TCK JSON-RPC records fail with 404 | The TCK adds a trailing slash to url | Post to the exact url |
From a2a-101 capture: 11-errors.http, a2a-101 capture: 10-cancel.http, a2a-101 capture: 18-extended-card.http, a2a-101 §5.4, a2a-101 §7.4, a2a-101 §R3, a2a-101 §7.3
Glossary#
- Agent card
- JSON that describes an agent, usually at
/.well-known/agent-card.json. - Task
- the unit of work a server creates for a message, with an
id. - Context
- a conversation that groups tasks and messages under one
contextId. - Message
- one turn, with a
messageId, arole, and parts. - Part
- smallest unit of content:
text,raw,url, ordata. - Artifact
- an output of a task, made of parts. Long ones arrive in chunks.
- Push notification
- an HTTP POST of a
StreamResponseto a client webhook. - Service parameter
- a per-request key such as
A2A-Version, sent as a header.
From a2a-101 §R5
Q&A#
- What does a send return?
- One
taskor onemessage. A message alone is a direct reply. - Does
lastChunkend the task? - No. It closes one artifact only.
- Why 200 OK on a JSON-RPC error?
- The spec sets no status. The kit and the SDK send
200 OK. - Which interface does a client use?
- The first
supportedInterfacesentry that it speaks. - How did 0.3
blockingchange? returnImmediatelyreplaced it, and a send now waits.
From a2a-101 §R1, a2a-101 §7.4, a2a-101 §1.2, a2a-101 §R4, a2a-101 §2.2