Chapter 22

Publish an Honest Agent Card

An Agent Card is the agent's discovery document: name, description, interfaces, protocol version, capabilities, security schemes, default data modes, and skills. The client reads the card before calling any optional operations - and so the card is both the agent's public face and its promise.

A working card looks like this: it honestly declares what the agent can do and how to talk to it.

TypeScript
export function createReleaseAgentCard(baseUrl: string): AgentCard {
  return {
    name: "Release Review Agent",
    description: "Checks a release snapshot against the approved policy and returns a report.",
    supportedInterfaces: [{
      url: `${baseUrl}/`,
      protocolBinding: "JSONRPC",
      tenant: "",
      protocolVersion: A2A_PROTOCOL_VERSION
    }],
    provider: {
      organization: "Developer Protocol Book",
      url: "https://example.com/developer-protocol-book"
    },
    version: "1.0.0",
    documentationUrl: `${baseUrl}/docs`,
    capabilities: {
      streaming: true,
      pushNotifications: false,
      extensions: [],
      extendedAgentCard: false
    },
    securitySchemes: {},
    securityRequirements: [],
    defaultInputModes: ["text/plain"],
    defaultOutputModes: ["text/markdown", "application/json"],
    skills: [{
      id: "review_release",
      name: "Release review",
      description: "Checks CI, tests, vulnerabilities, migration reversibility, and rollback readiness.",
      tags: ["release", "ci", "security", "rollback"],
      examples: ["Check the release web-portal@2.4.0"],
      inputModes: ["text/plain"],
      outputModes: ["text/markdown", "application/json"],
      securityRequirements: []
    }],
    signatures: []
  };
}

It's found at a standard address, and the client goes over the card top to bottom before sending anything.

GET /.well-known/agent-card.json
Accept: application/json

The client picks supportedInterfaces[]
checks protocolVersion + protocolBinding
checks streaming/push/extendedAgentCard
negotiates input/output media types
then applies the declared security scheme

The key word in the chapter title is "honest". The client uses every field of the card for a real decision, and so each has its own typical design error.

Field · The client uses it for · Design error

  • supportedInterfaces - URL, binding, version; Putting localhost in production
  • capabilities - Whether streaming/push/extended card is possible; Declaring a feature without an implementation
  • skills - Agent selection and task examples; A marketing "does everything"
  • modes - Media negotiation; Returning an unnegotiated format
  • security - How to authenticate a request; A secret in the card itself
  • signatures - Verifying the card's provenance; Treating a signature as authorization

Let's take the most dangerous. supportedInterfaces gives the URL, binding, and version - and putting localhost here in production means breaking every client. capabilities declares streaming/push/extended card - declaring a feature without an implementation is worse than not declaring it. skills is agent selection and task examples, not a marketing "does everything". And the signature in signatures verifies the card's provenance, but is not itself authorization.

The card is a promise of compatibility. Version control is needed not only for the agent's code. Changing a skill's semantics, a required input mode, or a security requirement can be a breaking change even at the same HTTP endpoint. Change the meaning - change the version.

The card declares how to talk to the agent. The conversation itself is carried by messages - and here A2A carefully separates the communication from the result of the work.

Links