Build an MCP Server with Spring AI
This article walks through building a small MCP server with Spring AI: exposing a tool, a resource, and a prompt, then testing the server with MCP Inspector. It uses Spring AI 2.0's @McpTool/@McpResource/@McpPrompt annotations, which replace the manual ToolCallbackProvider wiring from 1.x.
Add the starter
Spring AI ships two MCP server starters, one per transport. Pick the one matching how clients will reach the server.
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-server-webmvc</artifactId>
</dependency>
Adding either starter is enough. Auto-configuration handles annotation scanning, JSON schema generation, transport wiring, and the server lifecycle. No manual bean registration is needed beyond declaring the tool class as a Spring bean.
Define tools, a resource, and a prompt
A single @Component class can expose all three. Below, CalculatorTools has an add tool, a resource that returns past calculation results by ID, and a prompt that primes the model for math questions.
package com.example.mcp.tools;
import org.springframework.ai.mcp.annotation.McpTool;
import org.springframework.ai.mcp.annotation.McpToolParam;
import org.springframework.ai.mcp.annotation.McpResource;
import org.springframework.ai.mcp.annotation.McpPrompt;
import org.springframework.stereotype.Component;
@Component
public class CalculatorTools {
@McpTool(name = "add", description = "Add two numbers together")
public int add(
@McpToolParam(description = "First number", required = true) int a,
@McpToolParam(description = "Second number", required = true) int b) {
return a + b;
}
@McpResource(uri = "calculator://history/{id}", name = "Calculator History")
public String getHistory(String id) {
return "History for calculation " + id;
}
@McpPrompt(name = "math-helper", description = "Get help with math problems")
public String getMathPrompt() {
return "You are a helpful math assistant. Help the user solve math problems.";
}
}
@McpTool methods work the same way as the @Tool-annotated methods described in Tools, except they're registered with the MCP server rather than handed to a ChatClient directly. If a checked exception is thrown from a @McpTool method, it surfaces as an UndeclaredThrowableException rather than being converted to an error result, so wrap anything you want reported back to the model in a RuntimeException.
Configure the transport
For a server launched by its client over STDIO (a desktop MCP client, for example), no extra configuration is required beyond having spring-ai-starter-mcp-server on the classpath and spring.ai.mcp.server.stdio=true set.
For a server running as its own long-lived process:
spring:
ai:
mcp:
server:
name: calculator-mcp-server
version: 1.0.0
protocol: STREAMABLE
protocol: STREAMABLE selects Streamable HTTP, the current standard transport (the older SSE value still works but is deprecated). With the WebMVC starter on the classpath, the server listens for POST /mcp on the application's normal HTTP port.
Test with MCP Inspector
MCP Inspector is the quickest way to poke at a server without wiring up a full client. Start the application, then run:
npx @modelcontextprotocol/inspector
Point it at http://localhost:8080/mcp with the Streamable HTTP transport (or at the launch command for a STDIO server), connect, and the add tool, the calculator://history/{id} resource, and the math-helper prompt should all show up in their respective tabs. Calling add with a=2, b=3 should return 5.
Secure the endpoint before deploying it
The HTTP-based transports expose an unauthenticated JSON-RPC endpoint by default. Anyone who can reach /mcp can list and call every tool on the server. Localhost testing is fine as-is, but before exposing a server beyond your own machine, put a security boundary in front of it: Spring Security with a filter on the MCP endpoint, or a network-level control like an API gateway or the MCP gateway pattern described elsewhere in this section, which can also centralize which tools are visible to which clients.
Where to go from here
- MCP Proxy covers converting between STDIO and HTTP transports, useful if a client and this server don't speak the same one.
- MCP Gateway covers aggregating this server with others behind a single endpoint, and restricting which tools different clients can see.