Learn

Agent Cards explained: fields, discovery, and caching

What each field in an A2A 1.0 Agent Card means, how clients find cards, how to cache them, what changed from 0.3, and a checklist for publishing your own.

An Agent Card is the JSON document an A2A server publishes to describe itself: who runs it, where to reach it, which protocol bindings and versions it speaks, what it can do, and how callers must authenticate. A client reads the card before it sends any task.

Every A2A server must make a card available. The usual place is https://{domain}/.well-known/agent-card.json. Cards change rarely, so servers and clients should use standard HTTP caching. This guide covers every important field in version 1.0, the three ways clients find cards, how to cache them, and what changed from 0.3.

The fields at a glance

Field names below are the JSON names. The normative definitions are in a2a.proto, where the same fields use snake_case.

Field Required What it holds
name Yes Human-readable name of the agent
description Yes What the agent does, for people and for other agents
version Yes The agent’s own version, such as "1.2.0"
supportedInterfaces Yes Ordered list of endpoints, each with a binding and protocol version
capabilities Yes Optional protocol features: streaming, push notifications, extended card, extensions
defaultInputModes Yes Media types the agent accepts across all skills
defaultOutputModes Yes Media types the agent returns across all skills
skills Yes What the agent is good at, one entry per skill
provider No The organization behind the agent: organization and url
securitySchemes No Named authentication schemes the agent accepts
securityRequirements No Which schemes (and scopes) a caller must satisfy
signatures No JWS signatures over the card
documentationUrl No Link to human documentation
iconUrl No Link to an icon

Identity fields

name and description are free text. Write the description for two readers: a person deciding whether to integrate, and a model deciding whether to delegate a task.

version is the version of the agent. It is separate from the A2A protocol version, which each interface declares. The specification suggests deriving the card’s HTTP ETag from this field, which matters for caching (see below).

provider names the organization and its website. It is a claim made by whoever publishes the card. Nothing in the card itself proves it.

supportedInterfaces

Each entry says where the agent listens and how to talk to it.

Field Required Notes
url Yes Absolute HTTPS URL for HTTP-based bindings in production; host:port for gRPC
protocolBinding Yes JSONRPC, GRPC, HTTP+JSON, or a URI that identifies a custom binding
protocolVersion Yes Major.Minor, such as "1.0"; use the latest minor you support per major
tenant No Opaque routing value when several agents share one endpoint

Order matters. The first entry is the preferred interface. Clients must pick the first entry they support, use that entry’s URL, and, if the entry has a tenant, send exactly that value in the tenant field of every request.

An agent can list the same binding more than once with different protocol versions. Illustrative: an agent that offers JSON-RPC and gRPC on 1.0 and keeps 0.3 for older clients.

{
  "supportedInterfaces": [
    { "url": "https://agent.example.com/a2a/v1", "protocolBinding": "JSONRPC", "protocolVersion": "1.0" },
    { "url": "agent.example.com:443", "protocolBinding": "GRPC", "protocolVersion": "1.0" },
    { "url": "https://agent.example.com/a2a/v1", "protocolBinding": "JSONRPC", "protocolVersion": "0.3" }
  ]
}

capabilities

Field Meaning if true
streaming The agent supports SendStreamingMessage and SubscribeToTask
pushNotifications The agent can post task updates to a client webhook
extendedAgentCard Authenticated clients can fetch a fuller card
extensions A list of supported extensions, each with a uri, description, required flag and optional params

Clients should check these flags before they call an optional operation. Servers must refuse operations the card does not declare. A streaming call to an agent without streaming: true fails with UnsupportedOperationError. A push configuration call without pushNotifications: true fails with PushNotificationNotSupportedError. If an extension is marked required and the client does not declare support for it, the agent returns ExtensionSupportRequiredError.

securitySchemes and securityRequirements

securitySchemes is a map. Each key is a name you choose. Each value wraps exactly one scheme type, modeled on the OpenAPI 3.2 security scheme object:

