前言
在接入自己本地配置的 MCP Server 之后,我们已经具备了 整体流程 的知识基础,这篇文章中,由于是调用第三方的Server,代码的调整重心主要是在 Client 这边。
那么接下来就开始我们的接入吧
高德 MCP 服务获取
首先我们需要获取 高德的 MCP 服务,有了 高德的MCP服务调用的方法,我们才能针对性地对代码进行调整 相关链接:
成为高德地图开发者
进入 高德开放平台 | 高德地图API,登录或者注册账户后,
前往创建应用和 Key-MCP Server|高德地图API查看大致的流程,如图:

得到 API-KEY
跟着上述链接里面的 内容执行完后,页面应该是这样子:

这个 Key 字段下的值,就是我们需要的 API_KEY, 记得保存 到自己的配置文件中。
查看使用方法
在上述文档中,找到 SpringAI 的使用方式:
友情链接:快速接入-MCP Server|高德地图API

注意到 它需要我们添加配置类,并且在使用的时候 只能根据特定的城市进行天气查询。可是我们创建应用的时候不是支持很多功能吗?
那现在就到了我们 修改代码的时候了。
(如果不想看中间过程,可以直接跳转到 最终版本 环节)
修改代码
在开始修改前,我们还是得 老老实实地 将文档里的代码 搬到项目中。这样我们才有了参考。
搬运提示
如果想 注入自己在配置文件中 写入的 API_KEY 或者 URL等,可以考虑使用 @Value 注入 :
typescript
@Value("${amap.api-key}")
private String apiKey;
@Value("${amap.base-url}")
private String baseUrl;
@Bean
public List<NamedClientMcpTransport> aMapTransports() {
McpClientTransport transport = HttpClientSseClientTransport.builder(baseUrl)
.sseEndpoint("/sse?key=" + apiKey)
.objectMapper(new ObjectMapper())
.build();
return Collections.singletonList(new NamedClientMcpTransport("amap", transport));
}
开始修改
修改的思路 大致上来讲,是将能使用的工具拓展到 所有支持的服务上,而如何让AI自己去选择,我们就需要将这些工具注册到 AI 的请求中了。
所以修改的步骤如下:
找出所有支持的工具
尝试将工具注册到 容器,之后进一步注册到AI的请求中
测试是否可行
获取所有工具
在那个接口的代码中,我们可以注意到 在Lambda表达式中 有这些内容:
java
mcpClient.listTools()
.flatMap(tools -> {
logger.info("tools: {}", tools);
return mcpClient.callTool(
new McpSchema.CallToolRequest(
"maps_weather", Map.of("city", "北京")
)
);
});
可以看出 它们确实是获取到了 Tools,只是在获取了之后就开始了遍历,然后返回了天气查询的结果,
那我们是不是可以在获取到tools之后直接将逻辑截断呢,然后把tools 提取出来?
不浪费时间,我直接给出结果:
java
List<McpSchema.Tool> tools = mcpClient.listTools().block().tools();
我们可以通过这个式子 获取所有的工具,那现在就差 如何把工具注册进去了。
注册 工具
在之前的MCP 服务调用中,我们知道 传入的参数 是一个 ToolCallBackProvider 类型的数据,所以我们能不能如法炮制一个 ToolCallBackProvider 出来,然后放进去呢?
上代码:
less
@Component("aMapToolCallbackProvider")
public class AMapToolCallbackProvider implements ToolCallbackProvider {
@Autowired
@Qualifier("aMapTools")
private ToolCallback[] toolCallbacks;
@NotNull
@Override
public ToolCallback[] getToolCallbacks() {
return this.toolCallbacks;
}
}
我们通过 重写 getToolCallback() 方法注入了我们自己的 工具,那现在问题又来了,我们如何将工具 封装进ToolCallback[] 中呢?
封装工具
既然自己想不出来, SpringAI 肯定有相关的实现对吧,那这样子的话,我们去挖一挖源码,就能知道方法了。
查看 AsyncMcpToolCallbackProvider 内部的实现,我们发现包含了这些内容:

