A2A protocol features in Apicurio Registry
Apicurio Registry implements the A2A (Agent-to-Agent) protocol for AI agent discovery, orchestration, and lifecycle management.
A2A protocol overview
With the A2A protocol, AI agents can discover and communicate with each other through standardized endpoints. Apicurio Registry serves as both an A2A agent and an agent registry.
- Apicurio Registry as an A2A agent
-
Apicurio Registry provides its own capabilities, including schema validation, search, and artifact management.
- Apicurio Registry as an agent registry
-
Apicurio Registry stores and discovers other agents' Agent Cards.
| Apicurio Registry as an A2A agent | Apicurio Registry as an agent card registry |
|---|---|
Endpoint: Built-in skills:
|
Endpoints:
Capabilities:
|
A2A configuration properties
You can control A2A features by using the following configuration properties.
| Property | Default | Description |
|---|---|---|
|
|
Enable or disable A2A protocol support |
|
|
Name of the registry as an A2A agent |
|
|
Description of the registry agent |
|
app version |
Agent version (defaults to application version) |
|
registry base URL |
URL reported in the Agent Card |
|
|
Provider organization name |
|
Provider organization URL |
|
|
|
Whether streaming is supported |
|
|
Whether push notifications are supported |
|
|
A2A protocol version reported in the Agent Card and in its supported interfaces |
|
not set |
URL of the registry agent documentation, reported as |
|
not set |
URL of the registry agent icon, reported as |
|
|
Advertise API key authentication with the |
A2A well-known endpoints
Apicurio Registry provides the following well-known endpoints for A2A agent discovery and retrieval.
- GET /.well-known/agent.json
-
Retrieves the Agent Card for the Apicurio Registry instance. This endpoint requires no authentication. The same card is available at
/.well-known/agent-card.json.Response: Agent Card JSON document
{ "name": "Apicurio Registry", "description": "API and Schema Registry with A2A Agent support", "version": "3.3.3", "protocolVersion": "1.0", "supportedInterfaces": [ { "url": "http://localhost:8080", "protocolBinding": "http+json", "protocolVersion": "1.0" } ], "provider": { "organization": "Apicurio", "url": "https://www.apicur.io" }, "capabilities": { "streaming": false, "pushNotifications": false, "extendedAgentCard": false }, "skills": [ { "id": "schema-validation", "name": "Schema Validation", "description": "Validate schemas against format specifications (Avro, JSON Schema, Protobuf, OpenAPI, etc.)", "tags": ["schema", "validation", "avro", "json-schema", "protobuf", "openapi"] }, { "id": "schema-search", "name": "Schema Search", "description": "Search for schemas and APIs in the registry by name, description, labels, or content", "tags": ["schema", "search", "discovery"] } ], "defaultInputModes": ["text/plain"], "defaultOutputModes": ["text/plain"], "securitySchemes": { "bearer": { "type": "httpAuth", "scheme": "Bearer" } } }The example shows two of the five built-in skills. The
securitySchemesobject lists only the mechanisms that are enabled:bearerwhen OIDC authentication is enabled,basicwhen basic authentication is enabled, andapiKeywhenapicurio.a2a.agent.auth.api-key.enabledistrue. The Agent Card includesdocumentationUrlandiconUrlonly when you configure the corresponding properties. - GET /.well-known/agents
-
Searches for registered Agent Cards with filtering support. This endpoint requires no authentication. When any authentication mechanism is enabled, the search returns only the Agent Cards that the caller has permission to view, based on the
apicurio.agent.visibilitylabel.Table 3. Query parameters for /.well-known/agents Parameter Type Description namestring
Filter by artifact name or artifact ID. A value without
matches anywhere in the name or ID. Useas a prefix or suffix wildcard, for exampleweather*.skillstring (repeatable)
Filter by skill ID
capabilitystring (repeatable)
Filter by capability (for example,
streaming:true). Append:falseto require that a capability is absent or disabled.inputModestring (repeatable)
Filter by input mode (for example,
text,image)outputModestring (repeatable)
Filter by output mode
offsetinteger
Pagination offset (default: 0)
limitinteger
Pagination limit (default: 20, maximum: 500)
Example requestcurl "http://localhost:8080/.well-known/agents?skill=translation&capability=streaming:true"Example response: AgentSearchResults{ "count": 1, "agents": [ { "groupId": "ai-agents", "artifactId": "translator-agent", "name": "Translation Agent", "description": "Translates text between languages", "owner": "alice", "createdOn": 1756720530000, "supportedInterfaces": [ { "url": "http://translator:9001", "protocolBinding": "http+json", "protocolVersion": "1.0" } ], "skills": ["translation"], "capabilities": { "streaming": true, "pushNotifications": false } } ] }The
countfield is the total number of matching Agent Cards, not the number of entries in the current page. Theskillsarray lists skill IDs only. To get skill names and descriptions, retrieve the full Agent Card from/.well-known/agents/{groupId}/{artifactId}. - GET /.well-known/agents/{groupId}/{artifactId}
-
Retrieves a specific registered Agent Card.
Path parameters
-
groupId- The group containing the agent card -
artifactId- The artifact ID of the agent cardQuery parameters
-
version(optional) - Specific version (defaults to latest)Response: Agent Card JSON document
-
Agent visibility model
Agent Cards support three visibility levels, controlled by the apicurio.agent.visibility artifact label. When any authentication mechanism is enabled, GET /.well-known/agents and the AI Catalog and ARD endpoints described in AI Catalog and ARD discovery enforce visibility.
| Visibility | Behavior |
|---|---|
|
Visible to everyone, including unauthenticated clients |
|
Visible to callers who can read artifacts: a registry role ( |
|
Visible only to the artifact owner and registry administrators |
curl -X PUT "http://localhost:8080/apis/registry/v3/groups/my-agents/artifacts/my-agent" \
-H "Content-Type: application/json" \
-d '{"labels": {"apicurio.agent.visibility": "public"}}'
How entitlements work: Apicurio Registry maps the A2A community entitlement concept to its existing RBAC model:
-
Groups act as organizational namespaces
-
Entitling a client = granting read access to the group containing the Agent Card artifacts
-
Client authentication happens in an external identity provider, such as Keycloak or another OIDC provider
-
No new authorization primitives are required
| Property | Default | Description |
|---|---|---|
|
|
Default visibility for new Agent Card artifacts ( |
Visibility labels control which Agent Cards appear in /.well-known/agents search results and in the AI Catalog and ARD responses. When you retrieve a card by ID through /.well-known/agents/{groupId}/{artifactId} or the core REST API, only read authorization applies. Apicurio Registry does not check the visibility label.
| When no authentication mechanism is configured (OIDC, basic, proxy header, Kubernetes, or form), Apicurio Registry skips visibility filtering and all agents are visible to all users. |
Agent Card artifact type
Apicurio Registry stores Agent Cards as artifacts with type AGENT_CARD. You can create Agent Cards by using the REST API and you can validate them against the A2A specification JSON schema.
curl -X POST "http://localhost:8080/apis/registry/v3/groups/ai-agents/artifacts" \
-H "Content-Type: application/json" \
-d '{
"artifactId": "my-agent",
"artifactType": "AGENT_CARD",
"firstVersion": {
"version": "1.0.0",
"content": {
"contentType": "application/json",
"content": "{\"name\": \"My Agent\", \"skills\": [{\"id\": \"task\", \"name\": \"Task Execution\"}]}"
}
}
}'
Agent Cards must conform to the A2A specification:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"required": ["name"],
"properties": {
"name": {"type": "string"},
"description": {"type": "string"},
"version": {"type": "string"},
"url": {"type": "string", "format": "uri"},
"provider": {
"type": "object",
"properties": {
"organization": {"type": "string"},
"url": {"type": "string", "format": "uri"}
}
},
"capabilities": {
"type": "object",
"properties": {
"streaming": {"type": "boolean"},
"pushNotifications": {"type": "boolean"}
}
},
"skills": {
"type": "array",
"items": {
"type": "object",
"required": ["id", "name"],
"properties": {
"id": {"type": "string"},
"name": {"type": "string"},
"description": {"type": "string"},
"tags": {"type": "array", "items": {"type": "string"}},
"examples": {"type": "array", "items": {"type": "string"}}
}
}
},
"defaultInputModes": {"type": "array", "items": {"type": "string"}},
"defaultOutputModes": {"type": "array", "items": {"type": "string"}},
"authentication": {
"type": "object",
"properties": {
"schemes": {"type": "array", "items": {"type": "string"}}
}
}
}
}
Auto-generating Agent Cards from OpenAPI specifications
If you already document your API with OpenAPI, you can embed Agent Card metadata directly in your OpenAPI specification’s info block using the x-agent-card vendor extension, instead of authoring and maintaining a separate AGENT_CARD artifact by hand. Apicurio Registry detects the extension, assembles a valid Agent Card from it, and stores it as a companion artifact.
| Property | Default | Description |
|---|---|---|
|
|
Auto-generate a companion AGENT_CARD artifact from the |
|
|
Update the generated Agent Card whenever its source OpenAPI artifact is updated |
apicurio.a2a.openapi-integration.enabled is an experimental property. You must also set apicurio.features.experimental.enabled=true to use it.
|
x-agent-card extensionopenapi: "3.0.0"
info:
title: Weather API
description: Retrieves weather forecasts by city
version: "1.0.0"
x-agent-card:
capabilities: {}
skills:
- id: get-weather
name: Get Weather
description: Retrieve the current weather for a city
tags: [weather]
defaultInputModes: [text]
defaultOutputModes: [text]
servers:
- url: https://weather.example.com
When Apicurio Registry publishes an OPENAPI artifact version with an x-agent-card extension under info, it:
-
Derives any of
name,description, andversionthat the extension does not explicitly set, from the OpenAPI document’s owninfo.title,info.description, andinfo.version. -
Derives
supportedInterfacesfromservers[]only when omitted, expanding server variables using their string defaults and usinghttp+jsonas the binding. Explicit malformed values are rejected rather than replaced. Relative URLs require explicit absolutesupportedInterfaces; the registry does not guess a base URL. Publishers must ensure the advertised endpoint actually implements A2A; OpenAPI alone does not establish this. -
Validates the assembled Agent Card against the same A2A v1.0 schema used for
AGENT_CARDartifacts. If the assembled card is not valid, the OpenAPI write itself is rejected (HTTP 400) with aRuleViolationException, and nothing is persisted. -
Creates or updates
<artifactId>-agent-cardin the same group, checking companion ownership and applying its configured rules. Companion failure is logged and leaves the successful source write intact; rejected companion content is never persisted.
Ordinary DRAFT creates/edits do not generate published companions. Transitioning a draft to a published state validates and generates from its edited content. Dry-run requests do not write companions. Published updates re-read the source tip, and conditional target-version writes prevent a concurrent manual version from being superseded.
Required Agent Card fields with no OpenAPI equivalent — capabilities, skills, defaultInputModes, and defaultOutputModes — must always be supplied explicitly in the extension.
The companion artifact and its source OpenAPI artifact are marked with apicurio.a2a.openapi-agent-card.* labels:
| Label | Meaning |
|---|---|
|
|
|
Identifies the source OpenAPI artifact this companion was generated from |
|
Canonical hash committed with that generated content. Missing or mismatched provenance stops automatic synchronization. |
|
The exact source version; deletion/recreation of the source does not silently adopt the old companion. |
|
The artifact ID of its generated companion Agent Card |
If you edit the generated Agent Card artifact directly, Apicurio Registry detects this the next time the source OpenAPI artifact changes (the companion’s latest version content no longer matches its recorded generated hash) and skips the sync rather than overwriting your edit, logging a warning instead.
If an artifact already exists with the same name as the companion (<artifactId>-agent-card) but was not generated by this feature, Apicurio Registry leaves it untouched and logs a warning rather than overwriting it.
Labels are editable provenance/navigation hints, never authorization grants. Owner-only access is checked independently on the companion. Generation provenance is stored atomically with each version; failure updating the source navigation link can be repaired on a subsequent unchanged-content synchronization. A manually edited version without generation provenance is preserved. Regeneration after manual changes requires an explicit user decision, not deletion of its hash label.
-
REST publication paths trigger generation: first published version, new published version,
ifExists=UPDATE/FIND_OR_CREATE_VERSION, and publication of an edited draft. KafkaSQL REST requests journal both writes; replay itself does not generate an extra companion. Confluent-compatible APIs and read-only GitOps/KubernetesOps imports do not trigger generation. -
Source and companion are separate artifacts, not one transaction. Companion errors leave the source intact; repeated optimistic conflicts are bounded and logged. A later publication retries from current source content.
-
Deleting the source OpenAPI artifact does not delete its generated companion Agent Card.
-
AsyncAPI does not currently support the
x-agent-cardextension.
Agent Card validation rules
Agent Cards have three validation levels that control how much validation occurs when you create or update an Agent Card.
| Level | Description |
|---|---|
|
No validation. |
|
Validates that the content is syntactically valid JSON and is a JSON object. |
|
Complete schema validation including:
|
Agent Card compatibility rules
When you version Agent Cards, Apicurio Registry enforces compatibility rules to ensure that changes do not break existing clients.
Compatible changes (allowed):
-
Adding new skills
-
Adding new capabilities
-
Adding authentication schemes
-
Adding input or output modes
Incompatible changes (can break clients):
-
Removing skills
-
Removing or disabling capabilities
-
Removing supported interfaces (matched by URL and protocol binding)
-
Changing the protocol version on an existing interface
-
Removing security schemes
-
Removing input or output modes
Automatic label extraction for Agent Cards
Apicurio Registry automatically extracts labels from Agent Cards for search. You can use these labels for efficient capability-based discovery by using the Apicurio Registry label search.
| Label pattern | Source |
|---|---|
|
Each skill ID in the |
|
Each enabled capability in the |
|
Each value in the |
|
Each value in the |
|
Each |
|
Each key in the |
|
Each value in the |
Apicurio Registry built-in A2A skills
Apicurio Registry operates as an A2A agent with the following built-in skills.
| Skill ID | Description |
|---|---|
|
Validate schemas against format specifications (Avro, JSON Schema, Protobuf, OpenAPI, AsyncAPI, GraphQL, Thrift, WSDL, XSD) |
|
Search for schemas and APIs in the registry by name, labels, or content |
|
Create, update, and manage schema artifacts with full versioning |
|
Check schema compatibility between versions by using configurable rules |
|
Discover and manage A2A agent cards stored in the registry |
LLM lifecycle management
A2A integration includes full LLM lifecycle management with additional artifact types, including MODEL_SCHEMA and PROMPT_TEMPLATE.
The MODEL_SCHEMA artifact type defines input and output schemas for LLM agents:
{
"$schema": "https://apicurio.io/schemas/model-schema/v1",
"modelId": "sentiment-analysis-output",
"provider": "a2a-demo",
"version": "1.0.0",
"output": {
"type": "object",
"required": ["sentiment", "confidence"],
"properties": {
"sentiment": {"type": "string", "enum": ["positive", "negative", "neutral"]},
"confidence": {"type": "number", "minimum": 0, "maximum": 1}
}
}
}
The PROMPT_TEMPLATE artifact type stores versioned prompt templates with variable support:
templateId: sentiment-analysis
name: Sentiment Analysis Prompt
version: "1.0.0"
template: |
Analyze the sentiment of the following message:
MESSAGE: {{customerMessage}}
Respond with JSON containing sentiment and confidence.
variables:
customerMessage:
type: string
required: true
description: The message to analyze
metadata:
outputSchema: urn:apicurio:llm-agents.schemas/sentiment-output
Agent Cards can reference their schemas and prompts by using URN references:
{
"name": "Sentiment Agent",
"skills": [
{
"id": "sentiment-analysis",
"name": "Sentiment Analysis",
"outputSchema": "urn:apicurio:llm-agents.schemas/sentiment-agent-output",
"promptTemplate": "urn:apicurio:llm-agents.prompts/sentiment-agent-prompt"
}
]
}
Multi-agent workflow example
You can chain context across multiple agents in a pipeline. The a2a-real-world-integration example in the Apicurio Registry repository demonstrates this pattern.
| Step | Input context | Output |
|---|---|---|
1. Sentiment agent |
|
|
2. Issue analyzer |
|
|
3. Response generator |
|
|
4. Translation agent |
|
|
To run the example application locally, clone the Apicurio Registry repository and run the following commands:
cd examples/a2a-real-world-integration
docker-compose up -d
mvn clean compile exec:java
The Web UI is available at localhost:9000.
Java SDK usage for A2A
You can use the Java SDK to discover agents and register Agent Cards programmatically.
RegistryClient client = RegistryClientFactory.create(
RegistryClientOptions.create("http://localhost:8080/apis/registry/v3"));
// Search for agents with specific skill
var agents = client.wellKnown().agents()
.get(config -> {
config.queryParameters.skill = List.of("translation");
config.queryParameters.limit = 10;
});
for (var agent : agents.getAgents()) {
System.out.println("Found: " + agent.getName() + " @ " + agent.getUrl());
}
CreateArtifact artifact = new CreateArtifact();
artifact.setArtifactId("my-agent");
artifact.setArtifactType("AGENT_CARD");
CreateVersion version = new CreateVersion();
version.setVersion("1.0.0");
VersionContent content = new VersionContent();
content.setContentType("application/json");
content.setContent(agentCardJson);
version.setContent(content);
artifact.setFirstVersion(version);
client.groups().byGroupId("ai-agents").artifacts()
.post(artifact, config -> {
config.queryParameters.ifExists = IfArtifactExists.FIND_OR_CREATE_VERSION;
});
A2A REST API endpoints
The following table describes the core A2A endpoints available in Apicurio Registry.
| Endpoint | Method | Description |
|---|---|---|
|
GET |
Get the registry’s own Agent Card |
|
GET |
Search registered Agent Cards |
|
GET |
Get a specific Agent Card by artifact ID |
|
POST |
Create an Agent Card artifact (type: AGENT_CARD) |
|
GET |
Get Agent Card artifact metadata |
|
GET |
Get Agent Card content |
A2A troubleshooting
Use the following information to troubleshoot common issues with A2A features in Apicurio Registry.
- A2A endpoints return 404
-
Set
apicurio.a2a.enabled=truein your configuration:apicurio.a2a.enabled=true - Agent Card validation fails
-
Verify the following conditions:
-
The
namefield is present and non-empty. -
Skills have both
idandnamefields. -
Capabilities are boolean values.
-
The JSON is well-formed.
-
- Search returns no results
-
Verify the following conditions:
-
Agent Cards are stored with type
AGENT_CARD. -
The registry extracted labels correctly (check artifact labels).
-
Search filters match stored values exactly.
-
