Tutorial
A2A Agent Card JSON Schema tutorial: how to define an agent’s name, capabilities, skills, interfaces, and endpoint
The Card is a contract for the orchestrator, not a brief for your own model. Wrong fields fail discovery first.
The previous post, Agent Registry, split catalog from source JSON. Today is not registration, and not the discovery hops. You have an agent-card.json to commit. The questions are: what each field means, which ones are required, and whether 0.3’s top-level url may stay. The answers live in A2A spec §4.4, not on slides. The 0.3 → 1.0 move is on what’s new in v1.0. Google’s catalog accepts both contracts; see the Registry JSON schemas. New cards should be 1.0. Validation practice is a later post. Today is the field table.
Who this card is for
An Agent Card is the public business card an A2A server hangs at /.well-known/agent-card.json. The reader is not your own model. It is another orchestrator, a gateway, or an in-org catalog. The card answers three sentences: who you are, how to reach you, what you claim to handle. First: name / description / version. Second: supportedInterfaces. Third: skills[]. Pour a runbook into description and the 10KB cap hits first; the discovery surface gets thinner.
Version 1.0 hard-codes required. The spec table marks name, description, supportedInterfaces, version, capabilities, defaultInputModes, defaultOutputModes, and skills as Yes. Miss one, and a 1.0 client should not treat the file as a legal card. 0.3 could live on top-level url and protocolVersion. A 1.0 client should ignore those and read the interface array. Mix both field sets and catalog extract silently thins; the ticket still says “cannot find.”
The card is not a Plugin Manifest, and not MCP tools/list. How one coding agent grows skills is the Plugin post. How a call hop checks arguments is MCP and JSON Schema. Today is only how a sideways colleague describes itself. Signatures, extended cards, and GetExtendedAgentCard sit after auth. The public card must state skills first.
| Field | Required in 1.0 | What to write |
|---|---|---|
name / description / version | Yes | Human identity; version is the agent’s own |
supportedInterfaces | Yes | Ordered endpoints; first is preferred |
capabilities / default MIME / skills | Yes | Capability flags, media types, claimed skills |
Identity: name, description, version, provider
name is for humans scanning a catalog, not an internal service name. description states scope and a boundary: what you do, and what you will not. A returns specialist can say “classifies return requests; does not post refunds.” Orchestrators decide whether to send a Task from this paragraph, not from your README.
version is this agent’s release, such as 1.0.3. Protocol version travels with the interface, in supportedInterfaces[].protocolVersion. Write 1.0 in both places and later you cannot tell which side moved. provider is optional, but if present it is a pair: organization plus url. documentationUrl and iconUrl are optional too; long prose belongs at the docs URL, not in the card.
Stop after the identity block. Without interfaces the card cannot be called. Without skills the catalog cannot find you. Keep the first of the three sentences short and true, then fill endpoints.
Interfaces: supportedInterfaces is the endpoint
In 1.0 the primary endpoint is not top-level. supportedInterfaces is an ordered array; the first entry is preferred. Each item requires url, protocolBinding, and protocolVersion. Production url must be absolute HTTPS. Official core bindings are JSONRPC, GRPC, and HTTP+JSON; the spec leaves the string open for extensions. tenant is optional — write it only for multi-tenant routing.
One agent may list three bindings on three URLs. Clients pick the first they speak, in array order. Do not point all three at the same 404 to look complete. 0.3’s top-level url plus protocolVersion is the old contract; the v1.0 changes page says they are no longer primary. Register as 1.0 with the URL at the top, and 1.0 validation should fail or the primary endpoint is ignored.
The interface array decides how you speak, not what you handle. JSONRPC without skills: reachable, not searchable. Skills without interfaces: searchable, no Task. Both blocks must be present.
Capabilities and default MIME types
capabilities is a required object in 1.0; the booleans inside are optional: streaming, pushNotifications, extendedAgentCard, plus an extensions array. Missing or false means the matching operation should error, not silently retry. Do not copy 0.3’s stateTransitionHistory back in as a core capability. Table 4.4.3 no longer lists it.
defaultInputModes and defaultOutputModes are media-type arrays for every skill. A skill may override with inputModes / outputModes. Text only: text/plain. JSON out: add application/json. An empty array is an undeclared card; 1.0 validation should fail. Do not put file extensions or private enums here.
extendedAgentCard true means a second, richer card may be fetched after auth. The public card must still stand alone: skills, interfaces, default MIME. Hide a critical skill only on the extended card and unauthenticated catalogs will miss you on the search surface.
skills[]: id, tags, examples
Each skill requires id, name, description, and tags. id is a stable, short, programmatic key — no spaces. name is for humans. description states I/O bounds; it is still not an arguments schema. tags is a required string array in 1.0, for catalog and orchestrator keywords. Google Registry indexes tags too. Empty or omitted: the file may parse, and nobody finds you.
examples are optional prompts or scenes for humans, not JSON Schema. 1.0 does not treat inputSchema as the skill contract. Older implementations still hang a schema on a skill; a hint is fine, a tools/call contract is not. The other side is an opaque agent; you send a Task. The in-site 0.3 fragment that puts inputSchema on a skill is the old contract. Do not copy it into a new card.
Do not slice skills by internal function names. One skill is one kind of work an orchestrator would delegate. A returns specialist can expose classify-return and check-window — not “read table,” “write log,” “send mail” as three search terms. Below is a 1.0 card you can commit. Parse it, then run the official schema.
{
"name": "Returns Specialist",
"description": "Classifies return requests and checks the return window. Does not post refunds.",
"version": "1.0.3",
"provider": {
"organization": "Example Commerce",
"url": "https://commerce.example.com"
},
"documentationUrl": "https://docs.example.com/returns-agent",
"supportedInterfaces": [
{
"url": "https://agents.example.com/returns/a2a",
"protocolBinding": "JSONRPC",
"protocolVersion": "1.0"
},
{
"url": "https://agents.example.com/returns/a2a/json",
"protocolBinding": "HTTP+JSON",
"protocolVersion": "1.0"
}
],
"capabilities": {
"streaming": true,
"pushNotifications": false,
"extendedAgentCard": false
},
"defaultInputModes": ["text/plain", "application/json"],
"defaultOutputModes": ["text/plain", "application/json"],
"skills": [
{
"id": "classify-return",
"name": "Classify a return",
"description": "Decide whether a request is a return, exchange, or warranty claim.",
"tags": ["returns", "classify", "commerce"],
"examples": ["This jacket arrived damaged. Is it a return or a warranty claim?"]
},
{
"id": "check-window",
"name": "Check return window",
"description": "Say whether the purchase is still inside the return window.",
"tags": ["returns", "policy", "deadline"],
"examples": ["Order 8841 was delivered on 2026-08-02. Can they still return it?"]
}
]
}
| Field | Required | Usual breakage |
|---|---|---|
id / name / description | Yes | id copied from a function; description is a runbook |
tags | Yes | Missing or empty; the catalog cannot search |
examples / per-skill MIME | No | examples treated as inputSchema |
What must not go in a 1.0 card
Keep at least one negative: top-level url still present, a skill with no tags, plus an MCP-shaped inputSchema. 1.0 validation should fail. If CI mashes 0.3 and 1.0 into a “generic agent check,” you are messier than the client. The Registry picks rules from the version you declared and does not fetch a schema while loading.
{
"name": "Returns Specialist",
"description": "Classifies return requests.",
"version": "1.0.3",
"url": "https://agents.example.com/returns/a2a",
"protocolVersion": "1.0",
"supportedInterfaces": [
{
"url": "https://agents.example.com/returns/a2a",
"protocolBinding": "JSONRPC",
"protocolVersion": "1.0"
}
],
"capabilities": {
"streaming": true,
"stateTransitionHistory": true
},
"defaultInputModes": ["text/plain"],
"defaultOutputModes": ["text/plain"],
"skills": [
{
"id": "classify-return",
"name": "Classify a return",
"description": "Decide the request type.",
"inputSchema": {
"type": "object",
"required": ["orderId"],
"properties": {
"orderId": { "type": "string" }
}
}
}
]
}
securitySchemes and security requirements are an optional layer. A public card may ship without signatures. signatures are JWS; the verify walk is the practice post. Remember: a signature does not replace tags. An honest card with one real skill beats a pretty card with an empty skill list. skills is still a required array — do not submit zero items unless you truly have none.
Do not copy closed Plugin fields, SKILL.md paths, or MCP tools[].name into the Card. Three JSON files all say “capability”; failure handling differs. A bad Card is a discovery failure.
You can do this in the browser:JSON formatterto see whether the card parses;JSON Schema validatorto check 1.0 supportedInterfaces and skills[].tags;JSON Diffto catch top-level url / missing tags between the committed card and the negative. Nothing leaves the machine. Further reading:Agent Registry overview, and A2A vs MCP. The discovery walk is the next post.
Related: Google Agent Registry, A2A vs MCP, MCP and JSON Schema.
FAQ
May we keep top-level url for compatibility?
Not as the primary field if you register as 1.0. Old clients that still read top-level url are on the 0.3 contract. New cards put endpoints only in supportedInterfaces. Writing both is two contracts, each reading a different half.
Can a skill be just an id, with tags later?
Not as legal 1.0. The spec marks tags Yes. Catalog search eats tags. “Later” means not searchable now.
description is too short. Where does the handbook go?
On documentationUrl, or in the agent’s own skills or docs. Cards have a size cap. A handbook in the card hits 10KB first; discovery goes to zero.
Should a skill carry inputSchema?
Not as a 1.0 contract. Need a hint shape: write examples and MIME types. Deterministic parameters belong on MCP tools, not on the Agent Card.
Takeaways and next steps
In 2026 an A2A Agent Card collapses to one required table: three identity fields, an interface array, a capabilities object, default MIME types, and skills with tags. Orchestrators read those fields, not your architecture slide.
Ship in this order: a legal 1.0 card; first interface is a real endpoint; every skill has non-empty tags; parse and schema-check in JSONVue. How the catalog consumes the card: the previous post. The hops: the next. Signatures and a verify checklist: later.