MCP Connects Agents to Tools. A2A Connects Agents to Agents - Here's How to Debug It. A developer published a debugging field guide for the Agent2Agent (A2A) protocol, contrasting it with MCP: MCP connects agents to tools and resources, while A2A connects agents to other agents through long-lived, stateful tasks. The guide documents that A2A 1.0 and 0.3 are not wire-compatible — method names differ (e.g., SendMessage vs. message/send) and 1.0 adds JSON-RPC, HTTP+JSON (REST) and gRPC bindings — and walks through fetching an agent's public Agent Card at /.well-known/agent-card.json and tracking a task through states like working, input-required, completed and failed. MCP got the headlines, and deservedly so: it gave agents a standard way to call tools — search the docs, query the database, hit an API. But tools are only half of a multi-agent system. The other half is agents talking to each other : a support agent handing off to a billing agent, a research agent That's the job of the Agent2Agent A2A protocol. And the moment you try to debug an A2A call, you discover it's nothing like pointing curl at a REST route: This article is the debugging field guide I wish existed — and how to inspect an A2A conversation the same way you inspect an HTTP request. | | MCP | A2A | |---|---|---| | Connects | an agent to tools and resources | an agent to another agent | | Unit of work | a tool call | a message that starts a task | | Typical shape | request/response, short-lived | long-lived, stateful, often streaming | | Discovery | tool list | an Agent Card describing skills and auth | If MCP is "call this function," A2A is "delegate this to a capable counterpart and track the job." The first thing that looks like a server bug is often just a version mismatch. A2A 1.0 and 0.3 are explicitly not wire-compatible — the JSON-RPC method names differ: | Capability | A2A 1.0 | A2A 0.3 | |---|---|---| | Send a message | SendMessage | message/send | | Stream a message | SendStreamingMessage | message/stream | | Get a task | GetTask | tasks/get | | Cancel a task | CancelTask | tasks/cancel | | Subscribe to updates | SubscribeToTask | tasks/resubscribe | | Authenticated card | GetExtendedAgentCard | agent/getAuthenticatedExtendedCard | A 1.0 client sending message/send will be rejected by a 1.0 server, and vice versa. Before you inspect payloads, confirm both sides agree on the version. A2A 1.0 also defines three bindings — JSON-RPC , HTTP+JSON REST and gRPC — while 0.3 here is JSON-RPC only. Switching bindings changes the envelope: JSON-RPC wraps everything; REST and gRPC take the bare params object with no jsonrpc / id wrapper. If you paste a JSON-RPC body into a REST binding, that's a malformed request, not an agent failure. You don't guess an agent's endpoint or capabilities. You fetch its public Agent Card, conventionally served at: {endpoint}/.well-known/agent-card.json The card tells you what the agent can do its skills , where it lives, which transport it supports, and what authentication it expects. In a debugging tool this is a one-click "fetch the public card" step — inspect the card JSON first, because half of "the agent ignored my request" bugs are really "I sent a method this agent never advertised." This is the conceptual shift from REST. You don't call an endpoint and get the result synchronously. You send a message , and the agent creates a task that moves through states like working , input-required , completed and failed . You then GetTask , ListTasks , CancelTask , or subscribe to updates. A minimal A2A 1.0 SendMessage over JSON-RPC looks like this: { "jsonrpc": "2.0", "id": "a2a-0001", "method": "SendMessage", "params": { "message": { "messageId": "a2a-msg-0001", "role": "ROLE USER", "parts": { "text": "Where is order A-10293?" } } } } The same message on 0.3 is a different shape — lowercase role, a typed part, and an explicit message kind: { "jsonrpc": "2.0", "id": "a2a-0001", "method": "message/send", "params": { "message": { "messageId": "a2a-msg-0001", "role": "user", "kind": "message", "parts": { "kind": "text", "text": "Where is order A-10293?" } } } } Task follow-ups take the task id: { "jsonrpc": "2.0", "id": "a2a-0002", "method": "GetTask", "params": { "id": "