Thomas Piacentini
← Atelier

Chapitre

Extensions

Texte original · anglais

An extension is a URI that a card declares, a client activates per request with A2A-Extensions, and both sides carry as metadata keyed by that URI.

The three cards in 01-agent-cards.http declare no extension, so the planner sends plain requests. A reviewer that returned a citation with each finding would need data the core protocol lacks, and an extension adds it under a URI. When you finish this section, you can read an extension declaration, activate one on a request, and handle a missing required one.

AgentExtension in the card

Extension: an addition to the protocol, identified by a URI and defined by its own specification {{docs extensions}}. An agent declares each one as an AgentExtension in capabilities.extensions {{proto AgentCapabilities}}, with four optional fields {{proto AgentExtension}}.

  • uri, the unique URI of the extension {{proto AgentExtension}}.
  • description, how this agent uses it.
  • required, true when the client must understand the extension and follow its rules {{proto AgentExtension}}.
  • params, the configuration parameters of the extension {{proto AgentExtension}}, as a JSON object.

Section 4.6.1 puts the array on the AgentCard itself {{spec §4.6.1}}, and the migration guide reads agentCard.extensions {{docs whats-new-v1}}. The proto puts it under capabilities, so read capabilities.extensions.

two optional extensions on the §4.6.1 sample cardjsonFull source
  "capabilities": {
    "streaming": false,
    "pushNotifications": false,
    "extensions": [
      {
        "uri": "https://standards.org/extensions/citations/v1",
        "description": "Provides citation formatting and source verification",
        "required": false
      },
      {
        "uri": "https://example.com/extensions/geolocation/v1",
        "description": "Location-based search capabilities",
        "required": false
      }
    ]
  },
The sample card, cut to its capabilities. The same sample sends protocolVersion 0.3 and has a trailing comma (conflict D24).
Original source
title: two optional extensions on the §4.6.1 sample card
source: research/sources/specification.md
lang: json
note: The sample card, cut to its capabilities. The same sample sends protocolVersion 0.3 and has a trailing comma ([conflict D24](#s-ref-sources)).
---
  "capabilities": {
    "streaming": false,
    "pushNotifications": false,
    "extensions": [
      {
        "uri": "https://standards.org/extensions/citations/v1",
        "description": "Provides citation formatting and source verification",
        "required": false
      },
      {
        "uri": "https://example.com/extensions/geolocation/v1",
        "description": "Location-based search capabilities",
        "required": false
      }
    ]
  },

Activating an extension on a request

The client lists the URIs it wants in the A2A-Extensions service parameter {{spec §3.2.6}}. A2A-Version and A2A-Extensions says how that parameter travels in each binding.

Message.extensions lists the URIs of the extensions that are present in the message or that added to it {{proto Message}}. The payload sits in metadata under the same URI as key. The specification shows that keying by example only {{spec §4.6.2}}. Artifact.extensions works the same way {{proto Artifact}}.

the §4.6.1 request: the header names the extension, and metadata carries its datahttpFull source
POST /message:send HTTP/1.1
Host: agent.example.com
Content-Type: application/a2a+json
Authorization: Bearer token
A2A-Extensions: https://example.com/extensions/geolocation/v1,https://standards.org/extensions/citations/v1

{
  "message": {
    "role": "ROLE_USER",
    "parts": [{"text": "Find restaurants near me"}],
    "extensions": ["https://example.com/extensions/geolocation/v1"],
    "metadata": {
      "https://example.com/extensions/geolocation/v1": {
        "latitude": 37.7749,
        "longitude": -122.4194
      }
    }
  }
}
The HTTP sample under the card in §4.6.1. It omits the REQUIRED messageId (conflict D23).
Original source
title: the §4.6.1 request: the header names the extension, and metadata carries its data
source: research/sources/specification.md
lang: http
note: The HTTP sample under the card in §4.6.1. It omits the REQUIRED messageId ([conflict D23](#s-ref-sources)).
---
POST /message:send HTTP/1.1
Host: agent.example.com
Content-Type: application/a2a+json
Authorization: Bearer token
A2A-Extensions: https://example.com/extensions/geolocation/v1,https://standards.org/extensions/citations/v1

{
  "message": {
    "role": "ROLE_USER",
    "parts": [{"text": "Find restaurants near me"}],
    "extensions": ["https://example.com/extensions/geolocation/v1"],
    "metadata": {
      "https://example.com/extensions/geolocation/v1": {
        "latitude": 37.7749,
        "longitude": -122.4194
      }
    }
  }
}

The guide adds a third step: the response should carry the A2A-Extensions header with every extension that the server activated for that request {{docs extensions}}. The specification has no such rule, and the SDKs differ. The a2a-js server echoes the header on all three bindings {{sdk-js src/server/express/json_rpc_handler.ts at v1.3.0}}. The a2a-go and a2a-java servers echo it only as gRPC response metadata {{sdk-go a2agrpc/v1/handler.go at v2.6.0}} {{sdk-java reference/grpc/src/main/java/org/a2aproject/sdk/server/grpc/quarkus/A2AExtensionsInterceptor.java at v1.4.0.Final}}. The a2a-python, a2a-dotnet, and a2a-rs servers never write it {{sdk src/a2a/extensions/common.py}} {{sdk-dotnet src/A2A/Models/AgentExtension.cs at v1.0.0-preview2}} {{sdk-rust a2a/src/lib.rs at a2a-server-lf-v0.5.1}}. Figure shows the exchange.

Fig. 6.2activating an extension, and the error when a required one is missingsequence
The card lists the extension, the request names it in `A2A-Extensions` and keys its data by the URI, and a missing required extension answers -32008.
The card lists the extension, the request names it in A2A-Extensions and keys its data by the URI, and a missing required extension answers -32008. Read top to bottom. Steps 1 to 4 follow the §4.6.1 sample card and request, and the activation steps of the extensions guide. Steps 5 and 6 show the §3.3.4 rule for a card that marks an extension required, which the sample does not. The kit declares no extension, so no capture is shown. URIs are shortened to their last two path segments.

Original SVG

Original source
id: fig-extension-activation
kind: sequence
title: activating an extension, and the error when a required one is missing
claim: The card lists the extension, the request names it in `A2A-Extensions` and keys its data by the URI, and a missing required extension answers -32008.
caption: Read top to bottom. Steps 1 to 4 follow the §4.6.1 sample card and request, and the activation steps of the extensions guide. Steps 5 and 6 show the §3.3.4 rule for a card that marks an extension required, which the sample does not. The kit declares no extension, so no capture is shown. URIs are shortened to their last two path segments.

Required extensions and versions

A card can mark an extension required: true. When the client does not declare that extension, the agent must return ExtensionSupportRequiredError {{spec §3.3.4}}: -32008, HTTP 400, or gRPC FAILED_PRECONDITION {{spec §5.4}}, as errors tables. Only a2a-java has the check built in {{sdk-java server-common/src/main/java/org/a2aproject/sdk/server/extensions/A2AExtensions.java at v1.4.0.Final}}. The reference SDK only exposes the requested URIs as requested_extensions {{sdk src/a2a/server/routes/common.py}} and never raises the error {{sdk src/a2a/utils/errors.py}}.

An extension should put its version in its URI {{spec §4.6.3}}, and a breaking change must get a new URI {{spec §4.6.3}}. An agent ignores an unknown version of an optional extension and returns an error for a required one. It must not switch to an older version of the extension by itself {{spec §4.6.3}}.

Kinds, governance, and what exists

The extensions guide names four kinds {{docs extensions}}. Data-only extensions add structured data to the card. Profile extensions narrow the values that core messages carry. Method extensions add RPC methods. State machine extensions add states, which task and task state rejects (conflict D29).

Two tiers govern extensions in the a2aproject organization {{docs extension-and-binding-governance}}: official ones in ext-{name} repositories under the URI prefix https://a2a-protocol.org/extensions/, and experimental ones in experimental-ext-{name}. For SDKs, extensions must be off by default and need an explicit opt-in {{docs extension-and-binding-governance}}. A conformant implementation does not have to support extensions {{docs extension-and-binding-governance}}.

On 2026-10-06 the organization had no ext- repository, so no official extension exists. One experimental extension exists: experimental-ext-oid4vp-auth, for in-task authorization with OpenID for Verifiable Presentations. Its agent moves the task to TASK_STATE_AUTH_REQUIRED and puts an authorization request in metadata under the extension URI, for a wallet to answer. It builds on in-task authorization, and its README allows breaking changes. The four example extensions that the guide lists are samples in a2a-samples, outside the tiers: timestamp, traceability, secure-passport, and agp.

Original source
- Read `capabilities.extensions` before you call an agent, and support every extension it marks required.
- Send `A2A-Extensions` with the URIs you want, and key each payload in `metadata` by its URI.
- Treat `-32008` as a card problem, and read the card again before you retry.
- Create a new URI for a breaking change.

Sources: spec §3.2.6, §3.3.2, §3.3.4, §4.6, §4.6.1, §4.6.2, §4.6.3, §5.4 (research/sources/specification.md); proto AgentCapabilities, AgentExtension, Message, Artifact (research/sources/a2a.proto); docs extensions, whats-new-v1, extension-and-binding-governance (research/sources/docs.md); sdk src/a2a/extensions/common.py, src/a2a/server/routes/common.py, src/a2a/utils/errors.py at a2a-python 1.2.2; sdk-js src/server/express/json_rpc_handler.ts at v1.3.0; sdk-go a2agrpc/v1/handler.go at v2.6.0; sdk-java reference/grpc/src/main/java/org/a2aproject/sdk/server/grpc/quarkus/A2AExtensionsInterceptor.java, server-common/src/main/java/org/a2aproject/sdk/server/extensions/A2AExtensions.java at v1.4.0.Final; sdk-dotnet src/A2A/Models/AgentExtension.cs at v1.0.0-preview2; sdk-rust a2a/src/lib.rs at a2a-server-lf-v0.5.1; a2aproject/experimental-ext-oid4vp-auth at e86356d; a2aproject/a2a-samples at 6603ba3; capture/out/01-agent-cards.http

Code et livrables 1
Ce que vous en retenez

Enregistré dans votre carnet sur cet appareil.

Sources et limites

Les repères de lecture sont déclaratifs. Les résultats de tests sont enregistrés séparément ; ils valent pour les cas exécutés.

AI Engineering from Scratch · 3f9715c · MIT

Télécharger ce fichier ↓