領先一步
VMware 提供培訓和認證,助您加速進步。
瞭解更多
模型上下文協議 (MCP) 規範了AI應用程式如何與外部工具和資源互動。Spring作為主要貢獻者之一,很早就加入了MCP生態系統,幫助開發和維護了官方MCP Java SDK,該SDK是基於Java的MCP實現的基礎。在此貢獻的基礎上,Spring AI透過專用的Boot Starters和MCP Java Annotations全面支援MCP,使得構建能夠無縫連線到外部系統的複雜AI驅動應用程式比以往任何時候都更加容易。
本部落格介紹了核心MCP元件,並演示瞭如何使用Spring AI構建MCP伺服器和客戶端,展示了基本和高階功能。完整的原始碼可在以下網址獲取:MCP天氣示例。
注意:此內容僅適用於Spring AI
1.1.0-SNAPSHOT或 SpringAI 1.1.0-M1+版本。
模型上下文協議 (MCP) 是一種標準化協議,使AI模型能夠以結構化的方式與外部工具和資源互動。可以將其視為AI模型與現實世界之間的橋樑——允許它們透過一致的介面訪問資料庫、API、檔案系統和其他外部服務。
模型上下文協議遵循客戶端-伺服器架構,確保了關注點的明確分離。MCP伺服器從第三方服務中暴露特定的功能(工具、資源、提示)。MCP客戶端由宿主應用程式例項化,用於與特定的MCP伺服器通訊。每個客戶端處理與一個伺服器的一次直接通訊。
宿主是使用者互動的AI應用程式,而客戶端是實現伺服器連線的協議級元件。
MCP協議確保客戶端和伺服器之間完全、語言無關的互操作性。您可以擁有用Java、Python或TypeScript編寫的客戶端,與用任何語言編寫的伺服器進行通訊,反之亦然。
這種架構在客戶端和伺服器端開發之間建立了明確的界限和責任,自然地形成了兩個不同的開發者社群。
AI應用程式/宿主開發者
處理協調多個MCP伺服器(透過MCP客戶端連線)並與AI模型整合的複雜性。AI開發者構建AI應用程式,這些應用程式
MCP伺服器(提供者)開發者
專注於將第三方服務中的特定功能(工具、資源、提示)作為MCP伺服器暴露。伺服器開發者建立的伺服器
這種分離確保了伺服器開發者可以專注於封裝其領域特定服務,而無需擔心AI編排。同時,AI應用程式開發者可以利用現有的MCP伺服器,而無需瞭解每個第三方服務的複雜性。
這種分工意味著資料庫專家可以為PostgreSQL建立一個MCP伺服器,而無需理解LLM提示,而AI應用程式開發者可以使用該PostgreSQL伺服器,而無需瞭解SQL內部機制。MCP協議充當了它們之間的通用語言。
Spring AI透過MCP客戶端和MCP伺服器Boot Starters支援這種架構。這意味著Spring開發者可以參與MCP生態系統的兩方面——構建消費MCP伺服器的AI應用程式,以及建立將基於Spring的服務暴露給更廣泛AI社群的MCP伺服器。
客戶端和伺服器共享,MCP提供了一套廣泛的功能,使AI應用程式和外部服務之間能夠無縫通訊。
重要:工具由LLM擁有,與其他MCP功能(如提示和資源)不同。LLM(而不是宿主)決定何時、以何種順序呼叫工具。宿主只控制哪些工具描述提供給LLM。
讓我們構建一個提供即時天氣預報資訊的可流式HTTP MCP伺服器。
建立一個新的 (mcp-weather-server) Spring Boot應用程式
@SpringBootApplication
public class McpServerApplication {
public static void main(String[] args) {
SpringApplication.run(McpServerApplication.class, args);
}
}
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-server-webmvc</artifactId>
</dependency>
瞭解更多關於可用的伺服器依賴選項。
在application.properties中啟用可流式HTTP伺服器傳輸
spring.ai.mcp.server.protocol=STREAMABLE
您可以使用STREAMABLE、STATELESS或SSE傳輸啟動伺服器。要啟用STDIO傳輸,您需要設定spring.ai.mcp.server.stdio=true。
利用免費的天氣REST API構建一個能夠透過位置座標檢索天氣預報的服務。
新增@McpTool和@McpToolParam註解以將getTemperature方法註冊為MCP伺服器工具
@Service
public class WeatherService {
public record WeatherResponse(Current current) {
public record Current(LocalDateTime time, int interval, double temperature_2m) {}
}
@McpTool(description = "Get the temperature (in celsius) for a specific location")
public WeatherResponse getTemperature(
@McpToolParam(description = "The location latitude") double latitude,
@McpToolParam(description = "The location longitude") double longitude) {
return RestClient.create()
.get()
.uri("https://api.open-meteo.com/v1/forecast?latitude={latitude}&longitude={longitude}¤t=temperature_2m",
latitude, longitude)
.retrieve()
.body(WeatherResponse.class);
}
}
./mvnw clean install -DskipTests
java -jar target/mcp-weather-server-0.0.1-SNAPSHOT.jar
這將在埠8080上啟動mcp-weather-server。
MCP天氣伺服器啟動並執行後,您可以使用各種符合MCP的客戶端應用程式與之互動
MCP檢查器是一個互動式開發工具,用於測試和除錯MCP伺服器。要啟動檢查器,請執行
npx @modelcontextprotocol/inspector
在瀏覽器UI中,將傳輸型別設定為Streamable HTTP,URL設定為https://:8080/mcp。點選Connect建立連線。然後列出工具並執行getTemperature。
使用MCP Java SDK客戶端以程式設計方式連線到伺服器
var client = McpClient.sync(
HttpClientStreamableHttpTransport
.builder("https://:8080").build())
.build();
client.initialize();
CallToolResult weather = client.callTool(
new CallToolRequest("getTemperature",
Map.of("latitude", "47.6062",
"longitude", "-122.3321")));
其他符合MCP的AI應用程式/SDK
將您的MCP伺服器連線到流行的AI應用程式
要與Claude桌面版整合,使用本地STDIO傳輸,請在Claude桌面版設定中新增以下配置
{
"mcpServers": {
"spring-ai-mcp-weather": {
"command": "java",
"args": [
"-Dspring.ai.mcp.server.stdio=true",
"-Dspring.main.web-application-type=none",
"-Dlogging.pattern.console=",
"-jar",
"/path/to/mcp-weather-server-0.0.1.jar"]
}
}
}
將/absolute/path/to/替換為您的構建JAR檔案的實際路徑。
請遵循Claude桌面版的MCP伺服器安裝以獲取進一步指導。Claude桌面版的免費版本不支援取樣!
讓我們擴充套件我們的MCP天氣伺服器,以演示包括日誌、進度跟蹤和取樣在內的高階MCP功能。這些功能實現了伺服器和客戶端之間豐富的互動
在這個增強版本中,我們的天氣伺服器將向客戶端記錄其操作以實現透明度,在獲取和處理天氣資料時報告進度,並請求客戶端的LLM生成一首關於天氣預報的史詩般詩歌。
這是更新後的伺服器實現
@Service
public class WeatherService {
public record WeatherResponse(Current current) {
public record Current(LocalDateTime time, int interval, double temperature_2m) {}
}
@McpTool(description = "Get the temperature (in celsius) for a specific location")
public String getTemperature(
McpSyncServerExchange exchange, // (1)
@McpToolParam(description = "The location latitude") double latitude,
@McpToolParam(description = "The location longitude") double longitude,
@McpProgressToken String progressToken) { // (2)
exchange.loggingNotification(LoggingMessageNotification.builder() // (3)
.level(LoggingLevel.DEBUG)
.data("Call getTemperature Tool with latitude: " + latitude + " and longitude: " + longitude)
.meta(Map.of()) // non null meta as a workaround for bug: ...
.build());
WeatherResponse weatherResponse = RestClient.create()
.get()
.uri("https://api.open-meteo.com/v1/forecast?latitude={latitude}&longitude={longitude}¤t=temperature_2m",
latitude, longitude)
.retrieve()
.body(WeatherResponse.class);
String epicPoem = "MCP Client doesn't provide sampling capability.";
if (exchange.getClientCapabilities().sampling() != null) {
// 50% progress
exchange.progressNotification(new ProgressNotification(progressToken, 0.5, 1.0, "Start sampling")); // (4)
String samplingMessage = """
For a weather forecast (temperature is in Celsius): %s.
At location with latitude: %s and longitude: %s.
Please write an epic poem about this forecast using a Shakespearean style.
""".formatted(weatherResponse.current().temperature_2m(), latitude, longitude);
CreateMessageResult samplingResponse = exchange.createMessage(CreateMessageRequest.builder()
.systemPrompt("You are a poet!")
.messages(List.of(new SamplingMessage(Role.USER, new TextContent(samplingMessage))))
.build()); // (5)
epicPoem = ((TextContent) samplingResponse.content()).text();
}
// 100% progress
exchange.progressNotification(new ProgressNotification(progressToken, 1.0, 1.0, "Task completed"));
return """
Weather Poem: %s
about the weather: %s°C at location: (%s, %s)
""".formatted(epicPoem, weatherResponse.current().temperature_2m(), latitude, longitude);
}
}
McpSyncServerExchange - exchange引數提供對伺服器-客戶端通訊功能的訪問。它允許伺服器傳送通知並向客戶端發出請求。
@ProgressToken - progressToken引數啟用進度跟蹤。客戶端提供此令牌,伺服器使用它傳送進度更新。
日誌通知 - 向客戶端傳送結構化日誌訊息以進行除錯和監控。
進度更新 - 向客戶端報告操作進度(在本例中為50%),並附帶描述性訊息。
這允許伺服器利用客戶端的AI功能,建立雙向AI互動模式。
增強後的天氣服務現在不僅返回天氣資料,還返回一首關於天氣預報的創意詩歌,展示了MCP伺服器和AI模型之間強大的協同作用。
讓我們構建一個使用LLM並透過MCP客戶端連線到MCP伺服器的AI應用程式。
建立一個新的Spring Boot專案 (mcp-weather-client),並新增以下依賴
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-anthropic</artifactId>
</dependency>
瞭解關於可用依賴選項以配置不同的傳輸機制。
在application.yml中,配置與MCP伺服器的連線
spring:
main:
web-application-type: none
ai:
# Set credentials for your Anthropic API account
anthropic:
api-key: ${ANTHROPIC_API_KEY}
# Connect to the MCP Weather Server using streamable-http client transport
mcp:
client:
streamable-http:
connections:
my-weather-server:
url: https://:8080
請注意,配置已為伺服器連線分配了my-weather-server名稱。
建立一個使用連線到LLM和MCP天氣伺服器的ChatClient的客戶端應用程式。
@SpringBootApplication
public class McpClientApplication {
public static void main(String[] args) {
SpringApplication.run(McpClientApplication.class, args).close(); // (1)
}
@Bean
public ChatClient chatClient(ChatClient.Builder chatClientBuilder) { // (2)
return chatClientBuilder.build();
}
String userPrompt = """
Check the weather in Amsterdam right now and show the creative response!
Please incorporate all creative responses from all LLM providers.
""";
@Bean
public CommandLineRunner predefinedQuestions(ChatClient chatClient, ToolCallbackProvider mcpToolProvider) { // (3)
return args -> System.out.println(
chatClient.prompt(userPrompt) // (4)
.toolContext(Map.of("progressToken", "token-" + new Random().nextInt())) // (5)
.toolCallbacks(mcpToolProvider) // (6)
.call()
.content());
}
}
應用程式生命週期管理 - 應用程式啟動、執行天氣查詢、顯示結果,然後乾淨地退出。
ChatClient配置 - 使用Spring AI的自動配置構建器建立一個已配置的ChatClient bean。構建器會自動填充
CommandLineRunner - 在應用程式上下文完全載入後自動執行。它注入了已配置的ChatClient用於AI模型互動,以及包含所有已註冊的MCP工具的ToolCallbackProvider,這些工具來自連線的伺服器。
AI提示 - 指示AI模型獲取阿姆斯特丹的當前天氣。AI模型會根據提示自動發現並呼叫適當的MCP工具。
進度令牌 - 使用toolContext將唯一的progressToken傳遞給帶有@McpProgressToken引數註解的MCP工具。
MCP工具整合 - 這條關鍵行將ChatClient連線到所有可用的MCP工具
mcpToolProvider由Spring AI的MCP客戶端啟動器自動配置spring.ai.mcp.client.*.connections.*配置)建立一個服務類來處理來自伺服器的MCP通知和請求。這些處理器是我們在上面實現的高階伺服器功能的客戶端對應部分,實現了MCP伺服器和客戶端之間的雙向通訊。
@Service
public class McpClientHandlers {
private static final Logger logger = LoggerFactory.getLogger(McpClientHandlers.class);
private final ChatClient chatClient;
public McpClientHandlers(@Lazy ChatClient chatClient) { // Lazy is needed to avoid circular dependency
this.chatClient = chatClient;
}
@McpProgress(clients = "my-weather-server") // (1)
public void progressHandler(ProgressNotification progressNotification) {
logger.info("MCP PROGRESS: [{}] progress: {} total: {} message: {}",
progressNotification.progressToken(), progressNotification.progress(),
progressNotification.total(), progressNotification.message());
}
@McpLogging(clients = "my-weather-server")
public void loggingHandler(LoggingMessageNotification loggingMessage) {
logger.info("MCP LOGGING: [{}] {}", loggingMessage.level(), loggingMessage.data());
}
@McpSampling(clients = "my-weather-server")
public CreateMessageResult samplingHandler(CreateMessageRequest llmRequest) {
logger.info("MCP SAMPLING: {}", llmRequest);
String llmResponse = chatClient
.prompt()
.system(llmRequest.systemPrompt())
.user(((TextContent) llmRequest.messages().get(0).content()).text())
.call()
.content();
return CreateMessageResult.builder().content(new TextContent(llmResponse)).build();
}
}
進度處理器 - 接收來自伺服器長時間執行操作的即時進度更新。當伺服器呼叫exchange.progressNotification(...)時觸發。例如,天氣伺服器在開始取樣時傳送50%的進度,完成時傳送100%。通常用於顯示進度條、更新UI狀態或記錄操作進度。
日誌處理器 - 接收來自伺服器的結構化日誌訊息以進行除錯和監控。當伺服器呼叫exchange.loggingNotification(...)時觸發。例如,天氣伺服器記錄“呼叫getTemperature工具,緯度:X,經度:Y”。用於除錯伺服器操作、審計跟蹤或監控儀表板。
取樣處理器 - 最強大的功能。它使伺服器能夠從客戶端的LLM請求AI生成的內容。用於雙向AI互動、創意內容生成、動態響應。當伺服器呼叫帶有采樣功能檢查的exchange.createMessage(...)時觸發。執行流程如下
基於註解的路由:clients = "my-weather-server"屬性確保處理器僅處理來自配置中定義的特定MCP伺服器連線的通知:spring.ai.mcp.client.streamable-http.connections.[my-weather-server].url。
如果您的應用程式連線到多個MCP伺服器,請使用clients屬性將每個處理器分配給相應的MCP客戶端。
@McpProgress(clients = {"weather-server", "database-server"}) // Handle progress from multiple servers
public void multiServerProgressHandler(ProgressNotification notification) {
// Handle progress from both servers
}
@McpSampling(clients = "specialized-ai-server") // Handle sampling from specific server
public CreateMessageResult specializedSamplingHandler(CreateMessageRequest request) {
// Handle sampling requests from specialized AI server
}
ChatClient上的@Lazy註解可以防止在ChatClient也依賴於MCP元件時可能出現的迴圈依賴問題。
雙向AI通訊:取樣處理器建立了一個強大的模式,其中
伺服器(領域專家)可以利用客戶端的AI功能
客戶端的LLM根據伺服器提供的上下文生成創意內容
這實現了超越簡單工具呼叫的複雜AI-AI互動
這種架構使MCP客戶端成為伺服器操作中的反應式參與者,實現了複雜的互動,而不僅僅是被動的工具消費。
使用不同的傳輸連線到多個MCP伺服器。以下是如何在您的天氣伺服器旁邊新增Brave搜尋MCP伺服器進行網頁搜尋的示例
spring:
ai:
anthropic:
api-key: ${ANTHROPIC_API_KEY}
mcp:
client:
streamable-http:
connections:
my-weather-server:
url: https://:8080
stdio:
connections:
brave-search:
command: npx
args: ["-y",
"@modelcontextprotocol/server-brave-search"]
它使用STDIO客戶端傳輸。
現在您的LLM可以在單個提示中結合天氣資料和網頁搜尋
String userPrompt = """
Check the weather in Amsterdam and show the creative response!
Please incorporate all creative responses.
Then search online to find publishers for poetry and list top 3.
""";
確保您的MCP天氣伺服器已啟動並執行。
然後構建並啟動您的客戶端
./mvnw clean install -DskipTests
java -jar target/mcp-weather-client-0.0.1-SNAPSHOT.jar
Spring成熟的開發模型與MCP標準化協議的結合,為下一代AI應用程式奠定了堅實的基礎。無論您是構建聊天機器人、資料分析工具還是開發助手,Spring AI的MCP支援都能為您提供所需的構建塊。
本介紹涵蓋了基本的MCP概念,並演示瞭如何使用Spring AI的Boot Starters構建MCP伺服器和客戶端,並實現了基本的工具功能。然而,MCP生態系統提供了更復雜的功能,我們將在未來的部落格文章中進行探討。
Java MCP註解深入探討:學習如何利用Spring AI的基於註解的方法建立更易於維護和宣告式的MCP實現,包括高階註解模式和最佳實踐。
超越工具 - 提示、資源和補全:探索如何實現MCP的全套功能,包括共享提示模板、動態資源提供和智慧自動補全功能,這些功能使您的MCP伺服器更加使用者友好和強大。
授權支援 - 保護MCP伺服器:使用OAuth 2保護您的MCP伺服器,並確保只有授權使用者才能訪問工具、資源和其他功能。為您的MCP客戶端新增授權支援,以便它們可以獲取OAuth 2令牌以與安全的MCP伺服器進行身份驗證。
準備好開始了嗎?檢視示例應用程式,探索Spring AI和MCP與AI整合的全部潛力。
有關最新更新和全面文件,請訪問Spring AI參考文件。