Websites are written for two readers: people and search engines. A third one has arrived. AI agents that work on someone's behalf, compare offers, ask follow-up questions and pass on requests. They read pages well enough. What they cannot do reliably is talk to the business behind the page.
A2A is the protocol for exactly that conversation. Not between a person and a website, but between two agents: the one working for the customer and the one answering for the business.
A2A Is a Stable Standard Now#
A2A stands for Agent2Agent Protocol. Google launched it in April 2025, and in June 2025 the Linux Foundation took it on as an open project. Version 1.0 followed on March 12, 2026, the first release its makers call stable and ready for production. In August 2026, A2A joined the Agentic AI Foundation, the home the Linux Foundation runs for open agent standards. MCP lives there too.
More than 150 organizations back the protocol. When 1.0 came out, a technical steering committee with representatives of eight companies guided it: AWS, Cisco, Google, IBM Research, Microsoft, Salesforce, SAP and ServiceNow. On the practical side, Google Cloud, AWS with Bedrock AgentCore and Microsoft with Azure AI Foundry run A2A agents, and frameworks such as LangGraph, CrewAI and Pydantic AI speak it. Official SDKs exist for Python, JavaScript, Java, Go, .NET and Rust.
That shifts the question. A year ago it was whether A2A would last. Today it is what the agent card on your own site should say.
Find, Ask, Get an Answer#
The idea fits into three steps. An agent finds out what another agent can do. It sends a message. It gets back a task with a result, or with a question if something is missing.
Technically, A2A sits on JSON-RPC 2.0, a small and long-established way to call functions over HTTP. Version 1.0 describes the same operations for gRPC and for plain HTTP with JSON as well, so one agent can offer several routes to the same functions. These operations carry most of the work:
| Operation | What it does |
|---|---|
SendMessage | Sends a message and returns a task or a direct answer |
GetTask | Returns the current state of a task |
ListTasks | Lists tasks, for example those of one conversation |
CancelTask | Stops a task that is still running |
Around them sit operations for streaming (SendStreamingMessage, SubscribeToTask), for push notifications and for an extended agent card that only authenticated clients get to see. Anyone who built against version 0.3 knows SendMessage, GetTask and CancelTask as message/send, tasks/get and tasks/cancel.
A client states which version it speaks in the A2A-Version HTTP header. If the header is empty, the specification tells the server to treat the request as 0.3. That is how one server can serve both versions at the same address, and the agent card says so openly.
The Agent Card Is the Business Card#
Before one agent talks to another, it needs to know who is on the other side and what can be done there. That is the job of the agent card, a JSON file at /.well-known/agent-card.json on the agent's domain.
A simplified card for a restaurant, in the 1.0 format:
{
"name": "Pizzeria Roma",
"description": "Italian restaurant in Munich. Answers questions about the menu and takes table reservations.",
"supportedInterfaces": [
{
"url": "https://pizzeria-roma.example/a2a",
"protocolBinding": "JSONRPC",
"protocolVersion": "1.0"
}
],
"provider": {
"organization": "Pizzeria Roma",
"url": "https://pizzeria-roma.example"
},
"version": "1.0.0",
"capabilities": {
"streaming": false,
"pushNotifications": false
},
"defaultInputModes": ["text/plain", "application/json"],
"defaultOutputModes": ["text/plain", "application/json"],
"skills": [
{
"id": "make-reservation",
"name": "Table reservation",
"description": "Reserve a table with date, time and party size.",
"tags": ["reservation", "booking", "table"],
"examples": [
"Reserve a table for 4 people on Friday at 7 PM",
"Is there a table free tonight?"
]
},
{
"id": "view-menu",
"name": "Menu",
"description": "Current menu with prices and allergen information.",
"tags": ["menu", "food", "allergens"]
}
]
}
The biggest change compared with version 0.3 is supportedInterfaces. A 0.3 card named its main address in url, further transports in additionalInterfaces and one protocolVersion for the whole card. In 1.0, a single list carries every address together with its binding and the protocol version spoken there. An agent that serves 1.0 and 0.3 at the same address lists that URL twice, once per version. The field version is the version of the agent itself, not of the protocol.
The skills are what the card is really for. From them, a reading agent learns what it can ask for, in which format and with which kind of message. The more precise the description, the fewer wrong requests arrive.
Two fields matter as soon as trust comes into play. securitySchemes declares how a client has to authenticate, with the familiar options of the web: API key, HTTP authentication, OAuth 2, OpenID Connect or mutual TLS. And signatures can carry a JSON Web Signature over the card, so an agent can check that the card has not been altered and really comes from the provider it names. A card without a signature is still valid. It just proves less.
agents.json and the Agent Card Answer Different Questions#
The two files get mixed up a lot, and the difference is simple. agents.json describes which tools and HTTP endpoints a website offers. The agent card describes an agent you can talk to.
| agents.json | agent-card.json | |
|---|---|---|
| Question | What can this website do? | How do I talk to its agent? |
| Content | Tools with HTTP endpoints, methods and parameters | Skills, interfaces, capabilities, security |
| Protocol | None of its own, it describes REST endpoints | A2A over JSON-RPC, gRPC or HTTP with JSON |
| Origin | Community proposal | Google, now the Agentic AI Foundation |
| Status | No official standard | Specification at version 1.0 |
Both can sit side by side. An agent that finds a fitting tool in agents.json calls it directly. One that wants to hand over a task, get asked back and continue a conversation uses A2A. How agents.json works in detail is covered in our explainer on agents.json.
A2A and MCP Split the Work#
A2A is often mentioned in the same breath as MCP, and the obvious question is whether one replaces the other. It does not. The Agentic AI Foundation, which now hosts both, describes them as two layers. MCP connects an agent to tools, data and applications. A2A connects agents with each other, across companies and platforms.
For a business, that means two different doors. Through MCP, its knowledge and its actions become usable inside an assistant, for example when someone asks Claude about opening hours or free appointments. Through A2A, another agent can hand it a task, ask back and receive a result.
One point needs saying, because the name suggests otherwise: A2A is not a direct line into the chat window of Claude or ChatGPT. It connects agents that companies and platforms build. A large language model often runs inside those agents. Between them, they speak A2A.
A Walk Through Our Own Agent#
Our website carries an agent card, and the agent behind it answers in 1.0 and 0.3 at the same address. The card is signed, and the key to check it sits at /.well-known/jwks.json. That makes it a useful example, because every step below can be tried against the real thing.
Suppose someone tells their assistant: find me a web design studio on Mallorca and ask for an intro call. The agent fetches https://studiomeyer.io/.well-known/agent-card.json and finds the address of our agent and, among other skills, this one (shortened):
{
"name": "StudioMeyer",
"supportedInterfaces": [
{
"url": "https://studiomeyer.io/api/a2a",
"protocolBinding": "JSONRPC",
"protocolVersion": "1.0"
}
],
"skills": [
{
"id": "schedule-consultation",
"name": "Request a free intro call",
"description": "Sends a request for a free intro call to StudioMeyer. Needs name and email, optionally phone and topic, as a data part. Someone from StudioMeyer answers by email, written by a person and not by a machine; nothing is booked automatically. Select it with message.metadata.skillId = \"schedule-consultation\" or with a data part {\"skill\": \"schedule-consultation\"}.",
"inputModes": ["application/json"],
"outputModes": ["application/json"]
}
]
}
The agent picks the skill and sends its first message. It passes a name and a topic, but forgets the email address:
curl -s https://studiomeyer.io/api/a2a \
-H "Content-Type: application/json" \
-H "A2A-Version: 1.0" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "SendMessage",
"params": {
"message": {
"messageId": "msg-001",
"role": "ROLE_USER",
"parts": [
{
"data": {
"skill": "schedule-consultation",
"name": "Jane Doe",
"topic": "New website for a restaurant"
}
}
]
}
}
}'
The answer is a task that stops and asks (shortened):
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"task": {
"id": "task_0f953c4c-…",
"contextId": "ctx_bbf6ab0b-…",
"status": {
"state": "TASK_STATE_INPUT_REQUIRED",
"message": {
"messageId": "msg_989db7b4-…",
"role": "ROLE_AGENT",
"parts": [
{
"text": "To request a free intro call, send a data part with name and email, optionally phone and topic: {\"skill\": \"schedule-consultation\", \"name\": \"...\", \"email\": \"...\", \"topic\": \"...\"}"
}
]
}
}
}
}
}
The agent does not start over. It replies inside the same task, with the taskId and contextId from the answer, and sends all the details again:
{
"jsonrpc": "2.0",
"id": 2,
"method": "SendMessage",
"params": {
"message": {
"messageId": "msg-002",
"role": "ROLE_USER",
"taskId": "task_0f953c4c-…",
"contextId": "ctx_bbf6ab0b-…",
"parts": [
{
"data": {
"name": "Jane Doe",
"email": "jane@example.com",
"topic": "New website for a restaurant"
}
}
]
}
}
}
In this example the address is jane@example.com, and our agent asks once more. example.com is reserved for examples and never receives mail, so trying this out neither sends an email nor files a request. With a real address, the task ends as TASK_STATE_COMPLETED, the request reaches StudioMeyer, and a person answers by email. No machine writes that answer, and nothing gets booked automatically. The skill description says so. That is deliberate. An agent should only promise what actually happens behind it.
Plain text works as well. A message with a text part goes to our assistant, which answers in German, English or Spanish. Whoever sends the contextId along with the next message continues the same conversation, as long as it is still open. The full interface is documented on our developer page for agents.
A Task Always Knows Where It Stands#
A2A gives every task a clear state. In version 1.0 the names are:
TASK_STATE_SUBMITTED → TASK_STATE_WORKING → TASK_STATE_COMPLETED
→ TASK_STATE_FAILED
→ TASK_STATE_CANCELED
→ TASK_STATE_REJECTED
→ TASK_STATE_INPUT_REQUIRED
→ TASK_STATE_AUTH_REQUIRED
Completed, failed, canceled and rejected are final. Rejected means the agent decided not to carry out the task, at the start or later on. Input required and auth required only interrupt: the task waits for more input or for authentication and then continues under the same ID.
Input required is exactly what happened in our example. It is the moment an agent behaves like a good person on the phone. It does not hang up, it asks for what is missing.
Reach and Trust Are Still Open#
The support the A2A project reports comes from cloud platforms, enterprise software and agent frameworks. On the websites of small businesses, as far as I can see, an agent card is still rare. Anyone who publishes one today is early, not late.
Trust is the second open point. A signed card proves that it is unaltered and comes from the provider it names. It does not prove that the agent behind it is honest or does what it claims. Which agents you let in, and what you let them do, remains a decision every operator makes, with the usual tools of the web: authentication, limits and a look at the logs.
And agents still make mistakes when they fill in requests, even structured ones. A good agent on the other side absorbs that. It asks back instead of failing silently. The protocol provides the state for it. Using it is up to whoever builds the agent.
A Card Is a Promise#
An agent that reads a card believes it. It sends its requests the way the card describes, and it reports back to its person what the card claimed. A card that lists skills nobody behind it performs is worse than no card at all, because it produces errors where nobody is watching.
So a card should only carry what really answers. For us that means: every skill in the card can be executed, and one clear sentence says where the machine stops and a person takes over. The protocol is stable. What goes into the card is still a decision.