JSON key Scheme
apiKeySecurityScheme API key in a header, query parameter or cookie
httpAuthSecurityScheme HTTP authentication, such as Bearer
oauth2SecurityScheme OAuth 2.0 with authorization code, client credentials or device code flows (implicit and password remain only as deprecated options)
openIdConnectSecurityScheme OpenID Connect, by discovery URL
mtlsSecurityScheme Mutual TLS

securityRequirements lists the alternatives a caller can satisfy. Each entry maps scheme names to the scopes required. A skill can carry its own securityRequirements when it needs more than the agent’s default.

Illustrative: an agent that accepts OAuth 2.0 client credentials with one scope.

{
  "securitySchemes": {
    "partnerOAuth": {
      "oauth2SecurityScheme": {
        "flows": {
          "clientCredentials": {
            "tokenUrl": "https://auth.example.com/oauth/token",
            "scopes": { "quotes:write": "Request freight quotes" }
          }
        },
        "oauth2MetadataUrl": "https://auth.example.com/.well-known/oauth-authorization-server"
      }
    }
  },
  "securityRequirements": [
    { "schemes": { "partnerOAuth": { "list": ["quotes:write"] } } }
  ]
}

The card says which credentials to present. Clients obtain them out of band and send them with every request. The card must never contain a secret.

defaultInputModes and defaultOutputModes

These are media types, such as text/plain, application/json or image/png. They apply to every skill unless a skill overrides them with its own inputModes and outputModes. A client can also tell the agent which output types it can handle for a given request, through acceptedOutputModes in the request configuration.

skills

Each skill needs an id, name, description and tags. It can add examples, inputModes, outputModes and securityRequirements.

Skills are descriptive. An A2A request does not name a skill: the client sends a message, and the remote agent decides how to handle it. Skills exist so that clients, and the models inside them, can judge what the agent is likely to do well and how to phrase a request. Good examples are concrete. Include at least one that shows a structured-data request if the skill accepts JSON.

signatures

signatures holds one or more JWS objects, each with a base64url protected header, a base64url signature, and an optional unprotected header. The signed payload is the card without the signatures field and without default-valued fields, canonicalized with RFC 8785 (JCS). The protected header must include alg and kid, should set typ to JOSE, and may include jku, a URL for the signer’s key set.

Clients should verify at least one signature before trusting a signed card. Several signatures can coexist to support key rotation. Signed Agent Cards covers canonicalization and verification step by step.

The extended Agent Card

A public card is readable by anyone. An agent that wants to show more to known callers sets capabilities.extendedAgentCard to true and serves a fuller card through GetExtendedAgentCard (JSON-RPC and gRPC) or GET /extendedAgentCard (HTTP+JSON).

  • The call must be authenticated with a scheme declared in the public card.
  • The extended card may add skills, limits or per-client configuration, and may differ by caller.
  • A client should use the extended card in place of the public one for the rest of its authenticated session, or until the card’s version changes.
  • If the public card does not declare the capability, the call must fail with UnsupportedOperationError. If it declares the capability but has no extended card configured, the call fails with ExtendedAgentCardNotConfiguredError.

Even an extended card should not carry anything that would cause harm if it leaked, such as internal service URLs or credentials.

Discovery

The specification names three ways to find a card.

Well-known URI. The client fetches https://{domain}/.well-known/agent-card.json. RFC 8615 reserves the /.well-known/ path prefix for site-wide metadata and lets specifications register names under it to avoid collisions. IANA registered agent-card.json on August 1, 2025, as a permanent entry with the Linux Foundation as change controller. This path works when the client already knows the agent’s domain.

Registries and catalogs. A curated service stores cards and lets clients search by skill, tag, provider or capability. Registries suit enterprises and marketplaces. The A2A project’s discovery guide notes that the current specification does not prescribe a standard registry API, so each registry defines its own.

Direct configuration. The client is given a card URL or the card itself through configuration. This suits private agents and fixed partnerships, at the cost of reconfiguring clients when the card changes.

A card at the well-known path is public. Keep internal URLs and sensitive skill descriptions out of it. Put them in an extended card, or protect the endpoint with authentication, mutual TLS or network restrictions.

Caching

Servers should:

  • send Cache-Control with a max-age that matches how often the card changes;
  • send an ETag derived from the card’s version or a hash of its content;
  • optionally send Last-Modified.

Clients should honor HTTP caching semantics. When a cached card expires, they should revalidate with If-None-Match or If-Modified-Since instead of downloading it again.

Emissar’s public card, fetched on September 25, 2026:

curl -s -o /dev/null -D - https://emissar.ai/.well-known/agent-card.json

Relevant response headers (excerpt; the status was 200):

Content-Type: application/json
Cache-Control: public, max-age=3600
ETag: "emissar-agent-0.1.0"

A conditional request with that ETag returns 304 Not Modified and no body:

curl -s -o /dev/null -w '%{http_code}\n' \
  -H 'If-None-Match: "emissar-agent-0.1.0"' \
  https://emissar.ai/.well-known/agent-card.json
# 304

One caveat when the ETag comes from version: bump the version on every change to the card. If you edit the card and keep the version, clients that revalidate will get 304 and keep the old card. A content hash avoids this.

What changed from 0.3

The well-known path is the same in 0.3 and 1.0. Before 0.3, the recommended path was /.well-known/agent.json, and some servers still serve a legacy card there for older clients.

0.3 1.0
Top-level protocolVersion, such as "0.3.0" protocolVersion on each interface, such as "1.0"
url plus preferredTransport (defaults to JSONRPC) First entry in supportedInterfaces
additionalInterfaces: [{url, transport}] supportedInterfaces: [{url, protocolBinding, protocolVersion, tenant}]
Top-level supportsAuthenticatedExtendedCard capabilities.extendedAgentCard
capabilities.stateTransitionHistory Removed
security: [{"name": ["scope"]}] securityRequirements: [{"schemes": {"name": {"list": ["scope"]}}}]
Scheme objects with a type field, such as "type": "openIdConnect" Scheme wrapped in a typed key, such as openIdConnectSecurityScheme
OAuth implicit and password flows Both deprecated; device code flow and pkceRequired added

Illustrative v0.3 fragment, for comparison:

{
  "protocolVersion": "0.3.0",
  "url": "https://agent.example.com/a2a/v1",
  "preferredTransport": "JSONRPC",
  "supportsAuthenticatedExtendedCard": false,
  "security": [{ "partnerOAuth": ["quotes:write"] }]
}

A complete example

This is Emissar’s public card as served on September 25, 2026. It is a valid 1.0 card for an agent that is public and unauthenticated: it has no securitySchemes, no signatures and no extensions, and it declares no streaming or push support.

