Praktische Hinweise: Spring AI + MCP: Stellen Sie Ihre Java-Tools jedem AI-Klienten zur Verfügung (auch
Schritt-für-Schritt-Anleitung zu den Praktischen Hinweisen: Spring AI + MCP – Machen Sie Ihre Java-Tools für jeden AI-Klienten zugänglich (einschließlich Verträgen, Überprüfungen sowie Code-Blöcken für Teams, die dieses Muster einsetzen).
Dieser Leitfaden zeigt Schritt für Schritt den Weg von Rohstoffen bis zu einem funktionsfähigen System für: Spring AI + MCP: Ihre Java-Tools jedem AI-Klienten zugänglich machen (auch Claude Desktop). Der Schwerpunkt liegt auf ausführbaren Schritten, klaren Überprüfungen sowie Code, den Sie ohne Rückschluss auf die Absicht direkt in ein Repository einfügen können.
Ein praktischer Leitfaden zum Model Context Protocol (MCP) mit Spring AI 2.0. Erstellen Sie einen MCP-Server, der Zahlungstools über SSE bereitstellt, sowie einen separaten AI-Klienten, der diese Tools entdeckt und aufruft – ohne dass auf der Client-Seite Tool-Definitionen erforderlich sind.
Für das A-Handbuch zur praktischen Umsetzung sollten vor dem Ändern des Codes die Eingaben, der Verantwortliche für den Schritt sowie die Abbruchkriterien definiert werden. Die Operator sollten in der Lage sein, den Schritt von einem bekannten Checkpoint aus erneut auszuführen, ohne auf versteckte Zustände schließen zu müssen. Die Konfiguration sollte außerhalb des Anwendungscode gespeichert werden. Umgebungsdateien, Geheimdatenspeicher und Feature-Flags sollten an einem Ort zusammengefasst sein, den die Operator überprüfen können, ohne den gesamten Ablauf durchzulesen. Wählen Sie bei dem nächsten Schritt, der ein Codeabschnitt oder einen Toolaufruf ist, strukturierte Ausgaben mit Schema-Validierung statt freier Prosa.
Das Problem
Zur Phase „Das Problem“ sollten die Eingabedaten, der Verantwortliche für den Schritt sowie die Abbruchkriterien definiert werden, bevor der Code geändert wird. Die Operator sollten in der Lage sein, den Schritt von einem bekannten Checkpoint aus erneut auszuführen, ohne auf versteckte Zustände schließen zu müssen. Dokumentieren Sie gemeinsam den erfolgreichen Ablauf sowie den Notfallweg. Wiederholte Versuche, menschliche Überprüfungen und die Handhabung von Fehlern gehören zum Produkt selbst, nicht zu späteren Optimierungen. Authentifizieren Sie sich am Gateway und erteilen Sie erneut Berechtigungen auf der Datenebene. Ein alleiniges Trägertoken stellt keine Trennlinie zwischen verschiedenen Nutzern dar.
Was ist MCP?
Zur Phase „Was ist MCP“ sollten die Eingaben, der Verantwortliche für den Schritt sowie die Abbruchkriterien vor dem Codeändern definiert werden. Die Operator sollten in der Lage sein, den Schritt von einem bekannten Checkpoint aus erneut auszuführen, ohne auf versteckten Zuständen schließen zu müssen. Vorzuziehen sind kleine, testbare Einheiten statt umfangreicher Skripte. Wenn ein Schritt fehlschlägt, sollte der Fehler auf eine einzige Verantwortung verweisen und nicht auf ein verworrenes Pipeline-System. Authentifizieren Sie sich am Gateway und erteilen Sie erneut Berechtigungen auf der Datenebene. Ein alleinigesBearer-Token stellt keine Trennlinie zwischen verschiedenen Nutzern dar.
Was wir entwickeln
Zur Phase „Was wir entwickeln“ sollten die Eingabedaten, der Verantwortliche für den jeweiligen Schritt sowie die Abbruchkriterien vor dem Ändern des Codes definiert werden. Die Operator sollten in der Lage sein, den Schritt von einem bekannten Checkpoint aus erneut auszuführen, ohne auf versteckte Zustände schließen zu müssen. Betrachten Sie diese Phase als Vertrag zwischen den Eingabedaten und den validierten Ausgabedaten. Benennen Sie die Artefakte, definieren Sie Erfolgskontrollen und lehnen Sie stille, unvollständige Abschlüsse ab. Authentifizieren Sie sich am Gateway und erteilen Sie erneut Berechtigungen auf der Datenebene. Ein alleinigesBearer-Token stellt keine Trennlinie zwischen verschiedenen Nutzungseinheiten dar.
Voraussetzungen
Zur Voraussetzungsphase sollten die Eingaben, der Verantwortliche für den Schritt sowie die Abbruchkriterien vor dem Codeändern definiert werden. Die Operator sollten in der Lage sein, den Schritt von einem bekannten Checkpoint aus erneut auszuführen, ohne auf verborgene Zustände schließen zu müssen. Erhalten Sie Zeitenangaben sowie Kosten für Token oder Abfragen zusammen mit den funktionalen Ergebnissen. Eine frühzeitige Sichtbarkeit der Kosten verhindert überraschende Rechnungen, wenn der Weg von einer Demo-Umgebung in gemeinsam genutzte Umgebungen wechselt. Authentifizieren Sie sich am Gateway und erteilen Sie erneut Berechtigungen auf der Datenebene. Ein alleiniges Tragetoken stellt keine Trennlinie zwischen verschiedenen Nutzern dar. Zur Voraussetzungsphase sollten die Eingaben, der Verantwortliche für den Schritt sowie die Abbruchkriterien vor dem Codeändern definiert werden. Die Operator sollten in der Lage sein, den Schritt von einem bekannten Checkpoint aus erneut auszuführen, ohne auf verborgene Zustände schließen zu müssen. Dokumentieren Sie sowohl den erfolgreichen Ablauf als auch den Notfallablauf gemeinsam. Wiederholungsversuche, menschliche Überprüfungen sowie die Handhabung von Fehlern gehören zum Produkt selbst und nicht zu späteren Optimierungen.
Projekteinrichtung
Während der Projekt-Einrichtungsphase sollten Sie zunächst den Vertrag aufschreiben: erforderliche Eingaben, Erfolgsindikator sowie das Vorgehen bei teilweisen Fehlern. Diese Checkliste sorgt dafür, dass spätere Codeänderungen transparent bleiben. Ziehen Sie kleine, testbare Einheiten vor großen Skripten. Wenn ein Schritt fehlschlägt, sollte der Fehler auf eine einzige Verantwortung verweisen und nicht auf ein verworrenes Ablaufschema. Protokollieren Sie für jeden Aufruf den Namen des Tools, den Hash der Argumente, die Latenzzeit sowie das Ergebnis. Ohne diese Aufzeichnungen verschwenden Debugging-Tools wertvolle Stunden.
Parent POM
Während der Bearbeitung der Parent POM-Phase sollten Sie zunächst den Vertrag aufschreiben: erforderliche Eingaben, Erfolgsignal sowie das Vorgehen bei teilweisen Fehlern. Diese Checkliste sorgt dafür, dass spätere Codeänderungen transparent bleiben. Betrachten Sie diese Phase als Vertrag zwischen Eingaben und validierten Ausgaben. Benennen Sie die Artefakte, definieren Sie Erfolgskontrollen und lehnen Sie stille, teilweise abgeschlossene Vorgänge ab. Protokollieren Sie für jeden Aufruf den Namen der Tool, den Hash der Argumente, die Latenz sowie das Ergebnis. Ohne diese Aufzeichnungen verschwenden Debugging-Agenten Stunden mit sinnlosem Herumprobieren.
<groupId>com.anupam</groupId>
<artifactId>spring-ai-mcp</artifactId>
<packaging>pom</packaging>
<properties>
<java.version>21</java.version>
<spring-ai.version>2.0.0</spring-ai.version>
</properties>
<modules>
<module>mcp-server</module>
<module>mcp-client</module>
</modules>
<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>
Teil 1: Aufbau des MCP-Servers
Beim Arbeiten an Teil 1 „Bau der Plattform“ sollten Sie zunächst den Vertrag aufschreiben: erforderliche Eingaben, Erfolgsignal sowie das Vorgehen bei teilweisen Fehlern. Diese Checkliste sorgt dafür, dass spätere Codeänderungen transparent bleiben. Notieren Sie außerdem die Laufzeiten sowie die Kosten für Tokens oder Abfragen neben den funktionalen Ergebnissen. Eine frühzeitige Sichtbarkeit der Kosten verhindert überraschende Rechnungen, wenn der Weg von einer Demo-Umgebung in gemeinsam genutzte Umgebungen wechselt. Protokollieren Sie für jeden Aufruf den Namen der Tool, den Hash der Argumente, die Latenz sowie das Ergebnis. Ohne diese Aufzeichnungen verschwenden Debugging-Agenten wertvolle Stunden mit endlosen Schleifen.
Server-Abhängigkeiten
Während der Phase der Server-Abhängigkeiten sollte man zunächst den Vertrag aufschreiben: erforderliche Eingaben, Erfolgssignal sowie das Vorgehen bei teilweisen Fehlern. Diese Checkliste sorgt dafür, dass spätere Codeänderungen transparent bleiben. Bewahren Sie die Konfiguration außerhalb des Anwendungscode auf. Umgebungsdateien, Geheimdatenspeicher und Feature-Flags sollten an einem Ort zusammengefasst sein, den Betreiber ohne das Durchlesen des gesamten Graphen überprüfen können. Protokollieren Sie für jeden Aufruf den Namen des Tools, den Hash der Argumente, die Latenzzeit sowie das Ergebnis. Ohne diese Aufzeichnungen verschwenden Debugging-Agenten wertvolle Stunden mit endlosen Schleifen.
<dependencies>
<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>
</dependency>
</dependencies>
Server-Konfiguration
Während der Serverkonfiguration sollten Sie zunächst den Vertrag aufschreiben: erforderliche Eingaben, Erfolgsignal sowie das Vorgehen bei teilweisen Fehlern. Diese Checkliste sorgt dafür, dass spätere Codeänderungen transparent bleiben. Dokumentieren Sie sowohl den erfolgreichen Ablauf als auch den Wiederherstellungsprozess gemeinsam. Wiederholte Versuche, menschliche Überprüfungen sowie die Handhabung von Fehlern gehören zum Produkt selbst und nicht zu späteren Optimierungen. Protokollieren Sie für jeden Aufruf den Namen des Tools, den Hash der Argumente, die Latenzzeit sowie das Ergebnis. Ohne diese Aufzeichnungen verschwenden Debugging-Agenten wertvolle Stunden mit endlosen Schleifen.
spring:
ai:
mcp:
server:
name: payment-tools-server
version: 1.0.0
description: "MCP server exposing payment lookup and exchange rate tools"
server:
port: 8081
Tools mit @Tool definieren
Während der Phase „Define Tools with Tool“ sollten Sie zunächst den Vertrag aufschreiben: erforderliche Eingaben, Erfolgsignal sowie das Vorgehen bei teilweisen Fehlern. Diese Checkliste sorgt dafür, dass spätere Codeänderungen transparent bleiben. Ziehen Sie kleine, testbare Einheiten vor großen Skripten. Wenn ein Schritt fehlschlägt, sollte der Fehler auf eine einzige Verantwortung verweisen und nicht auf ein verworrenes Ablaufschema. Protokollieren Sie für jeden Aufruf den Toolnamen, den Hash der Argumente, die Latenzzeit sowie das Ergebnis. Ohne diese Aufzeichnungen verschwenden Debugging-Prozesse wertvolle Stunden.
@Component
public class PaymentMcpTools {
@Tool(description = "Get the current status and details of a payment by its transaction ID")
public PaymentInfo getPaymentStatus(
@ToolParam(description = "Transaction ID, e.g. TXN-9042") String transactionId) {
PaymentInfo info = payments.get(transactionId);
if (info == null) {
throw new RuntimeException("Payment not found: " + transactionId);
}
return info;
}
@Tool(description = "Get the current exchange rate between two currencies. " +
"Supported: USD, EUR, GBP, JPY, INR, CAD, AUD")
public ExchangeRate getExchangeRate(
@ToolParam(description = "Source currency code, e.g. USD") String from,
@ToolParam(description = "Target currency code, e.g. EUR") String to) {
// ... conversion logic
return new ExchangeRate(from, to, rate, LocalDateTime.now());
}
@Tool(description = "Calculate the total amount in a target currency for a given payment")
public String convertPaymentAmount(
@ToolParam(description = "Transaction ID") String transactionId,
@ToolParam(description = "Target currency code") String targetCurrency) {
PaymentInfo payment = getPaymentStatus(transactionId);
ExchangeRate rate = getExchangeRate(payment.currency(), targetCurrency);
BigDecimal converted = payment.amount().multiply(rate.rate());
return String.format("%s %s = %s %s", payment.amount(), payment.currency(),
converted, targetCurrency);
}
}
Server starten
Beim Bearbeiten der Phase „Server starten“ sollten Sie zunächst den Vertrag aufschreiben: erforderliche Eingaben, Erfolgsignal sowie das Vorgehen bei teilweisen Fehlern. Diese Checkliste sorgt dafür, dass spätere Codeänderungen transparent bleiben. Betrachten Sie diese Phase als Vertrag zwischen Eingaben und validierten Ausgaben. Benennen Sie die Erzeugnisse, definieren Sie Erfolgskontrollen und lehnen Sie stille, teilweise abgeschlossene Abläufe ab. Protokollieren Sie für jeden Aufruf den Namen des Tools, den Hash der Argumente, die Latenzzeit sowie das Ergebnis. Ohne diese Aufzeichnungen verschwenden Debugging-Agenten wertvolle Stunden mit endlosen Schleifen.
cd mcp-server
./mvnw spring-boot:run
Teil 2: Aufbau des MCP-Clients
Beim Arbeiten an Teil 2 „Bau der Plattform“ sollten Sie zunächst den Vertrag aufschreiben: erforderliche Eingaben, Erfolgsignal sowie das Vorgehen bei teilweisen Fehlern. Diese Checkliste sorgt dafür, dass spätere Codeänderungen transparent bleiben. Notieren Sie außerdem die Laufzeiten sowie die Kosten für Tokens oder Abfragen neben den funktionalen Ergebnissen. Eine frühzeitige Sichtbarkeit der Kosten verhindert überraschende Rechnungen, wenn der Weg von einer Demo-Umgebung in gemeinsam genutzte Umgebungen wechselt. Protokollieren Sie für jeden Aufruf den Namen der Tool, den Hash der Argumente, die Latenzzeit sowie das Ergebnis. Ohne diese Aufzeichnungen verschwenden Debugging-Agenten wertvolle Stunden mit endlosen Schleifen.
Kundenabhängigkeiten
Während der Phase der Client-Abhängigkeiten sollte man zunächst den Vertrag aufschreiben: erforderliche Eingaben, Erfolgssignal sowie das Vorgehen bei teilweisen Fehlern. Diese Checkliste sorgt dafür, dass spätere Codeänderungen transparent bleiben. Bewahren Sie die Konfiguration außerhalb des Anwendungscode auf. Umgebungsdateien, Geheimdatenspeicher und Feature-Flags sollten an einem Ort zusammengefasst sein, den Betreiber ohne das Durchlesen des gesamten Systems überprüfen können. Protokollieren Sie für jeden Aufruf den Namen des Tools, den Hash der Argumente, die Latenzzeit sowie das Ergebnis. Ohne diese Aufzeichnungen verschwenden Debugging-Agenten wertvolle Stunden mit endlosen Schleifen.
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-openai</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-client</artifactId>
</dependency>
</dependencies>
Kundenkonfiguration
Während der Phase der Client-Konfiguration sollten Sie zunächst den Vertrag aufschreiben: erforderliche Eingaben, Erfolgsignal sowie das Vorgehen bei teilweisen Fehlern. Diese Checkliste sorgt dafür, dass spätere Codeänderungen transparent bleiben. Dokumentieren Sie sowohl den erfolgreichen Ablauf als auch den Notfallweg gemeinsam. Wiederholte Versuche, menschliche Überprüfungen sowie die Handhabung von Fehlern gehören zum Produkt selbst und nicht zu späteren Optimierungen. Protokollieren Sie für jeden Aufruf den Namen des Tools, den Hash der Argumente, die Latenzzeit sowie das Ergebnis. Ohne diese Aufzeichnungen verschwenden Debugging-Agenten wertvolle Stunden mit endlosen Schleifen.
spring:
ai:
openai:
api-key: ${OPENAI_API_KEY}
chat:
options:
model: gpt-4o
temperature: 0.3
mcp:
client:
sse:
connections:
payment-tools:
url: http://localhost:8081
server:
port: 8080
MCP-Tools in ChatClient integrieren
Wenn Sie die Wire MCP Tools in die Umsetzung überführen, notieren Sie zunächst den Vertrag: erforderliche Eingaben, Erfolgsignal sowie das Vorgehen bei teilweisen Fehlern. Diese Checkliste sorgt dafür, dass spätere Codeänderungen transparent bleiben. Ziehen Sie kleine, testbare Einheiten vor großen Skripten vor. Wenn ein Schritt fehlschlägt, sollte der Fehler auf eine einzige Verantwortung verweisen und nicht auf ein verworrenes Ablaufschema. Protokollieren Sie für jeden Aufruf den Toolnamen, den Hash der Argumente, die Latenz sowie das Ergebnis. Ohne diese Aufzeichnungen verschwenden Sie bei der Fehlersuche Stunden.
@Configuration
public class AiConfig {
@Bean
public ChatClient chatClient(ChatModel chatModel, SyncMcpToolCallbackProvider mcpTools) {
return ChatClient.builder(chatModel)
.defaultSystem("""
You are a helpful payments assistant. You have access to tools
provided by an MCP server. Use them to look up payment status,
get exchange rates, and convert payment amounts.
""")
.defaultTools(mcpTools)
.build();
}
}
Der Controller (keine Tool-Kenntnisse erforderlich)
@RestController
@RequestMapping("/api/v1/assistant")
public class AssistantController {
private final ChatClient chatClient;
public AssistantController(ChatClient chatClient) {
this.chatClient = chatClient;
}
@PostMapping("/chat")
public ResponseEntity<ChatResponse> chat(@Valid @RequestBody ChatRequest request) {
String answer = chatClient.prompt()
.user(request.message())
.call()
.content();
return ResponseEntity.ok(ChatResponse.of(answer));
}
}
Testing
1. Starten Sie beide Anwendungen
# Terminal 1 — MCP Server
cd mcp-server
./mvnw spring-boot:run
# Terminal 2 - MCP Client
cd mcp-client
export OPENAI_API_KEY=sk-your-key-here
./mvnw spring-boot:run
2. Abfragen über den Client
curl -X POST http://localhost:8080/api/v1/assistant/chat \
-H "Content-Type: application/json" \
-d '{"message": "What is the status of payment TXN-9042?"}'
{
"answer": "Payment TXN-9042 has been completed. It was $250.00 USD sent from Alice Johnson to Bob Smith on August 20, 2026.",
"timestamp": "2026-08-22T11:00:00"
}
3. Verwenden Sie ein Tool, das andere Tools verknüpft
curl -X POST http://localhost:8080/api/v1/assistant/chat \
-H "Content-Type: application/json" \
-d '{"message": "Convert TXN-9043 amount to EUR"}'
{
"answer": "Payment TXN-9043 is $1,200.50 USD. At the current rate of 0.92, that equals approximately €1,104.46 EUR.",
"timestamp": "2026-08-22T11:00:05"
}
MCP gegen lokale Tools: Wann welches verwenden?
Kombination von lokalen und MCP-Tools
chatClient.prompt()
.user(question)
.tools(localTools, mcpTools) // Both in one call
.call()
.content();
Transportmöglichkeiten
Beispiel für stdio (Verbindung zu einem auf npm basierenden MCP-Server):
spring:
ai:
mcp:
client:
stdio:
connections:
filesystem:
command: npx
args: ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]
Sicherheitsaspekte
// Only allow specific tools from the MCP server
@Bean
McpToolFilter mcpToolFilter() {
return (serverName, toolName) ->
Set.of("getPaymentStatus", "getExchangeRate").contains(toolName);
}
Häufige Probleme
Vollständiges funktionierendes Beispiel
git clone https://github.com/AnupamSinha/spring-boot-examples/tree/main/06-ai-mcp
cd spring-ai-mcp
# Terminal 1 - Start server
cd mcp-server && ../mvnw spring-boot:run
# Terminal 2 - Start client
cd mcp-client && export OPENAI_API_KEY=sk-... && ../mvnw spring-boot:run