Generating and Validating A2A Agent Cards
Source: mortalapps.com- An Agent Card is a standardized JSON metadata file used in Agent-to-Agent (A2A) protocols to describe an agent's identity, capabilities, and communication endpoints.
- It solves the problem of manual integration by providing a machine-readable manifest for dynamic discovery and capability negotiation.
- Production systems rely on these cards to automate routing, ensure security compliance, and verify tool compatibility before execution.
- Implementing valid cards enables cross-vendor interoperability and reduces the maintenance overhead of multi-agent orchestration.
- Strict schema validation is required to prevent runtime failures in decentralized agent registries.
Why This Matters
In decentralized multi-agent systems, the ability for one agent to programmatically discover the capabilities of another is the cornerstone of interoperability. An a2a agent card json example illustrates how metadata - ranging from supported models to specific tool schemas - is structured to allow seamless handoffs. Without a standardized format like the Linux Foundation A2A Agent Card v1.0, developers are forced to write bespoke integration logic for every new agent pairing, which is unsustainable at scale. This approach was invented to decouple agent development from agent orchestration, allowing a 'plug-and-play' ecosystem where an orchestrator can query a registry and understand exactly how to invoke a specialized agent. If you ignore strict validation in production, you risk 'ghost agents' that appear in registries but fail during invocation due to mismatched endpoint signatures or unsupported capability versions. This leads to cascading failures in agentic workflows where a downstream agent cannot fulfill a delegated task. Use Agent Cards when building open ecosystems or internal platforms where agents are developed by different teams; use simpler, hardcoded configurations only for small, monolithic, or single-purpose agent scripts where discovery is not a requirement. From an enterprise perspective, these cards serve as the 'contract' for governance, allowing security teams to audit what an agent claims to do versus what its underlying permissions allow.
Core Concepts
The A2A Agent Card v1.0 specification defines several critical components that must be present for a card to be considered valid.
1. Identity and Metadata
Every card must contain a unique id (typically a UUID or a DID) and a version string. This allows registries to manage updates and deprecations.
2. Capability Descriptors
These are the most complex parts of the card, defining what the agent can actually do. Each capability includes: - Type: The category of skill (e.g., 'text-generation', 'data-analysis'). - Schema: A reference to the input/output JSON Schema the agent expects. - Version: The semantic version of the capability implementation.
3. Endpoint Definitions
Endpoints describe how to reach the agent. A card may list multiple endpoints for different protocols (e.g., WebSocket for streaming, HTTPS for REST). Each endpoint must specify its url, protocol, and authentication_methods.
4. Trust and Security Metadata
This section includes public keys or references to DID documents that allow other agents to verify the card's authenticity. It ensures that the agent claiming to be 'Financial-Analyst-01' is actually the authorized entity.
5. Constraints and Policies
Agents can declare operational limits, such as maximum token counts, supported languages, or regional data residency requirements. This allows orchestrators to filter agents based on compliance needs.
How It Works
The lifecycle of generating and validating an Agent Card follows a strict sequence to ensure the resulting JSON is both schema-compliant and functionally accurate.
Phase 1: Capability Mapping
The process begins by introspecting the agent's internal tools and LLM configurations. Developers map these internal functions to the standard A2A capability types. For example, a Python function using a specific library for PDF parsing is mapped to a 'document-processing' capability with a defined JSON Schema for its parameters.
Phase 2: Programmatic Generation
Using a type-safe library like Pydantic, the agent's metadata is serialized into the A2A JSON format. This step involves populating the identity fields, generating the capability list, and injecting the current deployment's endpoint URLs. Failure at this stage usually involves missing required fields like contact_email or license_info.
Phase 3: Schema Validation
The generated JSON is run against the official A2A v1.0 JSON Schema. This is a structural check that ensures all data types are correct (e.g., version is a string, not an integer) and that all mandatory arrays are present. If validation fails, the agent should not attempt to register itself with any discovery service.
Phase 4: Semantic Linting
Beyond basic schema checks, semantic linting verifies that the declared endpoints are reachable and that the referenced capability schemas are valid URIs. This phase prevents 'broken' cards from entering the ecosystem.
Phase 5: Serialization and Signing
Once validated, the card is serialized into a minified JSON string. In production environments, this string is often signed using a JSON Web Signature (JWS) to provide non-repudiation before being published to a registry or served via a .well-known/agent-card.json endpoint.
Architecture
The architecture for Agent Card management consists of four primary components.
- The Agent Provider: The service hosting the AI agent. It contains a 'Card Generator' module that pulls from the agent's internal configuration.
- The Validator Service: A standalone or middleware component that holds the A2A v1.0 JSON Schema. It receives raw JSON and returns a boolean success/fail with error logs.
- The Agent Registry: A centralized or distributed database (like a DHT or a specialized MCP server) where validated cards are stored. It serves as the 'Yellow Pages' for agents.
- The Discovery Client: An orchestrator or another agent that queries the registry. It parses the Agent Cards to build a routing table. Data flows from the Provider to the Validator, then to the Registry. The Discovery Client then pulls from the Registry to initiate an A2A session. Execution starts at the Provider's deployment and ends when the card is successfully indexed by the Registry.
Implementing the A2A v1.0 Schema
The A2A Agent Card v1.0 specification is built on top of JSON Schema Draft 7. When generating a card, the capabilities array is the most critical section. Each entry in this array must follow the Capability Object structure, which requires a name, description, and interface. The interface object is where the Model Context Protocol (MCP) or custom tool schemas are defined. For production-grade validation, you should not rely on simple dictionary checks. Instead, use a formal JSON Schema validator that supports remote $ref resolution, as many A2A cards reference external schema definitions for domain-specific tasks (e.g., financial reporting standards).
Programmatic Generation with
Pydantic Pydantic provides a robust framework for ensuring that the generated JSON matches the spec. By defining a BaseModel for each section of the Agent Card (Identity, Capability, Endpoint), you can catch type errors at instantiation time rather than at the validation step. A common pattern is to use Pydantic's Field aliases to map internal Pythonic names (like agent_id) to the spec-required names (like id). This keeps your internal code clean while maintaining strict compliance with the external protocol.
Semantic Linting and Verification
A card that is syntactically valid can still be functionally useless. Semantic linting involves checking the logic within the card. For example, if an agent claims to support 'A2A-Streaming-v1', but its only listed endpoint is a standard REST HTTPS URL that does not support long-lived connections, the linter should flag this as a mismatch. Furthermore, linting should verify that the trust_anchor provided is a valid DID or a reachable HTTPS URL hosting a public key. This prevents spoofing and ensures that the discovery process doesn't lead to a security dead-end.
Handling Dynamic
Endpoints In cloud-native environments, agent endpoints may change frequently due to scaling or redeployment. A robust generation strategy involves using environment variables or service discovery (like Kubernetes DNS) to populate the endpoints section of the card at runtime. The card should never be a static file checked into version control; it should be a dynamically generated artifact served by the agent's management API. This ensures that the registry always has the most current routing information.
Versioning and Backward Compatibility
The A2A spec uses semantic versioning for both the card format and the capabilities. When validating, your system must handle 'Partial Compatibility'. For instance, an orchestrator looking for a 'v2.0' capability might still be able to use an agent providing 'v1.8' if the changes are non-breaking. Your validation logic should include a 'compatibility matrix' that defines which versions of a capability are interchangeable. This prevents the ecosystem from fracturing every time a minor update is released.
Code Example
import os
import json
from uuid import uuid4
from pydantic import BaseModel, Field, HttpUrl, EmailStr
from typing import List, Optional
class Capability(BaseModel):
name: str
version: str
interface_type: str = Field(..., alias='interfaceType')
schema_uri: HttpUrl = Field(..., alias='schemaUri')
class Endpoint(BaseModel):
url: HttpUrl
protocol: str
auth_method: str = Field('none', alias='authMethod')
class AgentCard(BaseModel):
id: str = Field(default_factory=lambda: str(uuid4()))
name: str
version: str
description: str
contact: EmailStr
capabilities: List[Capability]
endpoints: List[Endpoint]
def generate_agent_card():
# Fetching deployment-specific values from environment
base_url = os.environ.get('AGENT_BASE_URL', 'https://api.example.com')
card = AgentCard(
name='DataAnalyzerAgent',
version='1.0.2',
description='Specialized agent for SQL generation and data visualization.',
contact='[email protected]',
capabilities=[
Capability(
name='nl-to-sql',
version='2.1.0',
interfaceType='mcp-tool',
schemaUri=f'{base_url}/schemas/sql-gen.json'
)
],
endpoints=[
Endpoint(
url=f'{base_url}/v1/a2a',
protocol='https/json-rpc',
authMethod='bearer-token'
)
]
)
return card.model_dump_json(by_alias=True, indent=2)
if __name__ == '__main__':
print(generate_agent_card())
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "DataAnalyzerAgent",
"version": "1.0.2",
"description": "Specialized agent for SQL generation and data visualization.",
"contact": "[email protected]",
"capabilities": [
{
"name": "nl-to-sql",
"version": "2.1.0",
"interfaceType": "mcp-tool",
"schemaUri": "https://api.example.com/schemas/sql-gen.json"
}
],
"endpoints": [
{
"url": "https://api.example.com/v1/a2a",
"protocol": "https/json-rpc",
"authMethod": "bearer-token"
}
]
}