手搓MCP客户端动态调用多MCP服务,调用哪个你说了算!

关注我的公众号:【编程朝花夕拾】,可获取首发内容。

01 引言

前两天,有个粉丝朋友咨询MCP服务如何动态调用,动态加载MCP服务的链接?我们都知道MCP客户端可以配置多个MCP服务的地址:

properties 复制代码
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到发送请求参数,就只有ChatModelToolCallbackProvider两个参数。而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配置

java 复制代码
@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 小结

到这里粉丝朋友的问题就全部解决了。同时,也分享给大家,希望对大家有帮助!

相关推荐
沸腾_罗强9 分钟前
redis内存被打爆了
后端
期待のcode11 分钟前
SpringMVC请求与响应
java·后端·spring
阿熊不凶27 分钟前
c语言中堆和栈的区别
java·c语言·jvm
Lethehong35 分钟前
飞算JavaAI:革新Java开发体验的智能助手
java·开发语言·java开发·飞算javaai炫技赛
泰勒疯狂展开36 分钟前
Java研学-RabbitMQ(八)
java·rabbitmq·java-rabbitmq
Java水解41 分钟前
Spring Boot 全局异常处理与日志监控实战
后端·面试
-睡到自然醒~41 分钟前
[go] 命令模式
java·开发语言·javascript·后端·golang·命令模式
别来无恙14943 分钟前
JavaWeb核心:HttpServletRequest与HttpServletResponse详解
java·前端·servlet
MrSYJ44 分钟前
为什么引入springsecurity的依赖后,会自动创建了过滤器链
spring boot·后端·代码规范
寒士obj1 小时前
熟悉并使用Spring框架 - XML篇
xml·java·spring