A2A Server Guide
Run your agentic Java application as an A2A server following the Agent2Agent Protocol.
A2A Server
The A2A Java SDK provides a Java server implementation of the Agent2Agent (A2A) Protocol. To run your agentic Java application as an A2A server, follow the steps below.
Supported Transports
- JSON-RPC 2.0
- gRPC
- HTTP+JSON/REST
1. Add a Server Dependency
JSON-RPC
<dependency>
<groupId>org.a2aproject.sdk</groupId>
<artifactId>a2a-java-sdk-reference-jsonrpc</artifactId>
<!-- Use a released version from https://github.com/a2aproject/a2a-java/releases -->
<version>${org.a2aproject.sdk.version}</version>
</dependency>
gRPC
<dependency>
<groupId>org.a2aproject.sdk</groupId>
<artifactId>a2a-java-sdk-reference-grpc</artifactId>
<version>${org.a2aproject.sdk.version}</version>
</dependency>
HTTP+JSON/REST
<dependency>
<groupId>org.a2aproject.sdk</groupId>
<artifactId>a2a-java-sdk-reference-rest</artifactId>
<version>${org.a2aproject.sdk.version}</version>
</dependency>
You can add more than one transport dependency to support multiple protocols simultaneously.
2. Define an Agent Card
@ApplicationScoped
public class WeatherAgentCardProducer {
private static final String AGENT_URL = "http://localhost:10001";
@Produces
@PublicAgentCard
public AgentCard agentCard() {
return AgentCard.builder()
.name("Weather Agent")
.description("Helps with weather")
.supportedInterfaces(List.of(
new AgentInterface(TransportProtocol.JSONRPC.asString(), AGENT_URL)))
.version("1.0.0")
.capabilities(AgentCapabilities.builder()
.streaming(true)
.pushNotifications(false)
.build())
.defaultInputModes(Collections.singletonList("text"))
.defaultOutputModes(Collections.singletonList("text"))
.skills(Collections.singletonList(AgentSkill.builder()
.id("weather_search")
.name("Search weather")
.description("Helps with weather in cities or states")
.tags(Collections.singletonList("weather"))
.examples(List.of("weather in LA, CA"))
.build()))
.build();
}
}
3. Implement an Agent Executor
@ApplicationScoped
public class WeatherAgentExecutorProducer {
@Inject
WeatherAgent weatherAgent;
@Produces
public AgentExecutor agentExecutor() {
return new WeatherAgentExecutor(weatherAgent);
}
private static class WeatherAgentExecutor implements AgentExecutor {
private final WeatherAgent weatherAgent;
public WeatherAgentExecutor(WeatherAgent weatherAgent) {
this.weatherAgent = weatherAgent;
}
@Override
public void execute(RequestContext context, AgentEmitter agentEmitter) throws JSONRPCError {
if (context.getTask() == null) {
agentEmitter.submit();
}
agentEmitter.startWork();
String userMessage = extractTextFromMessage(context.getMessage());
String response = weatherAgent.chat(userMessage);
agentEmitter.addArtifact(List.of(new TextPart(response)));
agentEmitter.complete();
}
@Override
public void cancel(RequestContext context, AgentEmitter agentEmitter) throws JSONRPCError {
Task task = context.getTask();
if (task == null) {
agentEmitter.cancel();
return;
}
if (task.getStatus().state() == TaskState.CANCELED ||
task.getStatus().state() == TaskState.COMPLETED) {
throw new TaskNotCancelableError();
}
agentEmitter.cancel();
}
private String extractTextFromMessage(Message message) {
if (message == null) {
return "";
}
StringBuilder textBuilder = new StringBuilder();
for (Part<?> part : message.parts()) {
if (part instanceof TextPart textPart) {
textBuilder.append(textPart.text());
}
}
return textBuilder.toString();
}
}
}
4. Configuration
See Configuration for all config properties and tuning.
5. Task Authorization (Optional)
See Task Authorization for per-user access control.
Backward Compatibility with v0.3
See Backward Compatibility for multi-version modules, version routing, and v0.3 client support.
Server Integrations
- Quarkus — Reference implementations are Quarkus-based (JSON-RPC, gRPC, REST)
- Jakarta EE — a2a-jakarta works with any Jakarta EE Web Profile runtime
See CONTRIBUTING_INTEGRATIONS.md to submit your own integration.