01 引言
前兩天,有個粉絲朋友咨詢MCP
服務如何動態調用,動態加載MCP
服務的鏈接?我們都知道MCP
客戶端可以配置多個MCP
服務的地址:
spring.ai.mcp.client.sse.connections.server1.url=http://localhost:xxxx
spring.ai.mcp.client.sse.connections.server2.url=http://localhost:xxxx
spring.ai.mcp.client.sse.connections.server3.url=http://localhost:xxxx
這樣的MCP
服務會自動加載到項目中,類似合成一個服務。一個請求進來,MCP
客戶端會在所有的服務中尋找合適的方法。
但是,業務中總會有各種不同的場景。例如,粉絲朋友的需求。SpringBoot
一直堅持約定大于配置的方式,Spring AI
也不例外,既然提供配置文件的配置,那么JavaBean
的配置一樣可行。指定調用只要需要找到調用的時機,自然可以控制。
本篇就帶大家一起解決這份粉絲朋友的問題。
02 MCP
動態調用
2.1 代碼追蹤
在研究動態調用之前,我們需要知道配置用在了哪里?
我們直接在.properties
或.yml
配置文件中,
按住Ctrl
,然后用鼠標點擊url
,就會跳轉到下面的文件:
從方法中可以看到:
最終的配置會保存在SseParameters
中,最后放到Map
集合中。使用或者獲取服務鏈接的時候,肯定也會通過getConnections()
來獲取,這個也是突破問題的關鍵。
2.2 探尋使用位置
上面找到了配置文件對用的Java
類:
org.springframework.ai.mcp.client.autoconfigure.properties.McpSseClientProperties
我們可以采用上面相同的方法,看看哪里調用了getConnections()
,由于我們的源碼沒有全部下載下來,所以很大程度上可能找不到。所以,斷點提示就變成了我們唯一的出路。
斷點啟動之后,我們看到連接數為0,也就是還沒有加載MCP
服務的鏈接呢。如下圖:
我們斷點繼續向下執行(快捷鍵:F8
),中間會經歷漫長的Bean
的創建過程。我們的目標就是看看是哪一個Bean
實例化的時候會獲取連接。
我們就需要注意幾個注解:@Bean
、@Component
等,終于實例化出來了,找到了關鍵類:
org.springframework.ai.mcp.client.autoconfigure.McpClientAutoConfiguration
具體如圖:
我們可以看到namedTransports
里面就包含了我們MCP
服務,最終放到mcpSyncClients
集合中,如下圖:
至此,Spring 啟動隨后完成。
2.3 修改點
我們可以看到mcpSyncClients
集合上有@Bean
標簽,所以會被Spring
管理,所以可以直接從Spring
容器中,通過注入的方式獲取到。
但是修改點有在哪里呢?我們先看看MCP
調用的案例:
從構建ChatClient
到發送請求參數,就只有ChatModel
和ToolCallbackProvider
兩個參數。而ChatMode
表示采用的大模型的類型,顯然和MCP
服務沒有關系,就只有ToolCallbackProvider
這個類了。
org.springframework.ai.tool.ToolCallbackProvider
的實現有四個:
通過注入的ToolCallbackProvider
,我們斷點可以看到它的實現是:
org.springframework.ai.mcp.SyncMcpToolCallbackProvider
從代碼的構造啟可以看到,參數就是我們上面注入的mcpSyncClients
。
2.4 動態調用
我們只要根據MCP
服務的名稱區分不同的McpSyncClient
即可。
我們從截圖可以看到:
小編提供了兩個MCP
服務,分別是csdn-mcp-server
(CSDN
文章瀏覽服務)和gzh-mcp-server
(種種好推薦服務)。小編沒有傳遞參數,默認會調用gzh-mcp-server
。
我們看看返回的結果:
請求是一個與csdn-mcp-server
匹配度比較高的請求,最終只調用了gzh-mcp-server
。所以我們就可以控制調用的MCP
服務了。
03 動態加載
動態調用的問題,我們已經解決了。如果這些服務鏈接想從數據庫讀取,又該如何處理呢?
最直接的想法,就是直接將配置文件對應的Bean
自己new
出來交給Spring
管理。
3.1 配置McpSseClientProperties
Bean配置
@Bean
public McpSseClientProperties mcpSseClientProperties() {McpSseClientProperties mcpSseClientProperties = new McpSseClientProperties();Map<String, SseParameters> connections = mcpSseClientProperties.getConnections();connections.put("server1", new SseParameters("http://localhost:8080", null));connections.put("server2", new SseParameters("http://localhost:8082", null));return mcpSseClientProperties;
}
啟動結果
McpSseClientProperties
發現了2個,實際只需要一個。也就是說,框架自動實例化McpSseClientProperties
和我們的沖突了。
這種方式行不通!!!
既然已經存在,那就直接添加連接呢?因為Spring
默認是單例。
3.2 動態加載鏈接
容器啟動后加載鏈接
測試
已經加載成功了。
04 小結
到這里粉絲朋友的問題就全部解決了。同時,也分享給大家,希望對大家有幫助!