# a2a-java
**Repository Path**: abaoworld/a2a-java
## Basic Information
- **Project Name**: a2a-java
- **Description**: No description available
- **Primary Language**: Unknown
- **License**: Apache-2.0
- **Default Branch**: code-analysis
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2026-06-19
- **Last Updated**: 2026-06-19
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# A2A Java SDK
[](LICENSE)
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`:
```bash
mvn clean install
```
### Regeneration of gRPC files
We copy https://github.com/a2aproject/A2A/blob/main/specification/grpc/a2a.proto to the [`spec-grpc/`](./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](https://github.com/a2aproject/a2a-samples/tree/main/samples/java/agents).
More examples will be added soon.
## A2A Server
The A2A Java SDK provides a Java server implementation of the [Agent2Agent (A2A) Protocol](https://a2a-protocol.org/). To run your agentic Java application as an A2A server, simply follow the steps below.
- [Add an A2A Java SDK Server Maven dependency to your project](#1-add-an-a2a-java-sdk-server-maven-dependency-to-your-project)
- [Add a class that creates an A2A Agent Card](#2-add-a-class-that-creates-an-a2a-agent-card)
- [Add a class that creates an A2A Agent Executor](#3-add-a-class-that-creates-an-a2a-agent-executor)
### 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](reference) based on [Quarkus](https://quarkus.io) 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](#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:
```xml
org.a2aproject.sdk
a2a-java-sdk-reference-jsonrpc
${org.a2aproject.sdk.version}
```
To use the reference implementation with the gRPC protocol, add the following dependency to your project:
```xml
org.a2aproject.sdk
a2a-java-sdk-reference-grpc
${org.a2aproject.sdk.version}
```
To use the reference implementation with the HTTP+JSON/REST protocol, add the following dependency to your project:
```xml
org.a2aproject.sdk
a2a-java-sdk-reference-rest
${org.a2aproject.sdk.version}
```
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
```java
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
```java
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> 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`](integrations/microprofile-config/README.md) integration to override defaults via `application.properties`, environment variables, or system properties
- **Spring/other frameworks**: See the [integration module README](integrations/microprofile-config/README.md#custom-config-providers) 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.
```properties
# 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)
```properties
# 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`.
### Serving Older Protocol Versions (Backward Compatibility)
The A2A Java SDK includes compatibility layers that allow your server to accept requests from clients using older protocol versions. Each compatibility layer is a separate set of modules that you add to your project as needed. **No changes to your `AgentExecutor` are needed** — the compatibility layer converts older protocol requests to v1.0 internally before delegating to your agent.
#### Adding v0.3 Protocol Support
To enable v0.3 support, add the v0.3 compat reference module for your chosen transport alongside (or instead of) the v1.0 reference module:
```xml
org.a2aproject.sdk
a2a-java-sdk-compat-0.3-reference-jsonrpc
${org.a2aproject.sdk.version}
org.a2aproject.sdk
a2a-java-sdk-compat-0.3-reference-rest
${org.a2aproject.sdk.version}
org.a2aproject.sdk
a2a-java-sdk-compat-0.3-reference-grpc
${org.a2aproject.sdk.version}
```
For example, a server that supports **v1.0 and v0.3 over JSON-RPC** would include both:
```xml
org.a2aproject.sdk
a2a-java-sdk-reference-jsonrpc
${org.a2aproject.sdk.version}
org.a2aproject.sdk
a2a-java-sdk-compat-0.3-reference-jsonrpc
${org.a2aproject.sdk.version}
```
A server that only needs to support **v0.3** would include only the compat dependency.
#### Multi-Version Convenience Modules
For JSON-RPC and REST, multi-version modules are provided that bundle all supported protocol versions together with version-dispatching routes:
```xml
org.a2aproject.sdk
a2a-java-sdk-reference-multiversion-jsonrpc
${org.a2aproject.sdk.version}
org.a2aproject.sdk
a2a-java-sdk-reference-multiversion-rest
${org.a2aproject.sdk.version}
```
These are a convenience — they transitively include all the individual compat reference modules.
#### How Version Routing Works
- **JSON-RPC and REST**: When serving multiple protocol versions, version routing inspects the `A2A-Version` HTTP header on each request. If the header is `"1.0"`, the request is routed to the v1.0 handler. If it is `"0.3"` or absent, the request is routed to the v0.3 handler.
- **gRPC**: Version dispatch is implicit — v0.3 clients use the `a2a.v1` protobuf package and v1.0 clients use `lf.a2a.v1`, so requests are routed to the correct service automatically.
- **Agent card**: When both v1.0 and v0.3 are enabled, the v1.0 `AgentCard` takes precedence and is served at `/.well-known/agent-card.json`. The v0.3 `AgentCard_v0_3` is ignored. If only v0.3 is enabled, the v0.3 agent card is used. If only v1.0 is enabled, the v1.0 agent card is used as-is.
#### Making the v1.0 Agent Card Compatible with v0.3 Clients
When serving both protocol versions, you need to ensure the v1.0 agent card contains fields that v0.3 clients expect. Existing v0.3 client implementations (in any language) look for `url`, `preferredTransport`, and `additionalInterfaces` with `transport`/`url` entries — fields that don't exist in the v1.0 format by default.
To make your v1.0 `AgentCard` parsable by v0.3 clients, set these fields on the builder:
```java
AgentCard card = AgentCard.builder()
.name("My Agent")
// ... other v1.0 fields ...
.supportedInterfaces(List.of(
new AgentInterface("jsonrpc", "http://localhost:9999")))
// v0.3 backward-compatibility fields:
.url("http://localhost:9999")
.preferredTransport("jsonrpc")
.additionalInterfaces(List.of(
new Legacy_0_3_AgentInterface("jsonrpc", "http://localhost:9999")))
.build();
```
The two interface lists serve different clients:
- `supportedInterfaces` — used by **v1.0 clients** to discover endpoints (uses `AgentInterface` with `protocolBinding`/`url`/`tenant` fields)
- `additionalInterfaces` — used by **v0.3 clients** to discover endpoints (uses `Legacy_0_3_AgentInterface` with v0.3 field names: `transport`/`url`)
- `url` and `preferredTransport` — top-level fields that v0.3 clients use to discover the primary endpoint
#### Push Notification Behavior
Push notification payloads are automatically formatted to match the protocol version used when the push notification configuration was registered. When a v0.3 client registers a push notification configuration (via any transport), the server records the protocol version alongside the configuration. When a notification is later sent to that webhook, the payload is formatted as a v0.3 Task object. Configurations registered by v1.0 clients receive v1.0 `StreamResponse` payloads as usual. This happens transparently — no additional configuration is needed beyond adding the compat reference module.
## A2A Client
The A2A Java SDK provides a Java client implementation of the [Agent2Agent (A2A) Protocol](https://a2a-protocol.org/), allowing communication with A2A servers. The Java client implementation supports the following transports:
* JSON-RPC 2.0
* gRPC
* HTTP+JSON/REST
To make use of the Java `Client`:
### 1. Add the A2A Java SDK Client dependency to your project
Adding a dependency on `a2a-java-sdk-client` will provide access to a `ClientBuilder`
that you can use to create your A2A `Client`.
```xml
org.a2aproject.sdk
a2a-java-sdk-client
${org.a2aproject.sdk.version}
```
### 2. Add one or more dependencies on the A2A Java SDK Client Transport(s) you'd like to use
By default, the `sdk-client` artifact includes the JSONRPC transport dependency. However, you must still explicitly configure this transport when building the `Client` as described in the [JSON-RPC Transport section](#json-rpc-transport-configuration).
If you want to use the gRPC transport, you'll need to add a relevant dependency:
```xml
org.a2aproject.sdk
a2a-java-sdk-client-transport-grpc
${org.a2aproject.sdk.version}
```
If you want to use the HTTP+JSON/REST transport, you'll need to add a relevant dependency:
```xml
org.a2aproject.sdk
a2a-java-sdk-client-transport-rest
${org.a2aproject.sdk.version}
```
### Sample Usage
#### Create a Client using the ClientBuilder
```java
// First, get the agent card for the A2A server agent you want to connect to
AgentCard agentCard = A2ACardResolver.builder().baseUrl("http://localhost:1234").build().getAgentCard();
// Specify configuration for the ClientBuilder
ClientConfig clientConfig = new ClientConfig.Builder()
.setAcceptedOutputModes(List.of("text"))
.build();
// Create event consumers to handle responses that will be received from the A2A server
// (these consumers will be used for both streaming and non-streaming responses)
List> consumers = List.of(
(event, card) -> {
if (event instanceof MessageEvent messageEvent) {
// handle the messageEvent.getMessage()
...
} else if (event instanceof TaskEvent taskEvent) {
// handle the taskEvent.getTask()
...
} else if (event instanceof TaskUpdateEvent updateEvent) {
// handle the updateEvent.getTask()
...
}
}
);
// Create a handler that will be used for any errors that occur during streaming
Consumer errorHandler = error -> {
// handle the error.getMessage()
...
};
// Create the client using the builder
Client client = Client
.builder(agentCard)
.clientConfig(clientConfig)
.withTransport(JSONRPCTransport.class, new JSONRPCTransportConfig())
.addConsumers(consumers)
.streamingErrorHandler(errorHandler)
.build();
```
#### Configuring Transport-Specific Settings
Different transport protocols can be configured with specific settings using specific `ClientTransportConfig` implementations. The A2A Java SDK provides `JSONRPCTransportConfig` for the JSON-RPC transport and `GrpcTransportConfig` for the gRPC transport.
##### JSON-RPC Transport Configuration
For the JSON-RPC transport, to use the default `JdkA2AHttpClient`, provide a `JSONRPCTransportConfig` created with its default constructor.
To use a custom HTTP client implementation, simply create a `JSONRPCTransportConfig` as follows:
```java
// Create a custom HTTP client
A2AHttpClient customHttpClient = ...
// Configure the client settings
ClientConfig clientConfig = new ClientConfig.Builder()
.setAcceptedOutputModes(List.of("text"))
.build();
Client client = Client
.builder(agentCard)
.clientConfig(clientConfig)
.withTransport(JSONRPCTransport.class, new JSONRPCTransportConfig(customHttpClient))
.build();
```
To customize the default JDK HTTP client without replacing the SDK implementation, provide
your own `java.net.http.HttpClient` to `JdkA2AHttpClient`:
```java
HttpClient jdkHttpClient = HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(5))
.followRedirects(HttpClient.Redirect.NORMAL)
.version(HttpClient.Version.HTTP_2)
.build();
Client client = Client
.builder(agentCard)
.withTransport(JSONRPCTransport.class, new JSONRPCTransportConfig(
new JdkA2AHttpClient(jdkHttpClient)))
.build();
```
##### gRPC Transport Configuration
For the gRPC transport, you must configure a channel factory:
```java
// Create a channel factory function that takes the agent URL and returns a Channel
Function channelFactory = agentUrl -> {
return ManagedChannelBuilder.forTarget(agentUrl)
...
.build();
};
// Configure the client with transport-specific settings
ClientConfig clientConfig = new ClientConfig.Builder()
.setAcceptedOutputModes(List.of("text"))
.build();
Client client = Client
.builder(agentCard)
.clientConfig(clientConfig)
.withTransport(GrpcTransport.class, new GrpcTransportConfig(channelFactory))
.build();
```
##### HTTP+JSON/REST Transport Configuration
For the HTTP+JSON/REST transport, if you'd like to use the default `JdkA2AHttpClient`, provide a `RestTransportConfig` created with its default constructor.
To use a custom HTTP client implementation, simply create a `RestTransportConfig` as follows:
```java
// Create a custom HTTP client
A2AHttpClient customHttpClient = ...
// Configure the client settings
ClientConfig clientConfig = new ClientConfig.Builder()
.setAcceptedOutputModes(List.of("text"))
.build();
Client client = Client
.builder(agentCard)
.clientConfig(clientConfig)
.withTransport(RestTransport.class, new RestTransportConfig(customHttpClient))
.build();
```
##### Multiple Transport Configurations
You can specify configuration for multiple transports, the appropriate configuration
will be used based on the selected transport:
```java
// Configure both JSON-RPC and gRPC transports
Client client = Client
.builder(agentCard)
.withTransport(GrpcTransport.class, new GrpcTransportConfig(channelFactory))
.withTransport(JSONRPCTransport.class, new JSONRPCTransportConfig())
.withTransport(RestTransport.class, new RestTransportConfig())
.build();
```
#### Send a message to the A2A server agent
```java
// Send a text message to the A2A server agent
Message message = A2A.toUserMessage("tell me a joke");
// Send the message (uses configured consumers to handle responses)
// Streaming will automatically be used if supported by both client and server,
// otherwise the non-streaming send message method will be used automatically
client.sendMessage(message);
// You can also optionally specify a ClientCallContext with call-specific config to use
client.sendMessage(message, clientCallContext);
```
#### Send a message with custom event handling
```java
// Create custom consumers for this specific message
List> customConsumers = List.of(
(event, card) -> {
// handle this specific message's responses
...
}
);
// Create custom error handler
Consumer customErrorHandler = error -> {
// handle the error
...
};
Message message = A2A.toUserMessage("tell me a joke");
client.sendMessage(message, customConsumers, customErrorHandler);
```
#### Get the current state of a task
```java
// Retrieve the task with id "task-1234"
Task task = client.getTask(new TaskQueryParams("task-1234"));
// You can also specify the maximum number of history items for the task
// to include in the response
Task task = client.getTask(new TaskQueryParams("task-1234", 10));
// You can also optionally specify a ClientCallContext with call-specific config to use
Task task = client.getTask(new TaskQueryParams("task-1234"), clientCallContext);
```
#### Cancel an ongoing task
```java
// Cancel the task we previously submitted with id "task-1234"
Task cancelledTask = client.cancelTask(new TaskIdParams("task-1234"));
// You can also specify additional properties using a map
Map metadata = Map.of("reason", "user_requested");
Task cancelledTask = client.cancelTask(new TaskIdParams("task-1234", metadata));
// You can also optionally specify a ClientCallContext with call-specific config to use
Task cancelledTask = client.cancelTask(new TaskIdParams("task-1234"), clientCallContext);
```
#### Get a push notification configuration for a task
```java
// Get task push notification configuration
TaskPushNotificationConfig config = client.getTaskPushNotificationConfiguration(
new GetTaskPushNotificationConfigParams("task-1234"));
// The push notification configuration ID can also be optionally specified
TaskPushNotificationConfig config = client.getTaskPushNotificationConfiguration(
new GetTaskPushNotificationConfigParams("task-1234", "config-4567"));
// Additional properties can be specified using a map
Map metadata = Map.of("source", "client");
TaskPushNotificationConfig config = client.getTaskPushNotificationConfiguration(
new GetTaskPushNotificationConfigParams("task-1234", "config-1234", metadata));
// You can also optionally specify a ClientCallContext with call-specific config to use
TaskPushNotificationConfig config = client.getTaskPushNotificationConfiguration(
new GetTaskPushNotificationConfigParams("task-1234"), clientCallContext);
```
#### Set a push notification configuration for a task
```java
// Set task push notification configuration
PushNotificationConfig pushNotificationConfig = PushNotificationConfig.builder()
.url("https://example.com/callback")
.authenticationInfo(new AuthenticationInfo(Collections.singletonList("jwt"), null))
.build();
TaskPushNotificationConfig taskConfig = TaskPushNotificationConfig.builder()
.taskId("task-1234")
.pushNotificationConfig(pushNotificationConfig)
.build();
TaskPushNotificationConfig result = client.createTaskPushNotificationConfiguration(taskConfig);
// You can also optionally specify a ClientCallContext with call-specific config to use
TaskPushNotificationConfig result = client.createTaskPushNotificationConfiguration(taskConfig, clientCallContext);
```
#### List the push notification configurations for a task
```java
List configs = client.listTaskPushNotificationConfigurations(
new ListTaskPushNotificationConfigParams("task-1234"));
// Additional properties can be specified using a map
Map metadata = Map.of("filter", "active");
List configs = client.listTaskPushNotificationConfigurations(
new ListTaskPushNotificationConfigParams("task-1234", metadata));
// You can also optionally specify a ClientCallContext with call-specific config to use
List configs = client.listTaskPushNotificationConfigurations(
new ListTaskPushNotificationConfigParams("task-1234"), clientCallContext);
```
#### Delete a push notification configuration for a task
```java
client.deleteTaskPushNotificationConfigurations(
new DeleteTaskPushNotificationConfigParams("task-1234", "config-4567"));
// Additional properties can be specified using a map
Map metadata = Map.of("reason", "cleanup");
client.deleteTaskPushNotificationConfigurations(
new DeleteTaskPushNotificationConfigParams("task-1234", "config-4567", metadata));
// You can also optionally specify a ClientCallContext with call-specific config to use
client.deleteTaskPushNotificationConfigurations(
new DeleteTaskPushNotificationConfigParams("task-1234", "config-4567", clientCallContext);
```
#### Subscribe to a task
```java
// Subscribe to an ongoing task with id "task-1234" using configured consumers
TaskIdParams taskIdParams = new TaskIdParams("task-1234");
client.subscribeToTask(taskIdParams);
// Or subscribe with custom consumers and error handler
List> customConsumers = List.of(
(event, card) -> System.out.println("Subscribe event: " + event)
);
Consumer customErrorHandler = error ->
System.err.println("Subscribe error: " + error.getMessage());
client.subscribeToTask(taskIdParams, customConsumers, customErrorHandler);
// You can also optionally specify a ClientCallContext with call-specific config to use
client.subscribeToTask(taskIdParams, clientCallContext);
```
#### Retrieve details about the server agent that this client agent is communicating with
```java
AgentCard serverAgentCard = client.getAgentCard();
```
### Communicating with v0.3 Agents
If you need to communicate with an agent that only supports protocol v0.3, use the compatibility client `Client_v0_3`.
#### 1. Add the v0.3 client dependency
```xml
org.a2aproject.sdk
a2a-java-sdk-compat-0.3-client
${org.a2aproject.sdk.version}
```
#### 2. Add a v0.3 client transport dependency
```xml
org.a2aproject.sdk
a2a-java-sdk-compat-0.3-client-transport-jsonrpc
${org.a2aproject.sdk.version}
```
gRPC and REST transports are also available:
- `a2a-java-sdk-compat-0.3-client-transport-grpc`
- `a2a-java-sdk-compat-0.3-client-transport-rest`
#### 3. Create the v0.3 client
```java
AgentCard card = A2ACardResolver.builder().baseUrl("http://localhost:1234").build().getAgentCard();
// Find the v0.3 interface from the agent card
AgentInterface v03Interface = card.supportedInterfaces().stream()
.filter(iface -> A2AProtocol_v0_3.PROTOCOL_VERSION.equals(iface.protocolVersion()))
.findFirst()
.orElseThrow();
// Create the v0.3 compatibility client
Client_v0_3 client = ClientBuilder_v0_3.forUrl(v03Interface.url())
.withTransport(JSONRPCTransport_v0_3.class, new JSONRPCTransportConfigBuilder_v0_3())
.build();
```
**Note:** `Client_v0_3` exposes only operations available in protocol v0.3. For example, `listTasks()` is not available (it was added in v1.0). Return types use v0.3 domain objects from the `org.a2aproject.sdk.compat03.spec` package.
## Additional Examples
### Hello World Client Example
A complete example of a Java A2A client communicating with a Python A2A server is available in the [examples/helloworld/client](examples/helloworld/client/README.md) directory. This example demonstrates:
- Setting up and using the A2A Java client
- Sending regular and streaming messages to a Python A2A server
- Receiving and processing responses from the Python A2A server
The example includes detailed instructions on how to run the Python A2A server and how to run the Java A2A client using JBang.
Check out the [example's README](examples/helloworld/client/README.md) for more information.
### Hello World Server Example
A complete example of a Python A2A client communicating with a Java A2A server is available in the [examples/helloworld/server](examples/helloworld/server/README.md) directory. This example demonstrates:
- A sample `AgentCard` producer
- A sample `AgentExecutor` producer
- A Java A2A server receiving regular and streaming messages from a Python A2A client
Check out the [example's README](examples/helloworld/server/README.md) for more information.
## Community Articles
See [COMMUNITY_ARTICLES.md](COMMUNITY_ARTICLES.md) for a list of community articles and videos.
## License
This project is licensed under the terms of the [Apache 2.0 License](LICENSE).
## Contributing
See [CONTRIBUTING.md](CONTRIBUTING.md) for contribution guidelines.
## Server Integrations
The following list contains community contributed integrations with various Java Runtimes.
To contribute an integration, please see [CONTRIBUTING_INTEGRATIONS.md](CONTRIBUTING_INTEGRATIONS.md).
* This project contains integration with Quarkus and has the reference implementations for the JSON-RPC, gRPC, and HTTP+JSON (REST) transports.
* https://github.com/wildfly-extras/a2a-jakarta - This integration is based on Jakarta EE, and should work in all runtimes supporting the [Jakarta EE Web Profile](https://jakarta.ee/specifications/webprofile/).
# Extras
See the [`extras`](./extras/README.md) folder for extra functionality not provided by the SDK itself!