Introduction
The Model Context Protocol (MCP) is an open standard that defines how AI models communicate with external tools, services, and data sources. It replaces ad-hoc integrations with a single, well-defined JSON-RPC 2.0 protocol, making it easy to connect any MCP-compatible AI client to any MCP server.
With Spring AI 2.0, building an MCP server is as simple as annotating a Spring bean method — no manual schema authoring, no boilerplate transport code. This article walks through a complete example: a Spring Boot 4 application that exposes MCP tools and resources, and a companion client that calls them interactively from the command line.
The full source code is available on GitHub.
MCP Services
An MCP server exposes three types of primitives:
| Primitive | Description |
|---|---|
| Tools | Callable functions with structured parameters and return values |
| Resources | Read-only, URI-addressable content (files, records, live data) |
| Prompts | Reusable prompt templates with named parameters |
This article covers tools and resources. The transport used is Streamable HTTP: a single
POST /mcp endpoint that speaks JSON-RPC, making it straightforward to test with curl or
the official MCP Inspector UI.
Project Setup
The project is a multi-module Maven build with two modules:
ai/
├── pom.xml ← parent POM
├── mcp-server/ ← Spring Boot app, port 8080
└── mcp-client/ ← Spring Boot app, interactive REPL
Parent POM (relevant excerpts):
1<parent> 2 <groupId>org.springframework.boot</groupId> 3 <artifactId>spring-boot-starter-parent</artifactId> 4 <version>4.0.6</version> 5</parent> 6 7<properties> 8 <java.version>21</java.version> 9 <spring-ai.version>2.0.0-M5</spring-ai.version> 10</properties> 11 12<dependencyManagement> 13 <dependencies> 14 <dependency> 15 <groupId>org.springframework.ai</groupId> 16 <artifactId>spring-ai-bom</artifactId> 17 <version>${spring-ai.version}</version> 18 <type>pom</type> 19 <scope>import</scope> 20 </dependency> 21 </dependencies> 22</dependencyManagement>
Building the MCP Server
The server module pulls in a single starter:
1<dependency> 2 <groupId>org.springframework.ai</groupId> 3 <artifactId>spring-ai-starter-mcp-server-webmvc</artifactId> 4</dependency>
Configuring the Transport
1# mcp-server/src/main/resources/application.yml 2spring: 3 ai: 4 mcp: 5 server: 6 name: ai-mcp-server 7 version: 1.0.0-SNAPSHOT 8 type: SYNC 9 protocol: STREAMABLE 10server: 11 port: 8080
protocol: STREAMABLE selects the Streamable HTTP transport. Spring AI wires up the
POST /mcp endpoint automatically — no controller code needed.
Exposing Tools with @McpTool
Tools are plain Spring beans. Annotate a method with @McpTool and Spring AI generates
the JSON schema for the parameters automatically:
1@Component
2public class PolicyNumberTools {
3
4 private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
5
6 @McpTool(description = "Creates a new policy number")
7 public String createPolicyNumber(
8 @McpToolParam(description = "Id of the LOB (line of business)", required = true)
9 String lobId) {
10 String timestamp = LocalDateTime.now().format(FORMATTER);
11 String randomPart = RandomStringUtils.randomAlphanumeric(5);
12 return (lobId + timestamp + randomPart).toUpperCase();
13 }
14
15}
At startup, Spring AI logs Registered tools: 1 — that is all that is needed.
Exposing Resources with @McpResource
Resources are identified by a URI and return their content as a string. The annotation
works the same way as @McpTool:
1@Component
2public class DemoResource {
3
4 @McpResource(
5 uri = "file:///demo.txt",
6 name = "demo-text",
7 description = "Demo text resource loaded from the classpath"
8 )
9 public String demoText() {
10 try {
11 return new ClassPathResource("demo.txt")
12 .getContentAsString(StandardCharsets.UTF_8);
13 } catch (IOException e) {
14 throw new RuntimeException("Failed to read demo.txt", e);
15 }
16 }
17}
The uri attribute is the protocol-level identifier returned to clients in
resources/list. Its scheme (file:///, db://, etc.) is free to choose — it carries
no technical meaning for the file access; ClassPathResource handles the actual reading.
Testing with MCP Inspector
The official MCP Inspector is an easy way to explore our MCP server without writing any client code:
1npx @modelcontextprotocol/inspector http://localhost:8080/mcp
Select Streamable HTTP as the transport type. The UI shows all registered tools and resources and lets you call them directly from the browser.
Building your own MCP Client
Spring AI also supports writing your own MCP clients. The client module depends on:
1<dependency> 2 <groupId>org.springframework.ai</groupId> 3 <artifactId>spring-ai-starter-mcp-client</artifactId> 4</dependency>
Client Configuration
1# mcp-client/src/main/resources/application.yml 2spring: 3 main: 4 web-application-type: none 5 ai: 6 mcp: 7 client: 8 enabled: true 9 type: SYNC 10 request-timeout: 30s 11 streamable-http: 12 connections: 13 demo: 14 url: http://localhost:8080 15 endpoint: /mcp
Calling the Server
Spring AI auto-configures a List<McpSyncClient> bean. Inject it and use the first
(and only) client:
1@Service
2public class McpClientService {
3
4 private final McpSyncClient mcpClient;
5
6 public McpClientService(List<McpSyncClient> mcpClients) {
7 this.mcpClient = mcpClients.getFirst();
8 }
9
10 public List<McpSchema.Tool> listTools() {
11 return mcpClient.listTools().tools();
12 }
13
14 public List<McpSchema.Resource> listResources() {
15 return mcpClient.listResources().resources();
16 }
17
18 public String callTool(String toolName, Map<String, Object> arguments) {
19 McpSchema.CallToolResult result = mcpClient.callTool(
20 new McpSchema.CallToolRequest(toolName, arguments));
21 return result.content().stream()
22 .filter(c -> c instanceof McpSchema.TextContent)
23 .map(c -> ((McpSchema.TextContent) c).text())
24 .findFirst()
25 .orElse("");
26 }
27}
Interactive REPL
A CommandLineRunner wraps a simple Scanner loop, making the client usable as a
command-line tool without any additional framework:
mcp-client> list-tools
createPolicyNumber Creates a new policy number
mcp-client> create-policy-number HR
HR20260511103235X0WJT
mcp-client> list-resources
file:///demo.txt Demo text resource loaded from the classpath
Agent Smith - it's your turn
In times where more and more agents appear at your IT landscape, MCP will be the protocol to integrate them with your existing applications. If a significant part of your applications use the Spring (Boot) ecosystem, Spring AI will be the tool of your choice.
From an architectural viewpoint there are at last two major patterns how do introduce MCP readiness. You can either create a thin layer into your existing business services to expose additional MCP endpoints ...
... or you add a separate adapter/gateway application in between:
Further Reading
If you are interested in MCP in general, maybe these blog post are worth a look:
More articles in this subject area
Discover exciting further topics and let the codecentric world inspire you.
Blog author
Tobias Trelle
Software Architect
Do you still have questions? Just send me a message.
Do you still have questions? Just send me a message.