Sitemap

Spring AI Recipe: Enabling Agent-to-Agent Communication with A2A

4 min readApr 20, 2026

--

Press enter or click to view image in full size

As pointed out in previous recipes, an agent is ultimately just an LLM with tools, running in a loop to achieve some goal. But when the goal is complex, a single agent doesn’t need to shoulder the load itself. Instead, it can delegate work to specialized sub-agents, working together as a team to get the job done.

But for that to work, an agent needs a way to understand what other agents are capable of — and decide whether they’re useful for achieving its goal. That’s where Agent-to-Agent (A2A) comes in.

NOTE: This recipe has been updated since it’s original publication to reflect changes in Spring AI 2.0.0.

Dependencies

Start with a basic Spring AI application and add the following dependencies:

implementation 'org.springframework.ai:spring-ai-starter-model-openai'
implementation 'org.springframework.boot:spring-boot-starter-webmvc'
implementation 'org.springaicommunity:spring-ai-a2a-server-autoconfigure:0.3.0'

Because A2A communication happens over HTTP, Spring MVC is required.

Configuring the ChatClient

Define a ChatClient bean:

@Configuration
public class ChatClientConfig {
@Bean
ChatClient chatClient(ChatClient.Builder chatClientBuilder) {
return chatClientBuilder.build();
}
}

This provides access to the LLM that will power your agent.

This recipe’s agent will provide weather information. Therefore, you’ll also need to add the WeatherTools (from a previous recipe):

@Service
public class WeatherTools {

@Tool(name = "get-weather-for-zipcode",
description = "Gets the current weather for a given zipcode")
public Weather getWeatherForZipcode(
@ToolParam(description = "The zipcode to get weather for") String zipcode) {
return new Weather(zipcode, "Raining cats and dogs", "77F");
}

}

And the Weather record it returns:

public record Weather(
String zipcode,
String conditions,
String temperature) {
}

And you’ll need to configure ChatClient with WeatherTools :

@Bean
ChatClientBuilderCustomizer addWeatherTools(WeatherTools weatherTools) {
return builder -> builder.defaultTools(weatherTools);
}

Exposing the Agent with AgentExecutor

To make the agent accessible via A2A, define an AgentExecutor:

@Bean
public AgentExecutor agentExecutor(ChatClient chatClient) {
return new DefaultAgentExecutor(chatClient, (chat, ctx) -> {
String userMessage = DefaultAgentExecutor
.extractTextFromMessage(ctx.getMessage());
return chat.prompt().user(userMessage).call().content();
});
}

This bridges incoming A2A requests to your ChatClient.

Defining the AgentCard

An A2A agent describes itself using an AgentCard, which is exposed as a JSON document.

@Bean
public AgentCard agentCard(
@Value("${server.host:localhost}") String host,
@Value("${server.port:8080}") int port) {
return new AgentCard.Builder()
.name("My Weather Agent")
.description("Provides weather information for a location")
.url("http://" + host + ":" + port + "/a2a/")
.version("1.2.3")
.capabilities(new AgentCapabilities.Builder().streaming(false).build())
.defaultInputModes(List.of("text"))
.defaultOutputModes(List.of("text"))
.skills(List.of(new AgentSkill.Builder()
.id("my_agent").name("My Weather Agent")
.description("Provides weather information for a location")
.tags(List.of("weather")).build()))
.protocolVersion("0.3.0")
.build();
}

The description is critical. A client agent will use this information to determine whether your agent is relevant to its goal. If the agent description is too vague, the client may not choose to use it even if it would be helpful.

Configuring the Endpoint

By common convention, A2A endpoints are often rooted at /a2a, but Spring MVC defaults to be rooted at /. To align the A2A endpoints exposed with convention, set the server.servlet.context-path configuration property:

server.servlet.context-path=/a2a

This exposes the agent card at: http://localhost:8080/a2a/.well-known/agent-card.json

Testing with the A2A Inspector

In a production system, your agent would be called by another agent. For development and testing, you can use the A2A Inspector.

Follow the setup instructions here:
https://a2aprotocol.ai/docs/guide/a2a-inspector

Once running…

  1. Open the inspector in your browser (typically http://localhost:5001)
  2. Enter: http://localhost:8080/a2a/.well-known/agent-card.json
  3. Click Connect

You should see the agent card details.

Press enter or click to view image in full size
Viewing an agent card in the A2A Inspector

Try It Out

Scroll to the chat section and ask:

What is the weather in Jal, New Mexico?

You should receive a response from your agent.

You can also inspect the raw request/response messages using the “Show” button in the inspector.

Press enter or click to view image in full size
Testing the agent using the A2A Inspector’s chat facility

What You’ve Built

At this point, you have:

  • An LLM-powered agent
  • Exposed via HTTP
  • Described with a machine-readable contract (AgentCard)
  • Ready to be consumed by other agents

This is the foundation for building systems composed of multiple specialized agents working together.

What’s Next

In a follow-up recipe, we’ll build a client agent that discovers and invokes this A2A agent.

You can find the source code for this recipe and other Spring AI recipes at https://github.com/habuma/spring-ai-recipes

--

--

Craig Walls
Craig Walls

Written by Craig Walls

Author Spring AI in Action, Spring in Action, and Build Talking Apps for Alexa