Explore A2A's third binding: gRPC. From the protobuf definition for A2A services, the advantages of streaming and backpressure, when to choose gRPC versus HTTP/JSON, to interop through gateways and reusing server handlers.

In episode 10 your agents were multi-tenant and could negotiate protocol versions. But imagine an orchestrator calling dozens of remote agents with HTTP+JSON and SSE: every request carries text serialization overhead, connections open and close constantly, and streaming over HTTP/1.1 feels like a leaking hose. A2A has a third answer for transport: gRPC.
This episode's roadmap: we start with how gRPC became the third official binding, dissect the protobuf definition for A2A services, the advantages of streaming and backpressure, criteria for when gRPC beats HTTP/JSON, and finally interop through gateways and reusing server handlers.
From the start, A2A was designed as a multi-transport protocol: JSON-RPC 2.0 over HTTP with SSE as the primary binding, and gRPC was added as an official binding since v0.3 (July 2025). The reason for adding it is simple — the ecosystem needed a high-performance transport for service-to-service communication, and gRPC is its de facto standard: strict schemas via protobuf, HTTP/2 transport, and natively supported streaming.
In A2A v1.0, gRPC isn't an experiment — it's a first-class citizen. The Agent Card declares it in supported_interfaces with a protocol_binding value of gRPC, clients can choose it just like they choose JSON-RPC, and the official Python, TypeScript, Go, Java, and .NET SDKs provide implementations.
The gRPC schema is defined in the official A2A protobuf file — a single source of truth for all languages. Its contents map the JSON-RPC methods we know from episode 5 into RPCs: MessageSend for message/send, SendSubscribe for streaming, GetTask for tasks/get, and Cancel for tasks/cancel:
syntax = "proto3";
package a2a.v1;
service A2AService {
rpc MessageSend(MessageSendRequest) returns (MessageSendResponse);
rpc SendSubscribe(SendSubscribeRequest) returns (stream SendSubscribeResponse);
rpc GetTask(GetTaskRequest) returns (GetTaskResponse);
rpc Cancel(CancelRequest) returns (CancelResponse);
}
message MessageSendRequest {
string task_id = 1;
Message message = 2;
}
message MessageSendResponse {
Task task = 1;
}Note that SendSubscribe returns a stream — this is the gRPC form of the SSE streaming we discussed in episode 7. From this schema, protobuf tooling generates client and server stubs in various languages, so calling MessageSend in Go or Python talks to the same service with an identical definition.
Why does gRPC excel at streaming? The answer is in HTTP/2 and the protobuf design:
Backpressure is what makes gRPC feel "honest": when the receiver is slow, the flow slows down on its own, instead of flooding an unbounded queue like SSE often does over HTTP/1.1.
gRPC isn't a replacement for HTTP/JSON in every case — the two complement each other. The selection criteria:
| Consideration | gRPC | HTTP/JSON |
|---|---|---|
| Schema | Strict, protobuf | Flexible, JSON |
| Streaming | HTTP/2, bidirectional, backpressure | One-way SSE |
| Performance | High, binary payload | Moderate, text payload |
| Accessibility | Needs tooling/stub | Browser, curl, any tool |
| Debugging | Needs grpcurl / reflection | Directly with curl |
The rule of thumb: use gRPC for internal communication between agents you fully control — high throughput, heavy streaming, large traffic. Use HTTP/JSON for the external surface — partners, browsers, quick debugging, and anyone who doesn't want to hold a protobuf stub. Many productions use both at once: gRPC inside the agent network, HTTP/JSON at the public gateway.
Info
Both bindings translate the same concepts — task lifecycle, message, part — so choosing a transport doesn't mean rewriting agent logic. Execution, the task store, and the Agent Card stay one; only the transport layer differs.
Because both bindings coexist, the need for interop arises: an HTTP client calling an agent that only exposes gRPC, or vice versa. There are two common strategies.
Strategy one: transparent gateway. Tooling like gRPC-gateway or Envoy translates HTTP+JSON requests into gRPC calls and returns responses as JSON. External clients keep using curl or the regular HTTP SDK; the gateway handles the translation. This is a favorite pattern for exposing internal gRPC services to external partners.
Strategy two: reuse server handlers. The official SDKs encourage this design: the executor and task store are written once, then mounted on both a JSON-RPC handler and a gRPC handler. In the Python SDK, the gRPC handler is assembled from the same components as the HTTP version:
from a2a.server.request_handlers import GrpcHandler
grpc_handler = GrpcHandler(
agent_executor=my_executor,
task_store=task_store,
agent_card=card,
)Because GrpcHandler accepts the same agent_executor and task_store as the HTTP version, the agent logic is never duplicated. One change to task behavior applies to both transports immediately. For quick verification, the grpcurl tool becomes curl's companion — calling grpcurl -plaintext localhost:50051 a2a.v1.A2AService/MessageSend tests the service without writing any code:
grpcurl -plaintext -d '{"message":{"role":"user","parts":[{"kind":"text","text":"Analisis lead"}]}}' \
localhost:50051 a2a.v1.A2AService/MessageSendWith -plaintext for a local connection without TLS, grpcurl sends the request and displays the response — the fastest way to confirm your gRPC service is alive.
Episode 11 closes the discussion of A2A transport bindings. gRPC arrived as the third binding since v0.3 and matured in v1.0, with protobuf definitions as the schema's source of truth, HTTP/2 streaming with backpressure, and more compact binary payloads. The choice between gRPC and HTTP/JSON depends on context — high-performance internal traffic for gRPC, the public surface for HTTP/JSON. And thanks to handler reuse and gateways, both can coexist without duplicating agent logic.
Here's the core takeaway:
supported_interfaces on the Agent Card.SendSubscribe.Once transport, authentication, multi-tenancy, and content are mastered, the next question is productivity: do you have to write all this from scratch? In episode 12 we discuss ADK & Framework Integration — exposing a Google ADK agent as an A2A server, using a remote A2A agent as a sub-agent, and the adapter pattern for LangChain, LangGraph, CrewAI, and the OpenAI Agents SDK. See you there!