5.4

A2A-Version and A2A-Extensions

Two service parameters travel as HTTP headers or gRPC metadata on every request, and a missing A2A-Version means 0.3, which a 1.0 agent must refuse.

The kit sends test-runner a SendMessage with only Host and Content-Type headers, as a client that forgot the version would. The agent answers -32009 and reports the request as 0.3 (no header), in exchange 2 of 11-errors.http. Every other request in the captures carries A2A-Version: 1.0.

When you finish this section, you can set both headers in any binding and predict what each SDK does without a version.

Service parameters

Service parameter: an entry in a key-value map that carries context or parameters that apply to every operation. The keys are case-insensitive strings, and the values are case-sensitive strings. The specification defines two, A2A-Version and A2A-Extensions, and reserves the prefix a2a- for its own. Each binding says how they travel: as HTTP request headers in JSON-RPC and HTTP+JSON, and as metadata keys in gRPC. A custom binding must document how it carries service parameters.

The IANA templates for both headers cite section 3.2.5 of the specification. That is the metadata section, where the parameters are §3.2.6 (conflict D17). Issue #2305 tracks it, still open.

A2A-Version

A version is Major.Minor, such as 1.0, and requests, responses, and Agent Cards should not carry a patch number. A client must send the A2A-Version header with every request, and a 1.0 client sends 1.0. A server has two duties: process the request with the semantics of that version, and return VersionNotSupportedError when the interface does not support it. The empty case has a fixed meaning: an agent must read an empty value as version 0.3. So a client that forgets the header gets 0.3 semantics from an agent that still serves 0.3, and this error from one that does not:

no A2A-Version header, read as 0.3 and refusedhttpFull log
POST /a2a/jsonrpc HTTP/1.1
Host: localhost:41241
Content-Type: application/json
…
HTTP/1.1 200 OK
Content-Type: application/json

{
  "jsonrpc": "2.0",
  "id": 2,
  "error": {
    "code": -32009,
    "message": "Protocol version not supported",
…
          "requested": "0.3 (no header)",
          "supported": "1.0"
The request body and the error details are cut down. The request carries only Host and Content-Type, and the kit speaks only 1.0.

VersionNotSupportedError is -32009 in JSON-RPC, 400 in HTTP+JSON, and FAILED_PRECONDITION in gRPC, with the reason VERSION_NOT_SUPPORTED, as errors lists. The version to send comes from the card: each supportedInterfaces entry declares its own protocolVersion. An agent can expose several interfaces on the same transport with different versions, as AgentCard fields shows.

Three samples in the specification send A2A-Version: 0.3, and the gRPC sample in §10.2 sends the same value as metadata. Never copy a sample's value into a 1.0 client (conflict D39). §3.6.1 also allows a client to send A2A-Version as a request parameter instead of a header. Yet both JSON bindings require the header (conflict D31). The reference SDK reads only the header, and the kit reads both, so send the header.

What each SDK does without the header

ImplementationMissing or empty headerAccepted valuesWhere it checks
kit, a2a_ref.pyrefused as 0.3 (no header)exactly 1.0, from the header or the query parameterJSON-RPC and HTTP+JSON
a2a-python 1.2.2read as 0.3, then refused1, 1.0, 1.0.0, and 1.5, because only the major must be 1JSON-RPC and HTTP+JSON, never gRPC
a2a-js 1.3.0read as 0.3, refused unless the card lists itonly the strings the card declares for that binding, so 1.0.0 is refusedall three bindings
a2a-java 1.4.0.Finalread as 0.3, then refusedthe same major, in major.minor form, so 1 is refusedall three, with gRPC UNIMPLEMENTED instead of FAILED_PRECONDITION
a2a-go 2.6.0acceptedanything, because no server code reads the headernowhere
a2a-dotnet 1.0.0-preview2accepted as 1.01.0 or 0.3, with 0.3 processed as 1.0JSON-RPC only
a2a-rs, a2a-server 0.5.1read as 0.3, then refusedmajor 1JSON-RPC only

Every client in the list sends 1.0 on each call, and the Python and JS clients send it on the card fetch too. So send the literal string 1.0, never a patch number, and never rely on a server to refuse a missing header.

A2A-Extensions

A2A-Extensions is a comma-separated list of the extension URIs that the client wants for the request. It is one header field in both JSON bindings and one metadata entry in gRPC. §4.6.1 also allows JSON-RPC request parameters as the mechanism, while §9.2 requires the header, so send the header (conflict D30). The reference SDK's with_a2a_extensions helper joins the URIs with commas on the client, and its server reads them into the call context. What the server does with them, the payload keyed by URI, and ExtensionSupportRequiredError are in extensions.

A2A protocol 1.0.1 · 3303592 · 2026-05-28 · Edition 2026.10