{"slug": "mcp-connects-agents-to-tools-a2a-connects-agents-to-agents-here-s-how-to-debug", "title": "MCP Connects Agents to Tools. A2A Connects Agents to Agents - Here's How to Debug It.", "summary": "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.", "body_md": "MCP got the headlines, and deservedly so: it gave agents a standard way to call\n\n**tools** — search the docs, query the database, hit an API. But tools are only\n\nhalf 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\n\nThat's the job of the **Agent2Agent (A2A)** protocol. And the moment you try to\n\ndebug an A2A call, you discover it's nothing like pointing curl at a REST route:\n\nThis article is the debugging field guide I wish existed — and how to inspect an\n\nA2A conversation the same way you inspect an HTTP request.\n\n|  | MCP | A2A | \n|---|---|---|\n| Connects | an agent to **tools and resources** | an agent to **another agent** | \n| Unit of work | a tool call | a message that starts a **task** | \n| Typical shape | request/response, short-lived | long-lived, stateful, often streaming | \n| Discovery | tool list | an **Agent Card** describing skills and auth | \n\nIf MCP is \"call this function,\" A2A is \"delegate this to a capable counterpart\n\nand track the job.\"\n\nThe first thing that looks like a server bug is often just a version mismatch.\n\nA2A **1.0** and **0.3** are explicitly not wire-compatible — the JSON-RPC\n\nmethod names differ:\n\n| Capability | A2A 1.0 | A2A 0.3 | \n|---|---|---|\n| Send a message | `SendMessage` | `message/send` | \n| Stream a message | `SendStreamingMessage` | `message/stream` | \n| Get a task | `GetTask` | `tasks/get` | \n| Cancel a task | `CancelTask` | `tasks/cancel` | \n| Subscribe to updates | `SubscribeToTask` | `tasks/resubscribe` | \n| Authenticated card | `GetExtendedAgentCard` | `agent/getAuthenticatedExtendedCard` | \n\nA 1.0 client sending `message/send` will be rejected by a 1.0 server, and vice\n\nversa. Before you inspect payloads, confirm both sides agree on the version.\n\nA2A 1.0 also defines three bindings — **JSON-RPC**, **HTTP+JSON (REST)** and\n\n**gRPC** — while 0.3 here is JSON-RPC only. Switching bindings changes the\n\nenvelope: JSON-RPC wraps everything; REST and gRPC take the bare `params`\n\nobject with no `jsonrpc`/` id` wrapper. If you paste a JSON-RPC body into a REST\n\nbinding, that's a malformed request, not an agent failure.\n\nYou don't guess an agent's endpoint or capabilities. You fetch its public Agent\n\nCard, conventionally served at:\n\n```\n{endpoint}/.well-known/agent-card.json\n```\n\nThe card tells you what the agent can do (its skills), where it lives, which\n\ntransport it supports, and what authentication it expects. In a debugging tool\n\nthis is a one-click \"fetch the public card\" step — inspect the card JSON first,\n\nbecause half of \"the agent ignored my request\" bugs are really \"I sent a method\n\nthis agent never advertised.\"\n\nThis is the conceptual shift from REST. You don't call an endpoint and get the\n\nresult synchronously. You send a **message**, and the agent creates a **task**\n\nthat moves through states like `working`, `input-required`, `completed` and\n\n`failed`. You then `GetTask`, `ListTasks`, `CancelTask`, or subscribe to\n\nupdates.\n\nA minimal A2A **1.0** `SendMessage` over JSON-RPC looks like this:\n\n```\n{\n  \"jsonrpc\": \"2.0\",\n  \"id\": \"a2a-0001\",\n  \"method\": \"SendMessage\",\n  \"params\": {\n    \"message\": {\n      \"messageId\": \"a2a-msg-0001\",\n      \"role\": \"ROLE_USER\",\n      \"parts\": [{ \"text\": \"Where is order A-10293?\" }]\n    }\n  }\n}\n```\n\nThe same message on **0.3** is a different shape — lowercase role, a typed\n\npart, and an explicit message kind:\n\n```\n{\n  \"jsonrpc\": \"2.0\",\n  \"id\": \"a2a-0001\",\n  \"method\": \"message/send\",\n  \"params\": {\n    \"message\": {\n      \"messageId\": \"a2a-msg-0001\",\n      \"role\": \"user\",\n      \"kind\": \"message\",\n      \"parts\": [{ \"kind\": \"text\", \"text\": \"Where is order A-10293?\" }]\n    }\n  }\n}\n```\n\nTask follow-ups take the task id:\n\n```\n{\n  \"jsonrpc\": \"2.0\",\n  \"id\": \"a2a-0002\",\n  \"method\": \"GetTask\",\n  \"params\": { \"id\": \"<task-id-from-the-send-response>\" }\n}\n```\n\nWhen you're debugging, send the message, capture the returned task id, and then\n\nwalk the lifecycle explicitly. Treating A2A like a single synchronous RPC is the\n\nmost common source of \"it sometimes returns nothing.\"\n\nFor anything that takes time, the agent doesn't block on one response; it\n\nstreams task updates (over SSE in the JSON-RPC binding). The streaming methods\n\nare `SendStreamingMessage` and `SubscribeToTask` on 1.0, and `message/stream`\n\nand `tasks/resubscribe` on 0.3.\n\nDebugging these means inspecting the **event sequence**, not just the final\n\nframe: did the task go `working` → artifact/progress events → `completed`, or\n\ndid it stall in `input-required` waiting on something you never sent? A stream\n\nthat ends without a terminal state is a different bug from one that returns an\n\nerror event, and a REST client that only reads the first chunk will miss both.\n\nAuthenticated A2A uses signed requests verified against a **JWKS** (a JSON Web\n\nKey Set). Here's the subtle failure: an Agent Card can advertise where to fetch\n\nkeys, but blindly fetching keys from a URL the remote card itself provides means\n\nthe remote party is handing you both the lock and the key. A spoofed or\n\ncompromised card can then point you at attacker-controlled keys.\n\nThe safe pattern:\n\nThis is the same principle as TLS pinning and webhook-signature verification:\n\nthe trust anchor has to arrive independently of the signed payload.\n\nOnce you know the version, binding, card and task lifecycle, an A2A call is\n\ndebuggable with the same discipline you already use for REST — you just need a\n\nclient that speaks the envelope. In Powerduck, A2A sits alongside HTTP as a\n\nfirst-class debug protocol: create a new **A2A operation**, pick the version\n\n(1.0 / 0.3) and binding (JSON-RPC / HTTP+JSON / gRPC), paste the Agent Card URL\n\nand fetch the public card, choose the method, edit the request from a valid\n\ntemplate, send it, and inspect the returned task or the streamed events.\n\nThat workflow enforces the rules above in the right order — unknown method or a\n\nJSON-RPC envelope pasted into a REST binding is rejected up front, so you fix\n\nthe request shape before you go chasing agent behavior.\n\nDebugging an existing agent needs no server. If you want *your* business service\n\ncallable over A2A, you can download an **A2A 1.0 adapter template**, wire it to\n\nyour own HTTP handler, and run it yourself. It receives A2A requests and returns\n\nyour business results over JSON-RPC, REST or gRPC.\n\nTwo expectations to set correctly: the adapter is a thin protocol bridge — it\n\ndoes **not** ship an AI model or a persistent task engine, and you bring the\n\nbusiness logic and auth. That's deliberate: A2A is the transport between\n\ncapable agents, not a replacement for what your agent actually does.\n\nWhat makes this manageable long-term is describing the underlying service once\n\nand reaching it through the right surface for the caller: humans read the docs,\n\nagents call tools over MCP, and other agents delegate over A2A. The protocol\n\ndiffers; the contract shouldn't.\n\nIf you're integrating agents today, do the boring debugging first: pin the\n\nversion, fetch the card, send one message, capture the task id, walk the\n\nlifecycle, pin the JWKS out of band. Most \"agent interoperability\" problems\n\ndissolve into one of those five steps.\n\nYou can create and send A2A 1.0/0.3 requests (JSON-RPC, REST and gRPC), fetch\n\nAgent Cards, inspect task/stream responses, and verify signatures in the free\n\nweb app at [powerduck.com/app](https://www.powerduck.com/app).\n\nHave you hit an A2A integration yet — version mismatch, streaming, or the\n\nsignature/JWKS trust step? Tell me which one burned the most time in the\n\ncomments; I'm collecting the sharp edges as the protocol settles.", "url": "https://wpnews.pro/news/mcp-connects-agents-to-tools-a2a-connects-agents-to-agents-here-s-how-to-debug", "canonical_source": "https://dev.to/jeff_pdc/mcp-connects-agents-to-tools-a2a-connects-agents-to-agents-heres-how-to-debug-it-4ml", "published_at": "2026-10-09 07:41:11+00:00", "updated_at": "2026-10-09 07:51:33.451978+00:00", "lang": "en", "topics": ["ai-agents", "agent-protocols", "developer-tools", "ai-tools"], "entities": ["Agent2Agent", "A2A", "MCP", "JSON-RPC", "gRPC"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/mcp-connects-agents-to-tools-a2a-connects-agents-to-agents-here-s-how-to-debug", "markdown": "https://wpnews.pro/news/mcp-connects-agents-to-tools-a2a-connects-agents-to-agents-here-s-how-to-debug.md", "text": "https://wpnews.pro/news/mcp-connects-agents-to-tools-a2a-connects-agents-to-agents-here-s-how-to-debug.txt", "jsonld": "https://wpnews.pro/news/mcp-connects-agents-to-tools-a2a-connects-agents-to-agents-here-s-how-to-debug.jsonld"}}