Spring AI MCP-Server: Spring-Dokumentation für LLMs bereitstellen
Wer Claude, Codex und Co. bei der Entwicklung von Spring-Anwendungen einsetzt, musste vielleicht auch schon feststellen, dass gerade neue Features des Frameworks nicht optimal verwendet werden.
Aufgrund fehlender oder veralteter Trainingsdaten erzeugen die Sprachmodelle zwar korrekten, aber nicht optimalen Code.
Sie definieren Beans, obwohl diese mittlerweile aus einer Autoconfiguration kommen, nutzen veraltete Klassen (z. B. JdbcTemplate statt JdbcClient) oder entpacken munter JARs, um den aktuellen Quellcode von Spring zu lesen.
In diesem Beitrag zeige ich, wie man mit Spring AI einen Model-Context-Protocol-Server (MCP-Server) für LLMs bereitstellt, der hier Abhilfe schafft. Der Server gibt Agents Zugriff auf die Spring-Dokumentation, die für das aktuelle Projekt relevant ist.
Spring AI ist ein offizielles Spring-Projekt, das generative KI mit dem Spring-Ökosystem verbindet. Es unterstützt zahlreiche KI-Modellanbieter und Modelltypen: neben Chat-Modellen (LLMs) auch Text-to-Image, Text-to-Speech und Audio-Transkription. Mit Tools, Memory und RAG-Funktionen deckt Spring AI auch Enterprise-Use-Cases ab.
Mit Spring AI lassen sich aber auch MCP-Server entwickeln. Das MCP stellt externe Tools auf standardisierte Art für LLMs bereit.
Wie gewohnt stellt Spring AI dafür Starter bereit. Auf Transportebene kann das MCP auf mehreren Protokollen aufsetzen. Für unseren Anwendungsfall passt ein zustandsloses Setup auf der Basis von Spring WebMVC. Entsprechend wählen wir folgenden Starter:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-server-webmvc</artifactId>
<version>2.0.0</version>
</dependency>
Zusätzlich setzen wir folgende Property: spring.ai.mcp.server.protocol=STATELESS.
Unser Beispiel-Server soll LLMs die Spring-Dokumentation durchsuchen lassen. Dafür ist keine Session notwendig. Auch muss unser MCP-Server selbst kein LLM verwenden oder auf Daten des Clients zugreifen. Somit reicht ein einfacher, zustandsloser Request-Response-Flow.
spring:
ai:
mcp:
server:
protocol: STATELESS
name: spring-doc-search-mcp
instructions: Version-pinned reference documentation for the Spring portfolio.
Die Instructions werden in der Regel an das LLM weitergegeben, damit es entscheiden kann, wann es den Server nutzt.
Beispiel: MCP-Server für Doku-Suche
Die Funktionen, die ein MCP-Server bereitstellt, heißen Tools. Ein Tool wird per Annotation definiert. Die Beschreibungen müssen einem LLM genug Kontext geben, um die Tools zu bedienen.
@Component
class SearchTool {
private final DocService docService;
SearchTool(DocService docService) {
this.docService = docService;
}
@McpTool(
name = "search_spring_docs",
description = "Durchsucht die Spring-Referenzdokumentation nach einem Stichwort",
annotations = @McpTool.McpAnnotations(
title = "Search Spring reference docs" /* Weitere Argumente ausgelassen... */)
)
SearchResponse search(
@McpToolParam(description = "Keyword query for searching the official Spring documentation")
String query
) {
return docService.search(query);
}
}
Spring AI generiert die API, sodass der MCP-Client (z. B. Claude Code) die Tools automatisch erkennt und gezielt an ein LLM (z. B. Claude Opus 5) vermittelt. Das LLM kann den Client dann bitten, ein Tool aufzurufen, wenn es für die aktuelle Aufgabe relevant erscheint.
Mehr ist nicht nötig. Starten wir jetzt unsere Spring-Anwendung, können wir sie als MCP-Server anbinden.
Was genau unser Server über sich preisgibt, lässt sich mit einem JSON-RPC-Request auf /mcp prüfen.
Dank des zustandslosen Protokolls genügt dafür ein einzelner POST ohne vorherigen Handshake:
curl -X POST http://localhost:8080/mcp \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
Das Schema ist standardisiert und wird von jedem MCP-Client verstanden.
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"tools": [
{
"name": "search_spring_docs",
"title": "Search Spring reference docs",
"description": "Durchsucht die Spring-Referenzdokumentation nach einem Stichwort",
"inputSchema": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "Keyword query for searching the official Spring documentation"
}
},
"required": ["query"]
}
// annotations (readOnlyHint, ...) und weitere Felder ausgelassen
}
// ... weitere Tools
]
}
}
Für meinen Anwendungsfall möchte ich den Server in Claude Code einbinden. Dazu genügt folgender Befehl:
claude mcp add --transport http spring-doc-mcp-local http://localhost:8080/mcp
Anschließend wird der MCP-Server als spring-doc-mcp-local in Claude Code aufgeführt.
/mcp)Für andere Clients gilt ein anderer Befehl.
Alternativ lässt sich eine generische MCP-Konfiguration (z. B. .mcp.json) verwenden:
{
"mcpServers": {
"spring-ai": {
"type": "http",
"url": "http://localhost:8080/mcp"
}
}
}
Prompt Engineering
Ob und wann ein LLM den MCP-Server anfragt, hängt stark von der Formulierung der Instructions und Tool-Beschreibungen ab. Starken Modellen genügt eine knappe, präzise Beschreibung. Schwache Modelle interpretieren sehr wörtlich und brauchen mehr Hilfestellung, etwa eine klare Anweisung wie "Nutze dafür den MCP-Server" im Prompt. Es lohnt sich daher zu testen, ob die Tools auch ohne explizite Aufforderung genutzt werden.
Context Pollution und Progressive Disclosure
Beim Arbeiten mit LLMs sollte man deren Kontext im Blick behalten. Untersuchungen zeigen, dass die Antwortqualität mit zunehmend gefülltem Kontextfenster merklich sinkt, lange bevor es voll ist. Tools von MCP-Servern belegen einen Teil dieses Kontexts. Das ist notwendig, damit das LLM überhaupt "weiß", welche Tools es gibt.
Am Beispiel von Claude Code sieht man, dass MCP-Tools jedoch lazy geladen werden.
Das LLM kennt zunächst nur die Server-Instructions (bei uns aus der application.yml) und die Namen der Tools.
Erst wenn das LLM ein Tool für hilfreich hält, wird dessen Beschreibung geladen. Dieses Muster nennt man Progressive Disclosure (schrittweise Offenlegung). Die Umsetzung unterscheidet sich jedoch je nach Client.
Beim Einsatz von MCP-Servern sollte man daher prüfen, wie viel Kontext wann an das LLM geht, um Context Pollution zu vermeiden.
Durchsuchen der Spring-Dokumentation
Ein Tool mit Spring AI anzubieten ist schnell gemacht.
Bisher haben wir uns jedoch nur um den MCP-Server selbst gekümmert.
Die konkrete Implementierung des DocService ist noch offen.
Dahinter steckt "normaler" Java-Code, der die Spring-Dokumentation lädt, indexiert, durchsucht, rankt und aufbereitet.
Intern hat sich das Tool bereits mehrfach bewährt, weshalb wir es hier veröffentlicht haben: sprig-mcp.de Sprig ist dabei kein Typo, sondern steht, passend zu Spring, für einen Zweig.
Der Sprig MCP-Server bietet zwei Tools: eine Suche, die eine Vorschau liefert, und ein Fetch, mit dem das LLM selbstständig vollständige Abschnitte zu relevanten Treffern nachschlagen kann. Beide Tools lassen sich hier live ausprobieren: sprig-mcp.de/app. Weitere Tools für Arbeit im Spring-Ökosystem, wie das Nachschlagen von Methodensignaturen und JavaDoc aus dem Framework sind für die Zukunft geplant.
Bei der Integration von KI-Funktionen in eigene Anwendungen unterstützt unsere KI-Beratung. Zu Spring AI und Spring Boot bieten wir außerdem passende Schulungen an: