MCP-Server mit Spring AI bauen
Spring AI macht MCP für Java-Teams einfach: bestehende Services mit @McpTool annotieren und als KI-Tool bereitstellen. Anleitung mit Beispielen.
Wenn dein Team mit Spring Boot arbeitet und KI-Agenten an eure Services anbinden will, braucht ihr keinen separaten MCP-Server in TypeScript oder Python. Spring AI (ab Version 1.1, aktuell als Snapshot verfügbar) hat MCP als First-Class-Feature integriert. Die MCP-Annotationen kommen aus dem Community-Projekt mcp-annotations, das als transitive Dependency automatisch mitgeliefert wird. Bestehende Services lassen sich damit mit ein paar Annotationen als MCP-Server bereitstellen.
Dieser Artikel bezieht sich auf Spring AI 1.1 (für Spring Boot 3.x). Parallel wird bereits Spring AI 2.0 entwickelt, das auf Spring Boot 4.x und Jakarta EE 11 aufbaut. Die MCP-API und Annotationen bleiben weitgehend gleich, wer jetzt mit 1.1 startet, kann später auf 2.0 migrieren.
Falls du noch nicht weißt, was MCP ist: Lies zuerst unseren Grundlagenartikel zu MCP.
Setup
Spring Initializr (start.spring.io) bietet MCP direkt als Dependency an. Wähle "Model Context Protocol Server" und/oder "Model Context Protocol Client".
Oder manuell in der pom.xml. Du brauchst die Spring AI BOM und den Starter:
<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>
<!-- MCP Server über HTTP (Spring MVC) -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-server-webmvc</artifactId>
</dependency>
</dependencies>
Da Spring AI 1.1 aktuell noch nicht final released ist, brauchst du das Snapshot-Repository:
<repositories>
<repository>
<id>spring-snapshots</id>
<url>https://repo.spring.io/snapshot</url>
<snapshots><enabled>true</enabled></snapshots>
</repository>
</repositories>
Für lokale Integration mit Claude Desktop oder Cursor (über STDIO):
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-server</artifactId>
</dependency>
Für reaktive Anwendungen gibt es spring-ai-starter-mcp-server-webflux.
Einen Service als MCP-Server bereitstellen
Angenommen, du hast einen bestehenden Kunden-Service:
import org.springaicommunity.mcp.annotation.McpTool;
import org.springaicommunity.mcp.annotation.McpToolParam;
@Service
public class CustomerService {
private final CustomerRepository customerRepository;
public CustomerService(CustomerRepository customerRepository) {
this.customerRepository = customerRepository;
}
@McpTool(name = "find-customer", description = "Kunden anhand der ID suchen")
public Customer findById(
@McpToolParam(description = "Kunden-ID") Long id) {
return customerRepository.findById(id)
.orElseThrow(() -> new NotFoundException("Kunde nicht gefunden"));
}
@McpTool(name = "search-customers", description = "Kunden nach Name suchen")
public List<Customer> search(
@McpToolParam(description = "Suchbegriff") String query) {
return customerRepository.findByNameContaining(query);
}
}
Das ist der ganze Code. @McpTool markiert eine Methode als Tool, das KI-Agenten aufrufen können. @McpToolParam dokumentiert die Parameter. Die Annotationen kommen aus dem Package org.springaicommunity.mcp.annotation. Spring AI generiert daraus automatisch das JSON-Schema, das MCP-Clients brauchen.
Resources und Prompts
Neben Tools kann ein MCP-Server auch Daten (Resources) und Prompt-Vorlagen bereitstellen:
import org.springaicommunity.mcp.annotation.McpArg;
import org.springaicommunity.mcp.annotation.McpPrompt;
import org.springaicommunity.mcp.annotation.McpResource;
@Component
public class CustomerMcpExtensions {
@McpResource(uri = "customers://{id}", name = "Kundenprofil")
public String getCustomerProfile(String id) {
Customer c = customerService.findById(Long.parseLong(id));
return "Name: %s, Plan: %s, Seit: %s".formatted(
c.getName(), c.getPlan(), c.getCreatedAt());
}
@McpPrompt(name = "customer-analysis",
description = "Analysiere das Kundenverhalten")
public String customerAnalysisPrompt(
@McpArg(name = "customerId", description = "Kunden-ID") Long customerId) {
return """
Analysiere das Verhalten von Kunde %d.
Nutze find-customer um die Stammdaten zu laden.
Fasse zusammen: Aktivität, offene Tickets, Upsell-Potenzial.
""".formatted(customerId);
}
}
Wichtig: Bei @McpResource mit URI-Templates müssen die Parameter vom Typ String sein, die MCP-Spezifikation übergibt URI-Variablen immer als Strings. Bei @McpPrompt wird statt @McpToolParam die Annotation @McpArg verwendet, die einen expliziten name-Parameter erwartet.
Resources sind Read-Only-Daten, die der Agent bei Bedarf abrufen kann. Prompts sind Vorlagen, die der Agent nutzen kann, um strukturierte Anfragen zu stellen.
Konfiguration
In application.yml:
spring:
ai:
mcp:
server:
type: SYNC
annotation-scanner:
enabled: true
Der annotation-scanner ist standardmäßig aktiviert, kann aber explizit gesetzt werden. Für das neuere Streamable-HTTP-Protokoll (empfohlen für neue Projekte) ergänze:
spring:
ai:
mcp:
server:
protocol: STREAMABLE
type: SYNC
Für STDIO (Claude Desktop, Cursor):
spring:
ai:
mcp:
server:
stdio: true
main:
web-application-type: none
Als MCP-Client: Externe Server nutzen
Spring AI kann auch als MCP-Client agieren und externe MCP-Server anbinden:
spring:
ai:
mcp:
client:
type: SYNC
sse:
connections:
github:
url: http://localhost:3001
stdio:
connections:
filesystem:
command: npx
args:
- -y
- "@modelcontextprotocol/server-filesystem"
- /path/to/dir
Im Code:
@Autowired
private SyncMcpToolCallbackProvider toolCallbackProvider;
public String askWithTools(String question) {
return ChatClient.create(chatModel)
.prompt(question)
.tools(toolCallbackProvider.getToolCallbacks())
.call()
.content();
}
Der ChatClient bekommt alle Tools der konfigurierten MCP-Server automatisch und entscheidet selbst, welche er braucht.
Warum Spring AI statt TypeScript/Python SDK?
Für Java/Kotlin-Teams hat Spring AI klare Vorteile:
- Kein Polyglot-Overhead. Kein separater Node.js- oder Python-Prozess, kein zusätzliches Deployment. Die MCP-Fähigkeiten leben in der gleichen Spring-Boot-Anwendung wie der Rest.
- Spring Security. Authentifizierung und Autorisierung für MCP-Endpoints über die bestehende Security-Konfiguration. Das Community-Projekt mcp-security vereinfacht das weiter.
- Observability. Micrometer-Metriken und Distributed Tracing funktionieren out of the box. Wenn ein Agent ein Tool aufruft, siehst du das in deinen bestehenden Dashboards.
- Type Safety. Compile-Time-Prüfung und automatische JSON-Schema-Generierung aus den Java-Typen.
Der MCP-Standard ist sprachunabhängig: Ein Spring-AI-Server kann von TypeScript-Clients aufgerufen werden und umgekehrt.
Praktisches Beispiel: Bestehende REST-API erweitern
Wenn du schon eine REST-API hast, ist der Aufwand minimal. Du fügst die MCP-Dependency hinzu und annotierst die Service-Methoden, die du für KI-Agenten freigeben willst. Die REST-API bleibt wie sie ist, der MCP-Server läuft parallel.
import org.springaicommunity.mcp.annotation.McpTool;
import org.springaicommunity.mcp.annotation.McpToolParam;
@Service
public class TicketService {
// REST-Controller nutzt diese Methoden weiterhin
// Jetzt können auch KI-Agenten darauf zugreifen
@McpTool(name = "open-tickets",
description = "Offene Tickets eines Projekts auflisten")
public List<Ticket> getOpenTickets(
@McpToolParam(description = "Projekt-Key (z.B. PROJ-1)") String projectKey) {
return ticketRepository.findByProjectAndStatus(projectKey, Status.OPEN);
}
@McpTool(name = "create-ticket",
description = "Neues Ticket erstellen")
public Ticket createTicket(
@McpToolParam(description = "Projekt-Key") String projectKey,
@McpToolParam(description = "Titel des Tickets") String title,
@McpToolParam(description = "Beschreibung") String description) {
return ticketRepository.save(new Ticket(projectKey, title, description));
}
}
Ein Claude-Agent könnte dann sagen: "Zeig mir die offenen Tickets in PROJ-1 und erstelle ein neues Ticket für den Bug, den ich gerade gefunden habe." Und hätte die Tools dafür.
Tipp: Fang mit einem Read-Only-Server an (nur @McpTool-Methoden, die Daten lesen). Wenn das funktioniert, füge Schreiboperationen hinzu. Nutze Spring Security, um zu kontrollieren, wer welche Tools aufrufen darf. Die offiziellen Beispiele sind ein guter Startpunkt.
Quellen
- Spring AI Reference: MCP Overview
- Spring AI MCP Server Boot Starter
- Spring AI MCP Annotations (Server)
- Spring AI MCP Client Boot Starter
- Getting Started with MCP in Spring AI
- Spring AI Community: MCP Annotations - das Community-Projekt, das
@McpTool,@McpResource,@McpPromptbereitstellt - Baeldung: MCP with Spring AI
- Spring AI Examples auf GitHub