Build AI agents with Spring AI 2.0 - basic agent, memory, tools/MCP, agentic workflows, guardrails, and observability
86
85%
Does it follow best practices?
Impact
90%
2.43xAverage score across 3 eval scenarios
Passed
No known issues
Your team's internal chatbot platform was built on Spring AI 1.1.x and has been running in production for several months. The platform includes an MCP server component that exposes customer data tools, an MCP client customizer for tuning request timeouts, and a custom Jackson serializer used to format responses. The tech lead has decided to upgrade to Spring AI 2.0 to take advantage of new capabilities and stay on a supported release track.
The upgrade involves changes to the build descriptor, application configuration, and Java source files. Several APIs and package names changed between 1.1.x and 2.0 and the codebase needs to be brought in line with the new versions. The team has asked you to produce the updated versions of all project files so they can be reviewed and merged.
Produce updated versions of all four input files with the changes needed to work correctly on Spring AI 2.0:
output/pom.xml — updated Maven build descriptoroutput/application.properties — updated application configurationoutput/CustomerDataServer.java — updated MCP server componentoutput/ChatResponseSerializer.java — updated Jackson serializerFor each file, apply all necessary version, package, and API changes. Do not leave any 1.1.x-specific constructs in the output.
The following files are provided as inputs. Extract them before beginning.
=============== FILE: inputs/pom.xml ===============
<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.3.5</version> </parent> <groupId>com.example</groupId> <artifactId>chatbot-platform</artifactId> <version>0.1.0-SNAPSHOT</version>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<version>1.1.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-openai</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-vertex-ai</artifactId>
</dependency>
<dependency>
<groupId>io.modelcontextprotocol.sdk</groupId>
<artifactId>mcp-spring-webmvc</artifactId>
<version>0.9.0</version>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-server-webmvc</artifactId>
</dependency>
</dependencies>=============== FILE: inputs/application.properties ===============
spring.ai.openai.api-key=${OPENAI_API_KEY} spring.ai.openai.chat.options.model=gpt-4o-mini
spring.ai.mcp.server.type=SYNC spring.ai.mcp.server.protocol=SSE
management.endpoints.web.exposure.include=health,metrics
=============== FILE: inputs/CustomerDataServer.java =============== package com.example.chatbot.mcp;
import org.springframework.ai.mcp.spring.annotations.McpTool; import org.springframework.ai.mcp.spring.annotations.McpToolParam; import org.springframework.stereotype.Component; import io.modelcontextprotocol.sdk.McpSyncClientCustomizer; import io.modelcontextprotocol.sdk.McpClient;
import java.time.Duration;
@Component public class CustomerDataServer {
@McpTool(name = "getCustomer", description = "Retrieve customer record by ID")
public String getCustomer(
@McpToolParam(description = "Customer identifier", required = true) String customerId) {
return "{\"id\": \"" + customerId + "\", \"name\": \"Alice\"}";
}
@McpTool(name = "listOrders", description = "List orders for a customer")
public String listOrders(
@McpToolParam(description = "Customer identifier", required = true) String customerId,
@McpToolParam(description = "Maximum number of orders to return", required = false) Integer limit) {
return "[]";
}
@Component
static class McpTimeoutCustomizer implements McpSyncClientCustomizer {
@Override
public void customize(String serverName, McpClient.SyncSpec spec) {
spec.requestTimeout(Duration.ofSeconds(30));
}
}}
=============== FILE: inputs/ChatResponseSerializer.java =============== package com.example.chatbot.serialization;
import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.SerializerProvider;
import java.io.IOException;
public class ChatResponseSerializer extends JsonSerializer<String> {
@Override
public void serialize(String value, JsonGenerator gen, SerializerProvider serializers)
throws IOException {
gen.writeStartObject();
gen.writeStringField("response", value);
gen.writeStringField("version", "1.0");
gen.writeEndObject();
}}