使用 Spring AI 探索模型上下文協議 (MCP)
1. 概述
現代網路應用程式越來越多地與大型語言模型 (LLM) 結合來建立解決方案,而這些解決方案不僅限於基於一般知識的問答。
為了增強 AI 模型的反應並使其更具情境感知能力,我們可以將其連接到外部來源,例如搜尋引擎、資料庫和檔案系統。然而,整合和管理具有不同格式和協定的多個資料來源是一項挑戰。
Anthropic推出的模型上下文協定 (MCP) 解決了這項整合挑戰,並提供了一種將人工智慧應用程式與外部資料來源連接起來的標準化方法。透過 MCP,我們可以在本機 LLM 之上建立複雜的代理和工作流程。
在本教程中,我們將透過使用 Spring AI 實際實作 MCP 的客戶端-伺服器架構來了解 MCP 的概念。我們將創建一個簡單的聊天機器人,並透過 MCP 伺服器擴展其功能以執行網路搜尋、執行檔案系統操作和存取自訂業務邏輯。
2. 模型上下文協定 101
在深入實現之前,讓我們仔細看看 MCP 及其各個元件:
MCP 遵循客戶端-伺服器架構,圍繞幾個關鍵元件:
- MCP Host :是我們的主要應用程序,它與 LLM 整合並需要它與外部資料來源連接
- MCP 用戶端:是與 MCP 伺服器建立並維持 1:1 連線的元件
- MCP 伺服器:是與外部資料來源整合並公開與其互動功能的元件
- 工具:指 MCP 伺服器開放給客戶端的可執行函數/方法
此外,為了處理客戶端和伺服器之間的通信,MCP 提供了兩個傳輸通道。
為了實現透過標準輸入和輸出流與本地進程和命令列工具的通信,它提供了標準輸入/輸出(stdio)傳輸類型。或者,對於客戶端和伺服器之間的基於 HTTP 的通信,它提供了伺服器發送事件 (SSE) 傳輸類型。
MCP 是一個複雜而龐大的主題,請參閱官方文件以了解更多資訊。
3. 建立 MCP 主機
現在我們已經對 MCP 有了高層次的了解,讓我們開始實際實作 MCP 架構。
我們將使用 Anthropic 的 Claude 模型來建立一個聊天機器人,它將充當我們的 MCP 主機。或者,我們可以透過 Hugging Face 或 Ollama 使用本地 LLM,因為特定的 AI 模型與此演示無關。
3.1.依賴項
讓我們先在專案的pom.xml
檔案中加入必要的依賴項:
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-anthropic-spring-boot-starter</artifactId>
<version>1.0.0-M6</version>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-mcp-client-spring-boot-starter</artifactId>
<version>1.0.0-M6</version>
</dependency>
Anthropic 啟動器依賴項是Anthropic Message API 的包裝器,我們將使用它在我們的應用程式中與 Claude 模型進行互動。
此外,我們匯入了MCP 用戶端啟動器依賴項,這將允許我們在 Spring Boot 應用程式內配置與 MCP 伺服器保持 1:1 連接的用戶端。
由於目前版本1.0.0-M6
是一個里程碑版本,我們還需要將 Spring Milestones 儲存庫新增到我們的pom.xml
中:
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
此儲存庫是發布里程碑版本的地方,與標準 Maven Central 儲存庫不同。
鑑於我們在專案中使用了多個 Spring AI 啟動器,我們還將在pom.xml
中包含Spring AI 物料清單 (BOM) :
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<version>1.0.0-M6</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
透過這個添加,我們現在可以從兩個啟動依賴項中刪除version
標籤。 BOM 消除了版本衝突的風險,並確保我們的 Spring AI 依賴關係彼此相容。
接下來,讓我們在application.yaml
檔案中設定我們的Anthropic API 金鑰和聊天模型:
spring:
ai:
anthropic:
api-key: ${ANTHROPIC_API_KEY}
chat:
options:
model: claude-3-7-sonnet-20250219
我們使用${}
屬性佔位符從環境變數載入 API 金鑰的值。
此外,我們使用claude-3-7-sonnet-20250219
模型 ID 指定 Anthropic 最聰明的模型Claude 3.7 Sonnet 。請隨意探索並根據需求使用不同的模型。
配置上述屬性後, Spring AI 會自動建立一個ChatModel
類型的 bean,讓我們可以與指定的模型互動。
3.2.為 Brave Search 和檔案系統伺服器設定 MCP 用戶端
現在,讓我們為兩個預先建置的 MCP 伺服器實作設定 MCP 用戶端: Brave Search和Filesystem 。這些伺服器將使我們的聊天機器人能夠執行網路搜尋和檔案系統操作。
讓我們先在application.yaml
檔案中為 Brave 搜尋 MCP 伺服器註冊一個 MCP 用戶端:
spring:
ai:
mcp:
client:
stdio:
connections:
brave-search:
command: npx
args:
- "-y"
- "@modelcontextprotocol/server-brave-search"
env:
BRAVE_API_KEY: ${BRAVE_API_KEY}
在這裡,我們用stdio
傳輸來配置一個client
。我們指定npx
command
來下載並執行基於 TypeScript 的@modelcontextprotocol/server-brave-search
包,並使用-y
標誌確認所有安裝提示。
此外,我們也提供BRAVE_API_KEY
作為環境變數。
接下來,讓我們為檔案系統 MCP 伺服器設定一個 MCP 用戶端:
spring:
ai:
mcp:
client:
stdio:
connections:
filesystem:
command: npx
args:
- "-y"
- "@modelcontextprotocol/server-filesystem"
- "./"
與前面的設定類似,我們指定執行Filesystem MCP 伺服器套件所需的command
和參數。此設定允許我們的聊天機器人執行在指定目錄中建立、讀取和寫入檔案等操作。
這裡,我們只配置當前目錄( ./
)用於檔案系統操作,但是,我們可以透過將多個目錄新增到args
列表來指定多個目錄。
在應用程式啟動期間,Spring AI 將掃描我們的配置,建立 MCP 用戶端,並與相應的 MCP 伺服器建立連線。它還創建了一個SyncMcpToolCallbackProvider
類型的 bean,它提供了已配置的 MCP 伺服器公開的所有工具的清單。
3.3.建立基本的聊天機器人
配置 AI 模型和 MCP 用戶端後,讓我們建立一個簡單的聊天機器人:
@Bean
ChatClient chatClient(ChatModel chatModel, SyncMcpToolCallbackProvider toolCallbackProvider) {
return ChatClient
.builder(chatModel)
.defaultTools(toolCallbackProvider.getToolCallbacks())
.build();
}
我們首先使用ChatModel
和SyncMcpToolCallbackProvider
bean 來建立ChatClient
類型的 bean。 ChatClient 類別將作為我們與聊天完成模型(即 Claude 3.7 Sonnet)互動的主要入口點。
接下來,讓我們注入ChatClient
bean 來建立一個新的ChatbotService
類別:
String chat(String question) {
return chatClient
.prompt()
.user(question)
.call()
.content();
}
我們創建一個chat()
方法,將使用者的question
傳遞給聊天客戶端bean,並簡單地傳回 AI 模型的回應。
現在我們已經實作了服務層,讓我們在其上公開一個 REST API :
@PostMapping("/chat")
ResponseEntity<ChatResponse> chat(@RequestBody ChatRequest chatRequest) {
String answer = chatbotService.chat(chatRequest.question());
return ResponseEntity.ok(new ChatResponse(answer));
}
record ChatRequest(String question) {}
record ChatResponse(String answer) {}
在本教學的後面我們將使用上述 API 端點與我們的聊天機器人互動。
4. 建立自訂 MCP 伺服器
除了使用預先建置的 MCP 伺服器之外,我們還可以建立自己的 MCP 伺服器,以使用我們的業務邏輯來擴展聊天機器人的功能。
讓我們探索如何使用 Spring AI 建立自訂 MCP 伺服器。
我們將在本節中建立一個新的 Spring Boot 應用程式。
4.1.依賴項
首先,讓我們在pom.xml
檔案中包含必要的依賴項:
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-mcp-server-webmvc-spring-boot-starter</artifactId>
<version>1.0.0-M6</version>
</dependency>
我們導入Spring AI 的 MCP 伺服器依賴項,它提供了建立支援基於 HTTP 的 SSE 傳輸的自訂 MCP 伺服器所需的類別。
4.2.訂和公開自訂工具
接下來,讓我們定義一些 MCP 伺服器將公開的自訂工具。
我們將建立一個AuthorRepository
類,提供獲取作者詳細資訊的方法:
class AuthorRepository {
@Tool(description = "Get Baeldung author details using an article title")
Author getAuthorByArticleTitle(String articleTitle) {
return new Author("John Doe", "[email protected]");
}
@Tool(description = "Get highest rated Baeldung authors")
List<Author> getTopAuthors() {
return List.of(
new Author("John Doe", "[email protected]"),
new Author("Jane Doe", "[email protected]")
);
}
record Author(String name, String email) {
}
}
為了演示,我們返回硬編碼的作者詳細信息,但在實際應用程式中,這些工具通常會與資料庫或外部 API 互動。
我們用@Tool
註釋註釋我們的兩種方法,並為它們每個提供簡短的description
。此description
有助於 AI 模型根據使用者輸入決定是否以及何時調用工具並將結果納入其回應中。
接下來,讓我們將我們的創作工具註冊到 MCP 伺服器:
@Bean
ToolCallbackProvider authorTools() {
return MethodToolCallbackProvider
.builder()
.toolObjects(new AuthorRepository())
.build();
}
我們使用MethodToolCallbackProvider
從AuthorRepository
類別中定義的工具中建立一個ToolCallbackProvider
bean。用@Tool
註釋的方法將在應用程式啟動時公開為 MCP 工具。
4.3.為我們的自訂 MCP 伺服器設定 MCP 用戶端
最後,為了在我們的聊天機器人應用程式中使用我們的自訂 MCP 伺服器,我們需要針對它配置一個 MCP 用戶端:
spring:
ai:
mcp:
client:
sse:
connections:
author-tools-server:
url: http://localhost:8081
在application.yaml
檔案中,我們根據自訂 MCP 伺服器設定一個新的客戶端。請注意,我們這裡使用的是sse
傳輸類型。
此配置假定 MCP 伺服器運行於http://localhost:8081
,如果它運行於不同的主機或端口,請確保更新url
。
透過此配置,除了 Brave Search 和 Filesystem MCP 伺服器提供的工具之外,我們的 MCP 用戶端現在還可以呼叫我們自訂伺服器公開的工具。
5. 與我們的聊天機器人互動
現在我們已經建立了聊天機器人並將其與各種 MCP 伺服器集成,讓我們與它進行互動並進行測試。
我們將使用 HTTPie CLI 來呼叫聊天機器人的 API 端點:
http POST :8080/chat question="How much was Elon Musk's initial offer to buy OpenAI in 2025?"
在這裡,我們向聊天機器人發送一個簡單的question
,關於 LLM 知識截止日期之後發生的事件。讓我們看看我們得到了什麼回應:
`{
"answer": "Elon Musk's initial offer to buy OpenAI was $97.4 billion. Source."
}`
我們可以看到,聊天機器人能夠使用配置的 Brave Search MCP 伺服器執行網路搜索,並提供準確的答案以及來源。
接下來,讓我們驗證聊天機器人是否可以使用檔案系統 MCP 伺服器執行檔案系統操作:
http POST :8080/chat question="Create a text file named 'mcp-demo.txt' with content 'This is awesome!'."
我們指示聊天機器人創建一個具有特定內容的mcp-demo.txt
檔案。讓我們看看它是否能夠滿足請求:
`{
"answer": "The text file named 'mcp-demo.txt' has been successfully created with the content you specified."
}`
聊天機器人回應成功的答案。我們可以驗證該檔案是在我們在application.yaml
檔案中指定的目錄中建立的。
最後,讓我們驗證聊天機器人是否可以呼叫我們自訂 MCP 伺服器公開的工具之一。我們將透過提及文章標題來詢問作者的詳細資訊:
http POST :8080/chat question="Who wrote the article 'Testing CORS in Spring Boot?' on Baeldung, and how can I contact them?"
讓我們呼叫 API 並查看聊天機器人回應是否包含硬編碼的作者詳細資訊:
`{
"answer": "The article 'Testing CORS in Spring Boot' on Baeldung was written by John Doe. You can contact him via email at [[email protected]](mailto:[email protected])."
}`
上述回應驗證聊天機器人是否使用我們自訂 MCP 伺服器公開的getAuthorByArticleTitle()
工具來取得作者詳細資訊。
我們強烈建議在本地設置程式碼庫並使用不同的提示來嘗試聊天機器人。
6. 結論
在本文中,我們探討了模型上下文協定並使用 Spring AI 實現了其客戶端-伺服器架構。
首先,我們使用 Anthropic 的 Claude 3.7 Sonnet 模型建立了一個簡單的聊天機器人作為我們的 MCP 主機。
然後,為了讓我們的聊天機器人具有網路搜尋功能並使其能夠執行檔案系統操作,我們根據 Brave Search API 和檔案系統的預先建置 MCP 伺服器實作配置了 MCP 用戶端。
最後,我們建立了一個自訂 MCP 伺服器,並在我們的 MCP 主機應用程式內配置了其對應的 MCP 用戶端。
與往常一樣,本文使用的所有程式碼範例均可在 GitHub 上找到。