A2A Transports and Core Methods

A2A defines what agents exchange independently of how it travels, so the same operations work over JSON-RPC, gRPC, or plain REST — and the operation set is small enough to hold in your head.

We have covered discovery, tasks, and the content model. This post is about the wire: how an A2A message actually moves between agents, and the set of operations the protocol defines. The Agent2Agent protocol (A2A) deliberately separates its abstract operations from any single transport, then provides multiple concrete bindings. This fifth post in the series covers the transports A2A supports and the core methods every binding exposes.

Abstract operations, multiple bindings

A2A’s specification is defined in a binding-independent way — the operations are described abstractly, and each transport binding must provide a functionally equivalent representation of them. That design choice is why A2A can meet teams where they are: an organization standardized on gRPC and one standardized on REST can both speak A2A without either abandoning its stack. The three supported bindings:

An agent declares which interface(s) and binding(s) it speaks in its Agent Card, so a client knows how to reach it. Because the operations are equivalent across bindings, the semantics you learn here are portable — only the surface syntax differs.

The core operations

The operation set is small and maps directly onto the concepts from earlier posts. Named as they appear in the JSON-RPC/gRPC bindings:

That is essentially the whole surface. Notice how cleanly it maps to the model built so far: you send a message to create a task, then get, list, cancel, or subscribe to that task, and manage push configs for async delivery. The concepts drive the API, not the other way around.

A concrete exchange

Over the JSON-RPC binding, initiating work looks like a familiar JSON-RPC call. The client sends a message; the remote agent responds with a Task it created to track the work:

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "SendMessage",
  "params": {
    "message": {
      "role": "ROLE_USER",
      "parts": [ { "text": "Summarize the attached report." } ]
    }
  }
}
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "task": {
      "id": "t-77",
      "status": { "state": "SUBMITTED" }
    }
  }
}

The client now holds t-77 and can call GetTask with that id to check progress, CancelTask to stop it, or subscribe for streaming updates. Over the REST binding the same interaction would be an HTTP POST to a messages endpoint returning the task as JSON; over gRPC it would be the SendMessage RPC returning a typed Task. Same operation, three surfaces.

Protocol versioning and negotiation headers

A2A carries a small amount of protocol metadata alongside each request so both sides stay aligned. An A2A-Version value (for example, 1.0) identifies the protocol version and is included with requests. An A2A-Extensions value lets a client advertise which optional extension URIs it supports, so agents can negotiate optional features without breaking base compatibility. These travel as HTTP headers in the REST and JSON-RPC bindings, or as metadata in gRPC. The practical takeaway mirrors MCP’s versioning advice: honor the declared version and negotiate extensions rather than assuming a peer supports everything.

Choosing a binding

Which transport you expose (or consume) is an engineering decision, not a semantic one:

Because A2A guarantees equivalent operations across bindings, you can pick per deployment and still interoperate. Expose the binding your ecosystem prefers, declare it in your Agent Card, and clients that speak it will work — the operations, and everything you learned about tasks and messages, stay the same underneath.

Key takeaways

Further reading

Sources & References

Transport bindings and methods