Migrating from Spring AI 1.x to 2.0
Spring AI 2.0 went GA in June 2026. It's a much bigger jump than a typical minor version bump: the internal tool-calling loop is gone, several provider modules were rewritten on top of vendor SDKs, and the baseline platform itself changed. Here are the changes that are most likely to break an existing 1.x application, and how to deal with them.
Spring Boot 4.0 is required
Spring AI 2.0 is built on the Spring Boot 4.0 / Spring Framework 7.0 dependency model, and it will not load in a Spring Boot 3.x context. Check this first: upgrade to Spring Boot 4.0, or stay on Spring AI 1.x, which still gets patch releases. If you're stuck on Spring 5 or Spring Boot 2 for other reasons, the workarounds in Spring 5 and Spring AI still apply to 1.x, but 2.0 is out of reach until the rest of the stack moves too.
The automatic tool-execution loop is removed from ChatModel
In 1.x, calling chatModel.call(prompt) would silently execute any tool calls returned by the model and loop until a final answer came back. In 2.0, that loop is gone from ChatModel. If your code called ChatModel directly with tools attached, it now returns after the first tool-call response instead of resolving it.
// 1.x: tool calls resolved automatically
ChatResponse response = chatModel.call(prompt);
// 2.0: use ChatClient, tool calling is handled by ToolCallingAdvisor
ChatClient.create(chatModel)
.prompt(question)
.tools(new MyTools())
.call()
.content();
If you need to stay on ChatModel directly, drive the loop yourself with ToolCallingManager. Most applications using ChatClient (which is what the quick start walks through) are unaffected, since ToolCallingAdvisor is now auto-registered.
OpenAiApi and friends are gone
This is the biggest change under the hood. Spring AI 2.0 deleted its hand-rolled provider facades (OpenAiApi, AnthropicApi, OpenAiModerationApi) and now delegates directly to the vendor SDKs (openai-java, anthropic-java). Every chat model factory got rewritten. Code that only goes through ChatClient, ChatModel, and ChatOptions is mostly insulated from this. Code built directly around the low-level API classes, like the Spring 5 workaround for RestClient, no longer applies to 2.0 at all.
For Anthropic specifically, the default maxTokens changed from 500 to 4096, and construction moved to a builder:
// 1.x
AnthropicApi anthropicApi = new AnthropicApi(apiKey);
AnthropicChatModel chatModel = new AnthropicChatModel(anthropicApi, options);
// 2.0
AnthropicChatModel chatModel = AnthropicChatModel.builder()
.apiKey(apiKey)
.defaultOptions(options)
.build();
Jackson 2 → Jackson 3
Spring AI now uses Jackson 3 (tools.jackson.*) instead of Jackson 2 (com.fasterxml.jackson.*). If you extended JsonParser/ModelOptionsUtils for custom (de)serialization, switch to the new JsonHelper:
// 1.x
Map<String, Object> map = ModelOptionsUtils.jsonToMap(jsonString);
// 2.0
JsonHelper jsonHelper = new JsonHelper();
Map<String, Object> map = jsonHelper.fromJsonToMap(jsonString);
MCP package and dependency moves
If you're building MCP servers or clients with Spring AI, two things moved:
- MCP annotations (
@McpTooland friends) moved fromorg.springaicommunity.mcp.*toorg.springframework.ai.mcp.annotation.*. - The
mcp-spring-webflux/mcp-spring-webmvctransport modules are no longer published by the MCP Java SDK. They now ship as part of Spring AI itself, under theorg.springframework.aigroupId.
<!-- 1.x -->
<dependency>
<groupId>io.modelcontextprotocol.sdk</groupId>
<artifactId>mcp-spring-webflux</artifactId>
</dependency>
<!-- 2.0 -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>mcp-spring-webflux</artifactId>
</dependency>
MCP servers also now validate tool arguments against the declared JSON schema before invoking the handler, and exception handling became type-based: a checked exception thrown from an @McpTool method now bubbles up as UndeclaredThrowableException instead of being silently converted, so wrap it in a RuntimeException if you want it reported back to the model.
Configuration property flattening
The .options segment was dropped from model configuration properties:
# 1.x
spring.ai.openai.embedding.options.model=text-embedding-3-small
# 2.0
spring.ai.openai.embedding.model=text-embedding-3-small
An automated recipe exists
Spring AI ships OpenRewrite recipes that handle most of the mechanical parts: imports, renamed methods, dependency coordinates.
mvn org.openrewrite.maven:rewrite-maven-plugin:6.32.0:run \
-Drewrite.configLocation=https://raw.githubusercontent.com/spring-projects/spring-ai/refs/heads/main/src/rewrite/migrate-to-2-0-0-M3.yaml \
-Drewrite.activeRecipes=org.springframework.ai.migration.M3*
It doesn't catch everything: anything built directly on the removed provider API classes still needs a manual look. But it's a good first pass before you start reading diffs by hand.
Bottom line
If an application only talks to Spring AI through ChatClient, standard ChatOptions builders, and Spring Boot auto-configuration, the upgrade is mostly a version bump plus the Spring Boot 4.0 migration. The pain shows up if you reached into the low-level provider APIs, rolled your own tool-execution loop, or built MCP servers against the SDK's transport modules directly. Check the official upgrade notes for the full list before you start.