里面是 直接将 client 和 tool 一起放入了一个构造函数 ,然后直接返回 ToolCallback[] 对象,我们也照着它的来干一干
代码如下:
java
@Configuration
public class AMapMcpConfiguration {
@Autowired
private List<McpAsyncClient> mcpAsyncClients;
@Bean
public ToolCallback[] aMapTools(){
McpAsyncClient mcpClient = mcpAsyncClients.get(0);
ToolCallback[] toolCallbacks = mcpClient.listTools().map((response) -> {
return response.tools().stream().map((tool) -> {
return new AsyncMcpToolCallback(mcpClient, tool);
}).toArray(ToolCallback[]::new);
}).block();
return toolCallbacks;
}
}
然后我们就获取到了所有需要的对象,现在可以尝试着将 获取到的 ToolCallBackProvider 对象注入到里面去了,通过 @Qualifier 解决了注入问题后,删掉之前搬运过来的接口,代码应该是这样:
less
@RestController
@RequestMapping("/mcp")
public class MCPController extends AIController{
@Autowired
@Qualifier("aMapToolCallbackProvider")
ToolCallbackProvider aMapToolProvider;
@Autowired
@Qualifier("mcpAsyncToolCallbacks")
ToolCallbackProvider mcpToolProvider;
@Autowired
ChatClient chatClient;
@GetMapping("/push")
public String push(@RequestParam("message") String message) {
String infos = chatClient.prompt()
.user(message)
.toolCallbacks(mcpToolProvider,aMapToolProvider)
.call()
.content();
System.out.println(infos);
return infos;
}
}
尝试运行
运行后,一切正常
进行测试,发现报错了,说是有多个相同的工具被注册进去了:

其实这里就是 SpringAI 内部的机制导致的问题,还记得我们 获取 ToolCallback [] 的代码吗?
new AsyncMcpToolCallback(mcpClient, tool)
由于我们 获取的是 AsyncMapToolCallback 和 mcpToolProvider 中的 工具是一个类型,所以 mcpToolProvider 内部就包含了 我们注册上去的 工具。(相当于 SpringAI 提前帮我们注册上去了)
所以解决起来也很简单,删掉 aMapToolProvider 就可以了。
测试
调整了之后,进行测试,发现结果是对的,而且返回高德地图控制台,也能在流量详情 中 看到确实是发了请求:(会延迟几分钟)
流量详情 如下:
进一步思考
既然 SpringAI 会帮我们执行操作,那我们是不是只需要在配置文件中配置,然后它也可以全套操作都帮我们解决呢?
实践:
yaml
sse:
connections:
server1:
url: http://localhost:8085
server2:
url: https://mcp.amap.com
sse-endpoint: /sse?key=${AMAP_API_KEY}
进行这一配置后,将其他配置都添加注释,再次运行,结果还是正确的。
说明真的可以这么干,但是 高德地图的文档中明确说明了:

注意不要在配置文件中填写高德sse 连接
所以 怎么弄 就 见仁见智 咯。(应该是担心 key 会泄露)
最终版本
application.yaml:
yaml
sse:
connections:
server1:
url: http://localhost:8085
# sse-endpoint: /mcp/book
server2:
url: https://mcp.amap.com
sse-endpoint: /sse?key=${AMAP_API_KEY}
enabled: true
type: async
request-timeout: 60000
MCPController:
java
@RestController
@RequestMapping("/mcp")
public class MCPController extends AIController{
@Autowired
ToolCallbackProvider mcpToolProvider;
@Autowired
ChatClient chatClient;
@GetMapping("/push")
public String push(@RequestParam("message") String message) {
String infos = chatClient.prompt()
.user(message)
.toolCallbacks(mcpToolProvider)
.call()
.content();
System.out.println(infos);
return infos;
}
}
结束啦 !!!
最终版本 太简洁了 ヽ(ー_ー)ノ
总结
借助 整合 高德地图的 MCP,我们可以更深层次的了解到 SpringAI 是怎么注入工具类的。
也可以了解到如何进行配置,对后续的 MCP 导入会大有帮助。