MCPcopy Index your code
hub / github.com/a2aproject/a2a-java

github.com/a2aproject/a2a-java @v1.1.0.Final

Chat with this repo
repository ↗ · DeepWiki ↗ · release v1.1.0.Final ↗ · + Follow
13,554 symbols 53,650 edges 1,038 files 6,077 documented · 45%
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

A2A Java SDK

License

A2A Logo

A Java library that helps run agentic applications as A2AServers following the Agent2Agent (A2A) Protocol.

Installation

You can build the A2A Java SDK using mvn:

mvn clean install

Regeneration of gRPC files

We copy https://github.com/a2aproject/A2A/blob/main/specification/grpc/a2a.proto to the spec-grpc/ project, and adjust the java_package option to be as follows:

option java_package = "org.a2aproject.sdk.grpc";

Then build the spec-grpc module with mvn clean install -Dskip.protobuf.generate=false to regenerate the gRPC classes in the org.a2aproject.sdk.grpc package.

Examples

You can find examples of how to use the A2A Java SDK in the a2a-samples repository.

More examples will be added soon.

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, simply follow the steps below.

1. Add an A2A Java SDK Server Maven dependency to your project

Adding a dependency on an A2A Java SDK Server will provide access to the core classes that make up the A2A specification and allow you to run your agentic Java application as an A2A server agent.

The A2A Java SDK provides reference A2A server implementations based on Quarkus for use with our tests and examples. However, the project is designed in such a way that it is trivial to integrate with various Java runtimes.

Server Integrations contains a list of community contributed integrations of the server with various runtimes. You might be able to use one of these for your target runtime, or you can use them as inspiration to create your own.

Server Transports

The A2A Java SDK Reference Server implementations support the following transports:

  • JSON-RPC 2.0
  • gRPC
  • HTTP+JSON/REST

To use the reference implementation with the JSON-RPC protocol, add the following dependency to your project:

<dependency>
    <groupId>org.a2aproject.sdk</groupId>
    <artifactId>a2a-java-sdk-reference-jsonrpc</artifactId>

    <version>${org.a2aproject.sdk.version}</version>
</dependency>

To use the reference implementation with the gRPC protocol, add the following dependency to your project:

<dependency>
    <groupId>org.a2aproject.sdk</groupId>
    <artifactId>a2a-java-sdk-reference-grpc</artifactId>

    <version>${org.a2aproject.sdk.version}</version>
</dependency>

To use the reference implementation with the HTTP+JSON/REST protocol, add the following dependency to your project:

<dependency>
    <groupId>org.a2aproject.sdk</groupId>
    <artifactId>a2a-java-sdk-reference-rest</artifactId>

    <version>${org.a2aproject.sdk.version}</version>
</dependency>

Note that you can add more than one of the above dependencies to your project depending on the transports you'd like to support.

2. Add a class that creates an A2A Agent Card

import org.a2aproject.sdk.server.PublicAgentCard;
import org.a2aproject.sdk.spec.AgentCapabilities;
import org.a2aproject.sdk.spec.AgentCard;
import org.a2aproject.sdk.spec.AgentInterface;
import org.a2aproject.sdk.spec.AgentSkill;
import org.a2aproject.sdk.spec.TransportProtocol;
...

@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. Add a class that creates an A2A Agent Executor

import org.a2aproject.sdk.server.agentexecution.AgentExecutor;
import org.a2aproject.sdk.server.agentexecution.RequestContext;
import org.a2aproject.sdk.server.events.EventQueue;
import org.a2aproject.sdk.server.tasks.AgentEmitter;
import org.a2aproject.sdk.spec.JSONRPCError;
import org.a2aproject.sdk.spec.Message;
import org.a2aproject.sdk.spec.Part;
import org.a2aproject.sdk.spec.Task;
import org.a2aproject.sdk.spec.TaskNotCancelableError;
import org.a2aproject.sdk.spec.TaskState;
import org.a2aproject.sdk.spec.TextPart;
...

@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 {
            // mark the task as submitted and start working on it
            if (context.getTask() == null) {
                agentEmitter.submit();
            }
            agentEmitter.startWork();

            // extract the text from the message
            String userMessage = extractTextFromMessage(context.getMessage());

            // call the weather agent with the user's message
            String response = weatherAgent.chat(userMessage);

            // create the response part
            TextPart responsePart = new TextPart(response);
            List<Part<?>> parts = List.of(responsePart);

            // add the response as an artifact and complete the task
            agentEmitter.addArtifact(parts);
            agentEmitter.complete();
        }

        @Override
        public void cancel(RequestContext context, AgentEmitter agentEmitter) throws JSONRPCError {
            Task task = context.getTask();

            if (task.getStatus().state() == TaskState.CANCELED) {
                // task already cancelled
                throw new TaskNotCancelableError();
            }

            if (task.getStatus().state() == TaskState.COMPLETED) {
                // task already completed
                throw new TaskNotCancelableError();
            }

            // cancel the task
            agentEmitter.cancel();
        }

        private String extractTextFromMessage(Message message) {
            StringBuilder textBuilder = new StringBuilder();
            for (Part<?> part : message.parts()) {
                if (part instanceof TextPart textPart) {
                    textBuilder.append(textPart.text());
                }
            }
            return textBuilder.toString();
        }
    }
}

