Las webs se escriben para dos lectores: las personas y los buscadores. Ha llegado un tercero. Agentes de IA que trabajan por encargo de alguien, comparan ofertas, hacen preguntas y transmiten solicitudes. Leen las páginas bastante bien. Lo que no consiguen de forma fiable es hablar con el negocio que hay detrás.
A2A es el protocolo para exactamente esa conversación. No entre una persona y una web, sino entre dos agentes: el que trabaja para el cliente y el que responde por el negocio.
A2A ya es un estándar estable#
A2A significa Agent2Agent Protocol. Google lo presentó en abril de 2025, y en junio de 2025 la Linux Foundation lo acogió como proyecto abierto. El 12 de marzo de 2026 salió la versión 1.0, la primera que sus autores consideran estable y lista para producción. En agosto de 2026, A2A se unió a la Agentic AI Foundation, la casa que la Linux Foundation mantiene para los estándares abiertos de agentes. Allí vive también MCP.
Más de 150 organizaciones respaldan el protocolo. Cuando salió la 1.0, lo guiaba un comité técnico con representantes de ocho empresas: AWS, Cisco, Google, IBM Research, Microsoft, Salesforce, SAP y ServiceNow. En la práctica, Google Cloud, AWS con Bedrock AgentCore y Microsoft con Azure AI Foundry ejecutan agentes A2A, y frameworks como LangGraph, CrewAI y Pydantic AI lo hablan. Hay SDK oficiales para Python, JavaScript, Java, Go, .NET y Rust.
Eso cambia la pregunta. Hace un año era si A2A iba a durar. Hoy es qué debería decir la agent card de tu propia web.
Encontrar, preguntar, recibir respuesta#
La idea cabe en tres pasos. Un agente averigua qué puede hacer otro agente. Envía un mensaje. Recibe una tarea con un resultado, o con una pregunta si falta algo.
Técnicamente, A2A se apoya en JSON-RPC 2.0, una forma pequeña y muy asentada de llamar funciones a través de HTTP. La versión 1.0 describe las mismas operaciones también para gRPC y para HTTP simple con JSON, así que un agente puede ofrecer varios caminos hacia las mismas funciones. Estas operaciones cargan con la mayor parte del trabajo:
| Operación | Qué hace |
|---|---|
SendMessage | Envía un mensaje y devuelve una tarea o una respuesta directa |
GetTask | Devuelve el estado actual de una tarea |
ListTasks | Lista tareas, por ejemplo las de una conversación |
CancelTask | Detiene una tarea que sigue en curso |
Alrededor hay operaciones para streaming (SendStreamingMessage, SubscribeToTask), para notificaciones push y para una agent card ampliada que solo ven los clientes autenticados. Quien construyó contra la versión 0.3 conoce SendMessage, GetTask y CancelTask como message/send, tasks/get y tasks/cancel.
Un cliente indica qué versión habla en la cabecera HTTP A2A-Version. Si la cabecera está vacía, la especificación indica al servidor que trate la petición como 0.3. Así un mismo servidor puede atender las dos versiones en la misma dirección, y la agent card lo dice abiertamente.
La agent card es la tarjeta de visita#
Antes de que un agente hable con otro, necesita saber quién está al otro lado y qué se puede hacer allí. Esa es la función de la agent card, un archivo JSON en /.well-known/agent-card.json dentro del dominio del agente.
Una tarjeta simplificada para un restaurante, en el formato de la 1.0:
{
"name": "Pizzeria Roma",
"description": "Restaurante italiano en Múnich. Responde preguntas sobre la carta y acepta reservas de mesa.",
"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": "Reserva de mesa",
"description": "Reservar una mesa con fecha, hora y número de personas.",
"tags": ["reservation", "booking", "table"],
"examples": [
"Reserva una mesa para 4 personas el viernes a las 19:00",
"¿Queda alguna mesa libre esta noche?"
]
},
{
"id": "view-menu",
"name": "Carta",
"description": "Carta actual con precios e información sobre alérgenos.",
"tags": ["menu", "food", "allergens"]
}
]
}
El cambio más importante frente a la versión 0.3 es supportedInterfaces. Una tarjeta de la 0.3 indicaba su dirección principal en url, otros transportes en additionalInterfaces y un único protocolVersion para toda la tarjeta. En la 1.0, una sola lista recoge cada dirección junto con su binding y la versión del protocolo que se habla allí. Un agente que atiende la 1.0 y la 0.3 en la misma dirección indica esa URL dos veces, una por versión. El campo version es la versión del propio agente, no la del protocolo.
Los skills son la verdadera razón de ser de la tarjeta. Por ellos, un agente que la lee sabe qué puede pedir, en qué formato y con qué tipo de mensaje. Cuanto más precisa es la descripción, menos peticiones erróneas llegan.
Dos campos importan en cuanto entra en juego la confianza. securitySchemes declara cómo tiene que autenticarse un cliente, con las opciones conocidas de la web: clave de API, autenticación HTTP, OAuth 2, OpenID Connect o TLS mutuo. Y signatures puede llevar una JSON Web Signature sobre la tarjeta, para que un agente compruebe que la tarjeta no se ha alterado y que viene de verdad del proveedor que indica. Una tarjeta sin firma sigue siendo válida. Solo demuestra menos.
agents.json y la agent card responden a preguntas distintas#
Los dos archivos se confunden a menudo, y la diferencia es sencilla. agents.json describe qué herramientas y endpoints HTTP ofrece una web. La agent card describe un agente con el que se puede hablar.
| agents.json | agent-card.json | |
|---|---|---|
| Pregunta | ¿Qué puede hacer esta web? | ¿Cómo hablo con su agente? |
| Contenido | Herramientas con endpoints HTTP, métodos y parámetros | Skills, interfaces, capacidades, seguridad |
| Protocolo | Ninguno propio, describe endpoints REST | A2A sobre JSON-RPC, gRPC o HTTP con JSON |
| Origen | Propuesta de la comunidad | Google, hoy la Agentic AI Foundation |
| Estado | Sin estándar oficial | Especificación en la versión 1.0 |
Los dos pueden convivir. Un agente que encuentra una herramienta adecuada en agents.json la llama directamente. Uno que quiere entregar una tarea, recibir preguntas y continuar una conversación usa A2A. Cómo funciona agents.json en detalle lo explicamos en nuestro artículo sobre agents.json.
A2A y MCP se reparten el trabajo#
A2A suele mencionarse junto a MCP, y la pregunta obvia es si uno sustituye al otro. No lo hace. La Agentic AI Foundation, que hoy acoge a los dos, los describe como dos capas. MCP conecta un agente con herramientas, datos y aplicaciones. A2A conecta agentes entre sí, más allá de empresas y plataformas.
Para un negocio, eso significa dos puertas distintas. A través de MCP, su conocimiento y sus acciones se pueden usar dentro de un asistente, por ejemplo cuando alguien le pregunta a Claude por el horario o por citas libres. A través de A2A, otro agente puede entregarle una tarea, hacerle preguntas y recibir un resultado.
Hay algo que conviene decir con claridad, porque el nombre sugiere otra cosa: A2A no es una línea directa a la ventana de chat de Claude o ChatGPT. Conecta agentes creados por empresas y plataformas. Dentro de esos agentes suele trabajar un gran modelo de lenguaje. Entre ellos hablan A2A.
Un recorrido por nuestro propio agente#
Nuestra web tiene una agent card, y el agente que hay detrás responde en 1.0 y en 0.3 en la misma dirección. La tarjeta está firmada, y la clave para comprobarla está en /.well-known/jwks.json. Eso la convierte en un buen ejemplo, porque cada paso de abajo se puede probar con el agente real.
Supongamos que alguien le dice a su asistente: búscame un estudio de diseño web en Mallorca y pide una primera llamada. El agente consulta https://studiomeyer.io/.well-known/agent-card.json y encuentra la dirección de nuestro agente y, entre otros skills, este (abreviado):
{
"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"]
}
]
}
El agente elige el skill y envía su primer mensaje. Incluye un nombre y un tema, pero olvida el correo electrónico:
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": "Nueva web para un restaurante"
}
}
]
}
}
}'
La respuesta es una tarea que se detiene y pregunta (abreviada):
{
"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\": \"...\"}"
}
]
}
}
}
}
}
El agente no empieza de cero. Responde dentro de la misma tarea, con el taskId y el contextId de la respuesta, y vuelve a enviar todos los datos:
{
"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": "Nueva web para un restaurante"
}
}
]
}
}
}
En este ejemplo la dirección es jane@example.com, y nuestro agente vuelve a preguntar. example.com está reservado para ejemplos y nunca recibe correo, así que al probarlo no se envía ningún correo ni se registra ninguna solicitud. Con una dirección real, la tarea termina como TASK_STATE_COMPLETED, la solicitud llega a StudioMeyer y una persona responde por correo electrónico. Esa respuesta no la escribe ninguna máquina, y no se reserva nada de forma automática. La descripción del skill lo dice. Es intencionado. Un agente solo debería prometer lo que de verdad ocurre detrás de él.
El texto libre también funciona. Un mensaje con una parte de texto llega a nuestro asistente, que responde en alemán, inglés o español. Quien envía el contextId con el siguiente mensaje continúa la misma conversación, mientras siga abierta. La interfaz completa está documentada en nuestra página para desarrolladores de agentes.
Una tarea siempre sabe en qué punto está#
A2A da a cada tarea un estado claro. En la versión 1.0 los estados se llaman así:
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 y rejected son definitivos. Rejected significa que el agente ha decidido no hacer la tarea, al principio o más adelante. Input required y auth required solo interrumpen: la tarea espera más datos o una autenticación y después continúa con el mismo ID.
Input required es justo lo que pasó en nuestro ejemplo. Es el momento en que un agente se comporta como una buena persona al teléfono. No cuelga, pregunta por lo que falta.
El alcance y la confianza siguen abiertos#
El respaldo que comunica el proyecto A2A viene de plataformas en la nube, software empresarial y frameworks de agentes. En las webs de los pequeños negocios, por lo que veo, una agent card todavía es rara. Quien publica una hoy llega pronto, no tarde.
La confianza es el segundo punto abierto. Una tarjeta firmada demuestra que no se ha alterado y que viene del proveedor que indica. No demuestra que el agente que hay detrás sea honesto ni que haga lo que dice. Qué agentes dejas entrar y qué les dejas hacer sigue siendo una decisión de cada operador, con las herramientas habituales de la web: autenticación, límites y un vistazo a los registros.
Y los agentes siguen cometiendo errores al rellenar peticiones, incluso las estructuradas. Un buen agente al otro lado lo absorbe. Pregunta en lugar de fallar en silencio. El protocolo trae el estado para ello. Usarlo depende de quien construye el agente.
Una tarjeta es una promesa#
Un agente que lee una tarjeta se la cree. Envía sus peticiones tal como la tarjeta las describe e informa a su persona de lo que la tarjeta afirmaba. Una tarjeta con skills que nadie ejecuta detrás es peor que no tener ninguna, porque produce errores donde nadie mira.
Por eso en una tarjeta solo debería estar lo que de verdad responde. Para nosotros eso significa: cada skill de la tarjeta se puede ejecutar, y una frase clara dice dónde termina la máquina y empieza una persona. El protocolo es estable. Lo que va en la tarjeta sigue siendo una decisión.