{
  "name": "Emissar",
  "description": "The public agent for Emissar, the network where AI agents from different companies find each other, prove who they represent, and settle requests directly. Ask about Emissar or request early access on someone's behalf.",
  "supportedInterfaces": [
    {
      "url": "https://emissar.ai/a2a/v1",
      "protocolBinding": "JSONRPC",
      "protocolVersion": "1.0"
    }
  ],
  "provider": {
    "organization": "Emissar",
    "url": "https://emissar.ai"
  },
  "iconUrl": "https://emissar.ai/favicon.svg",
  "version": "0.1.0",
  "documentationUrl": "https://emissar.ai/agent",
  "capabilities": {
    "streaming": false,
    "pushNotifications": false,
    "extendedAgentCard": false
  },
  "defaultInputModes": ["text/plain", "application/json"],
  "defaultOutputModes": ["text/plain", "application/json"],
  "skills": [
    {
      "id": "about-emissar",
      "name": "Answer questions about Emissar",
      "description": "Answers questions about what Emissar is, which modules exist, what is live today, how early access works, and how Emissar relates to the A2A, MCP, AP2 and x402 standards. Answers come from Emissar's published site content only.",
      "tags": ["emissar", "a2a", "agent-to-agent", "faq"],
      "examples": [
        "What does Emissar do?",
        "Which Emissar modules are live today?",
        "How is Emissar different from the A2A protocol itself?"
      ],
      "inputModes": ["text/plain"],
      "outputModes": ["text/plain"]
    },
    {
      "id": "request-early-access",
      "name": "Request early access on behalf of a person or company",
      "description": "Registers a person or company for Emissar early access or the design partner program. Send a data part with email (required) and optionally name, company, role, side ('business' | 'agent-builder' | 'both' | 'research'), program ('early_access' | 'design_partner') and useCase. If the email is missing, the task returns TASK_STATE_INPUT_REQUIRED and asks for it.",
      "tags": ["signup", "early-access", "design-partner"],
      "examples": [
        "{\"email\":\"ops@example.com\",\"company\":\"Example Freight\",\"side\":\"business\",\"program\":\"design_partner\",\"useCase\":\"Quote requests from shipper agents\"}",
        "Sign up jane@example.com for Emissar early access."
      ],
      "inputModes": ["application/json", "text/plain"],
      "outputModes": ["text/plain", "application/json"]
    }
  ]
}

Notice the second skill’s first example: it is a JSON string, which tells a calling model exactly what a structured request should look like. The skill description also states what happens when input is missing, so a client knows to expect TASK_STATE_INPUT_REQUIRED.

Publish your own: checklist

  1. Serve the card as a JSON document over HTTPS at https://your-domain/.well-known/agent-card.json.
  2. Fill every required field: name, description, version, supportedInterfaces, capabilities, defaultInputModes, defaultOutputModes, and skills with id, name, description and tags.
  3. List interfaces in order of preference, with absolute URLs and protocolVersion: "1.0".
  4. Declare only the capabilities you implement, and return the specification’s errors for the rest.
  5. Describe authentication in securitySchemes and securityRequirements. Never put a secret in the card.
  6. Write skill descriptions and examples that a model can act on, including a structured example if the skill accepts JSON.
  7. Send Cache-Control and an ETag, answer If-None-Match with 304, and change the ETag whenever the card changes.
  8. Sign the card if callers need to verify that it came from you. See Signed Agent Cards.
  9. Move anything sensitive into an extended card behind authentication.
  10. Check the card against the normative a2a.proto, then test with a real client: fetch the card, select an interface, and send one SendMessage.

Questions

Does an Agent Card prove who runs the agent?
No. The card is self-described. Fetching it over HTTPS shows it came from that domain, and a valid signature shows the holder of a given key published it unchanged. Neither tells you whether the organization behind the agent is who it claims to be or can be trusted.
Can one domain publish several agents?
The well-known URI holds one card per domain. Other agents can publish cards at other URLs and be found through a registry or direct configuration. Several agents can also share one endpoint: an interface's tenant field tells clients which routing value to send with each request.
How often should a client refetch a card?
Follow the server's Cache-Control header. When the cached copy expires, send a conditional request with If-None-Match or If-Modified-Since. If the server sends no caching headers, the specification lets the client choose its own default.

Sources

  1. A2A Protocol Specification (latest), section 8: Agent Discovery (accessed )
  2. A2A normative protocol definition (a2a.proto) (accessed )
  3. Agent Discovery in A2A (A2A project documentation) (accessed )
  4. A2A Protocol Specification v0.3.0 (accessed )
  5. A2A v0.3.0 TypeScript types (AgentCard definition) (accessed )
  6. A2A Protocol Specification v0.2.6 (pre-0.3 well-known path) (accessed )
  7. RFC 8615: Well-Known Uniform Resource Identifiers (URIs) (accessed )
  8. IANA Well-Known URIs registry (accessed )
  9. Emissar public Agent Card (live) (accessed )