4. Configuration System

The A2A Java SDK uses a flexible configuration system that works across different frameworks.

Default behavior: Configuration values come from META-INF/a2a-defaults.properties files on the classpath (provided by core modules and extras). These defaults work out of the box without any additional setup.

Customizing configuration: - Quarkus/MicroProfile Config users: Add the microprofile-config integration to override defaults via application.properties, environment variables, or system properties - Spring/other frameworks: See the integration module README for how to implement a custom A2AConfigProvider - Reference implementations: Already include the MicroProfile Config integration

Configuration Properties

Executor Settings (Optional)

The SDK uses a dedicated executor for async operations like streaming. Default: 5 core threads, 50 max threads.

# Core thread pool size for the @Internal executor (default: 5)
a2a.executor.core-pool-size=5

# Maximum thread pool size (default: 50)
a2a.executor.max-pool-size=50

# Thread keep-alive time in seconds (default: 60)
a2a.executor.keep-alive-seconds=60

Blocking Call Timeouts (Optional)

# Timeout for agent execution in blocking calls (default: 30 seconds)
a2a.blocking.agent.timeout.seconds=30

# Timeout for event consumption in blocking calls (default: 5 seconds)
a2a.blocking.consumption.timeout.seconds=5

Why this matters: - Streaming Performance: The executor handles streaming subscriptions. Too few threads can cause timeouts under concurrent load. - Resource Management: The dedicated executor prevents streaming operations from competing with the ForkJoinPool. - Concurrency: In production with high concurrent streaming, increase pool sizes accordingly. - Agent Timeouts: LLM-based agents may need longer timeouts (60-120s) compared to simple agents.

Note: The reference server implementations (Quarkus-based) automatically include the MicroProfile Config integration, so properties work out of the box in application.properties.

5. Task Authorization (Optional)

The SDK includes an opt-in SPI for per-user task authorization. When enabled, every RequestHandler operation checks whether the authenticated user is allowed to access the target task before proceeding. When no provider is present, all operations are permitted (the default).

⚠ Security note: For multi-user deployments, a TaskAuthorizationProvider must be configured. Without one, all operations are permitted regardless of authentication — any authenticated user can read, modify, or cancel any task. Production deployments should use a fail-closed ownership policy (deny access when ownership is unknown).

Providing an implementation

Create an @ApplicationScoped CDI bean that implements TaskAuthorizationProvider:

import jakarta.enterprise.context.ApplicationScoped;
import org.a2aproject.sdk.server.auth.TaskAuthorizationProvider;
import org.a2aproject.sdk.server.auth.TaskOperation;
import org.a2aproject.sdk.server.ServerCallContext;

@ApplicationScoped
public class MyTaskAuthorizationProvider implements TaskAuthorizationProvider {

    @Override
    public boolean checkRead(ServerCallContext context, String taskId, TaskOperation op) {
        // Return true to allow, false to deny.
        // Denied reads throw TaskNotFoundError — the caller cannot distinguish
        // "not found" from "not authorized", preventing information leakage.
        String owner = ownershipStore.get(taskId);
        if (owner == null) {
            return false; // fail-closed: unknown ownership → deny
        }
        return owner.equals(context.getUser().getUsername());
    }

    @Override
    public boolean checkWrite(ServerCallContext context, String taskId, TaskOperation op) {
        return checkRead(context, taskId, op);
    }

    @Override
    public boolean checkCreate(ServerCallContext context, TaskOperation op) {
        return context.getUser().isAuthenticated();
    }

    @Override
    public boolean isTaskRecorded(String taskId) {
        return ownershipStore.contains(taskId);
    }

    @Override
    public void recordOwnership(ServerCallContext context, String taskId, TaskOperation op) {
        ownershipStore.put(taskId, context.getUser().getUsername());
    }
}

No additional configuration is required — the SDK automatically discovers the bean via CDI and wires it into the request pipeline. See the TaskAuthorizationProvider javadoc for the full contract, including thread-safety requirements and ownership-recording semantics.

