Module 2: Environment Setup
Duration: ~30 minutes | Level: Intermediate | Prerequisites: Java 21 installed, Maven or Gradle, an API key from Anthropic or OpenAI
What You'll Have After This Module
- A Spring Boot 4.1.x project with Spring AI and MCP dependencies correctly configured
- A working API key connected via environment variable
- A smoke test confirming your AI provider connection works
- Solid understanding of the dependency structure and why each piece exists
Project Setup: Get the Code
All code in this course lives in the companion repository at projects/mcp-spring-ai-course/. It is a single multi-module Maven build: a parent POM (com.themcpguy:mcp-spring-ai-course:1.0.0-SNAPSHOT, packaging pom) plus four child modules, one per code-bearing module of the course:
first-connection(Modules 2 and 3)chatclient-demo(Module 4)multi-server(Module 5)order-mcp-server(Module 6)
The parent POM centralises everything the children share: it imports the spring-boot-dependencies and spring-ai-bom BOMs, sets Java 21, and pins the build plugins. The exact versions in the reference parent are:
- Java: 21
- Spring Boot: 4.1.0 (via the
spring-boot-dependenciesBOM) - Spring AI: 2.0.0 (via the
spring-ai-bom)
Build everything from the repo root, then run an individual module:
# From the repository root (projects/mcp-spring-ai-course/)
mvn install # builds the parent and all four child modules
# Run a single module (e.g. the first-connection app from this course module)
mvn -pl first-connection spring-boot:run
The reference children are intentionally lean: they inherit versions, plugins, and the BOM imports from the parent, so their own pom.xml files list no versions on the Spring Boot or Spring AI dependencies. The lessons, by contrast, present standalone-equivalent POMs (with a spring-boot-starter-parent, an explicit spring-ai-bom import, and pinned versions) so each module reads as a complete, self-contained project. The two are equivalent in what they pull in, but a child pom.xml copied straight out of the repo will not build on its own: it needs the parent. To run reference code, build from the repo root as shown above; to follow along in your own fresh project, use the standalone POM below.
Understanding the Dependency Stack
Before touching any files, let's understand what we're pulling in and why. This saves you from cargo-culting a pom.xml and being confused when things don't work.
Spring Boot Parent
Spring Boot's parent POM manages hundreds of transitive dependency versions. When you add a Spring Boot dependency, you usually don't specify a version. The parent handles it. This is Spring's "opinionated" approach: tested version combinations, so you don't discover incompatibilities at 2am.
Spring AI BOM
Spring AI follows the same pattern. The Spring AI BOM (Bill of Materials) pins the versions of all Spring AI modules (spring-ai-model, spring-ai-starter-mcp-client, spring-ai-starter-model-anthropic, and so on) to a single tested set.
Without the BOM, you'd need to manually align versions across multiple Spring AI artifacts. With it, you import one BOM entry and everything just works.
The MCP Client Starter
spring-ai-starter-mcp-client pulls in everything needed to connect to MCP servers from a Spring Boot application:
- The MCP client library (manages JSON-RPC connections over stdio or Streamable HTTP)
- Spring Boot autoconfiguration that reads your
application.propertiesand createsMcpClientbeans SyncMcpToolCallbackProvider, the bridge that turns MCP tools into Spring AIToolCallbackobjects
A Model Provider Starter
Spring AI separates the model protocol from the model provider. You add one starter for MCP (the tool protocol) and one starter for your AI provider (Anthropic, OpenAI, etc). They work together through the ChatModel abstraction.
Prerequisites
Java 21. Spring AI 2.0.x (on Spring Boot 4) requires Java 17+, but we recommend 21. It's a well-supported LTS (Java 25, released September 2025, is the current LTS) and Spring Boot 4.1.x is optimised for it. Verify with:
java -version
# Should show: openjdk 21.0.x or similar
Maven 3.9+ (or Gradle 8.x). All examples use Maven.
mvn -version
# Should show: Apache Maven 3.9.x
An API Key. For Anthropic:
- Create an account at console.anthropic.com
- Navigate to Settings, API Keys, Create Key
- Copy it. You won't see it again
For OpenAI:
- Visit platform.openai.com/api-keys
- Create, then Copy
Store it as an environment variable. Do not put API keys in application.properties directly. That file ends up in version control.
# Add to ~/.bashrc, ~/.zshrc, or equivalent
export ANTHROPIC_API_KEY="sk-ant-api03-..."
# Or for OpenAI
export OPENAI_API_KEY="sk-proj-..."
Node.js (optional but useful). Several MCP servers (including the official filesystem reference implementation) are distributed as npm packages. Install Node.js 20+ from nodejs.org if you want to use them for testing.
Create the Project
Use Spring Initializr or create the Maven project manually. The Initializr is quickest for the base, then you'll add the Spring AI starters to pom.xml (Initializr's catalog of Spring AI starters has changed over time, so manual edits keep the dependency set explicit).
Start with this base pom.xml. It is the standalone-equivalent of the repo's first-connection module (it inlines the parent and BOM the reference inherits, so it builds on its own):
<?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
http://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>4.1.0</version>
<relativePath/>
</parent>
<groupId>com.themcpguy</groupId>
<artifactId>first-connection</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<java.version>21</java.version>
<spring-ai.version>2.0.0</spring-ai.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<version>${spring-ai.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- Spring Boot base -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- MCP client: connects to MCP servers, registers their tools -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-client</artifactId>
</dependency>
<!-- AI model provider: choose one -->
<!-- Option A: Anthropic (Claude) -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-anthropic</artifactId>
</dependency>
<!-- Option B: OpenAI (GPT-4o). Uncomment to use instead of Anthropic -->
<!--
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-openai</artifactId>
</dependency>
-->
<!-- Testing -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<!-- Spring AI milestone repository: optional for GA builds; only needed to resolve pre-GA milestones/RCs -->
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
</project>
Why the Spring Milestones Repository?
Spring AI 1.x and 2.0.x GA releases are available on Maven Central. Pre-GA milestones (for example, a future 2.1.0-Mx line) live in the Spring Milestones repository. If you're using only GA releases on Maven Central, this repository is optional, but including it future-proofs your build when you want to evaluate a milestone.
Configure Your Application
Create src/main/resources/application.properties:
# ── AI Provider ─────────────────────────────────────────────────────────────
# Anthropic Claude
spring.ai.anthropic.api-key=${ANTHROPIC_API_KEY}
spring.ai.anthropic.chat.model=claude-sonnet-4-6
# OpenAI GPT-4o (uncomment if using OpenAI)
# spring.ai.openai.api-key=${OPENAI_API_KEY}
# spring.ai.openai.chat.model=gpt-4o
# ── MCP Client ──────────────────────────────────────────────────────────────
# Automatically register MCP tools with ChatClient
spring.ai.mcp.client.toolcallback.enabled=true
# Log MCP connection activity at startup
logging.level.org.springframework.ai.mcp=DEBUG
Notice that the API key uses ${ANTHROPIC_API_KEY}. Spring Boot resolves environment variables using this ${VAR_NAME} syntax in properties files. The actual key never appears in the file.
Older Spring AI examples use spring.ai.anthropic.chat.options.* keys; those still work in 2.0.0 but are deprecated for removal, so this course uses the new flattened keys like spring.ai.anthropic.chat.model.
No MCP server connections are configured yet. We'll add those in Module 3. For now, we're just verifying the AI provider connection.
Write the Smoke Test
Create a minimal application class that calls the LLM once and exits:
package com.themcpguy.springai;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class FirstConnectionApplication {
public static void main(String[] args) {
SpringApplication.run(FirstConnectionApplication.class, args);
}
@Bean
CommandLineRunner smokeTest(ChatClient.Builder builder) {
return args -> {
ChatClient chatClient = builder.build();
String response = chatClient.prompt()
.user("Reply with exactly: 'Spring AI is working.'")
.call()
.content();
System.out.println("Response: " + response);
};
}
}
ChatClient.Builder is auto-configured by the AI provider starter. You inject the builder, call .build(), and you have a ChatClient ready to use.
The CommandLineRunner pattern runs code on startup and then exits, perfect for smoke tests and command-line tools.
Run it:
mvn spring-boot:run
You should see something like:
Response: Spring AI is working.
If you see that, your stack is correctly configured end to end: Spring Boot, then Spring AI, then Anthropic API, then Claude, then response back.
The Auto-Configuration Chain
Let's be explicit about what happened automatically when you ran the application:
-
spring-ai-starter-model-anthropicregistered anAnthropicChatModelbean that points at Anthropic's API using your key. -
Spring AI core registered a
ChatClient.Builderbean backed by thatChatModel. -
Your
CommandLineRunnerinjected the builder, built aChatClient, and called the API. -
spring-ai-starter-mcp-clientis present but did nothing yet. There are no MCP servers configured, so it has nothing to connect to.
The Spring AI autoconfiguration classes are in spring-ai-autoconfigure. You can explore them with mvn dependency:tree to see the full dependency graph.
Troubleshooting Common Issues
401 Unauthorized from the AI provider
Your API key is wrong, expired, or missing. Verify:
echo $ANTHROPIC_API_KEY # Should print your key, not empty
# Test the key directly
curl https://api.anthropic.com/v1/messages \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d '{"model":"claude-haiku-4-5","max_tokens":10,"messages":[{"role":"user","content":"hi"}]}'
Could not resolve artifact spring-ai-starter-mcp-client
With the GA 2.0.0 pin used in this lesson, this artifact comes from Maven Central, so the milestones repository is not the cause. Check, in order: the <spring-ai.version> property matches a released version (2.0.0), the spring-ai-bom import is present in <dependencyManagement>, and the artifact id is spelled exactly spring-ai-starter-mcp-client. Then force a metadata refresh:
mvn dependency:resolve -U # Force update of snapshots/releases
If you are deliberately using a pre-GA milestone or RC version, also verify the Spring Milestones repository entry in the <repositories> block.
No qualifying bean of type 'ChatClient.Builder'
You're missing the AI provider starter (or it's commented out). The provider starter is what registers the ChatModel bean, which is what ChatClient.Builder wraps. You must have at least one provider starter.
Application starts but no output appears
The CommandLineRunner may have thrown an exception that Spring swallowed. Add this to your properties:
logging.level.root=INFO
spring.main.banner-mode=off
And check the full log output for exception stack traces.
Check the Latest Versions
Spring AI releases frequently. Before starting a new project, check the current stable version:
To update, change <spring-ai.version> in your pom.xml and run mvn verify. The BOM ensures all Spring AI artifacts update together.
Next: Module 3: Connecting to Your First MCP Server. Add an MCP server to your configuration and inspect the tools it exposes.