User identity in ServerCallContext

Authorization decisions rely on context.getUser() returning the authenticated user. How the user is populated depends on the transport:

  • JSON-RPC and REST: The Quarkus route handler extracts the user from the Vert.x routing context (rc.userContext()) and sets it on ServerCallContext directly.
  • gRPC: The reference server includes a QuarkusCallContextFactory CDI bean that injects the Quarkus SecurityIdentity and maps it to the ServerCallContext User. T

Extension points exported contracts — how you extend this code

ClientTransportProvider (Interface)
Client transport provider interface. [6 implementers]
client/transport/spi/src/main/java/org/a2aproject/sdk/client/transport/spi/ClientTransportProvider.java
ClientTransportProvider_v0_3 (Interface)
Client transport provider interface. [6 implementers]
compat-0.3/client/transport/spi/src/main/java/org/a2aproject/sdk/compat03/client/transport/spi/ClientTransportProvider_v0_3.java
StreamingEventKind_v0_3 (Interface)
Sealed interface for events that can be emitted during streaming A2A Protocol operations. StreamingEventKind represe [8 …
compat-0.3/spec/src/main/java/org/a2aproject/sdk/compat03/spec/StreamingEventKind_v0_3.java
A2AMessage (Interface)
Base interface for all JSON-RPC 2.0 protocol messages in the A2A Protocol. This sealed interface defines the fundame [6 …
jsonrpc-common/src/main/java/org/a2aproject/sdk/jsonrpc/common/wrappers/A2AMessage.java
TransportMetadata (Interface)
Interface for transport endpoint implementations to provide metadata about their transport. This is used by the validati [8 …
server-common/src/main/java/org/a2aproject/sdk/server/TransportMetadata.java
A2AHttpClientProvider (Interface)
Service provider interface for creating A2AHttpClient instances. Implementations of this interface can be r [6 implementers]
http-client/src/main/java/org/a2aproject/sdk/client/http/A2AHttpClientProvider.java
EventKind (Interface)
Interface for events that can be returned from non-streaming A2A Protocol operations. EventKind represents events th [8 …
spec/src/main/java/org/a2aproject/sdk/spec/EventKind.java
MutualTlsSecuritySchemeOrBuilder (Interface)
(no doc) [21 implementers]
compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/MutualTlsSecuritySchemeOrBuilder.java

Core symbols most depended-on inside this repo

get
called by 1571
server-common/src/main/java/org/a2aproject/sdk/server/tasks/TaskStore.java
build
called by 1235
reference/jsonrpc/src/main/java/org/a2aproject/sdk/server/apps/quarkus/CallContextFactory.java
of
called by 803
http-client/src/main/java/org/a2aproject/sdk/client/http/A2AHttpHeaders.java
id
called by 770
spec/src/main/java/org/a2aproject/sdk/spec/Task.java
build
called by 729
compat-0.3/reference/jsonrpc/src/main/java/org/a2aproject/sdk/compat03/server/apps/quarkus/CallContextFactory_v0_3.java
getMessage
called by 702
spec-grpc/src/main/java/org/a2aproject/sdk/grpc/TaskStatusOrBuilder.java
status
called by 648
http-client/src/main/java/org/a2aproject/sdk/client/http/A2AHttpResponse.java
size
called by 580
server-common/src/main/java/org/a2aproject/sdk/server/events/EventQueue.java

Shape

Method 12,214
Class 1,093
Interface 221
Enum 26

Languages

Java100%

Modules by API surface

compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/AgentCard.java244 symbols
spec-grpc/src/main/java/org/a2aproject/sdk/grpc/AgentCard.java230 symbols
spec-grpc/src/main/java/org/a2aproject/sdk/grpc/AgentSkill.java129 symbols
compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/AgentSkill.java129 symbols
spec-grpc/src/main/java/org/a2aproject/sdk/grpc/Message.java120 symbols
spec-grpc/src/main/java/org/a2aproject/sdk/grpc/Task.java109 symbols
compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/Task.java109 symbols
compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/Message.java106 symbols
spec-grpc/src/main/java/org/a2aproject/sdk/grpc/Part.java101 symbols
spec-grpc/src/main/java/org/a2aproject/sdk/grpc/Artifact.java99 symbols
spec-grpc/src/main/java/org/a2aproject/sdk/grpc/A2AServiceGrpc.java99 symbols
compat-0.3/spec-grpc/src/main/java/org/a2aproject/sdk/compat03/grpc/Artifact.java99 symbols

Datastores touched

a2aDatabase · 1 repos
a2a_dbDatabase · 1 repos
a2adbDatabase · 1 repos

For agents

$ claude mcp add a2a-java \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact