首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

分享一个把你的API快速升级为MCP规范的方案,可在线体验

  • 25-04-23 21:21
  • 4683
  • 12290
juejin.cn

前言

前段时间,Anthropic发布了新版本MCP协议,在Remote MCP Server场景下实现了显著改进。此次更新的核心亮点是Streamable HTTP传输机制,它不仅继承了HTTP+SSE的实时消息传输能力,还通过一系列优化使得连接更加稳定、数据传输更具弹性。新版协议采用单一MCP端点同时支持HTTP POST和GET请求,通过强制使用Mcp-Session-Id头实现会话管理,并支持批量请求、响应和通知,以及SSE流的可恢复性。(摘自:开源 Remote MCP Server 一站式托管来啦)

作为java语言最流行的框架Spring,Spring AI模块中也接入了MCP,Spring AI MCP通过Spring Boot接入扩展了MCPJavaSDK,提供客户端和服务器启动器。 使用Spring初始化器引导您的AI应用程序支持MCP。(摘自:Spring AI官网)

今天给大家带来一个使用Spring AI MCP开发的开源项目:easy-remote-mcp,通过简单的实现思路,使用Spring AI MCP一个java应用支持多个MCP Server。为开发者提供一种高效且便捷的方式来管理和整合多个MCP服务器。(目前仅支持工具调用)

话不多说,直接上项目演示和体验地址。


项目演示

项目体验地址:http://123.56.187.33:8082/home (本地址仅供学习参考,未做任何安全防护,不要上传个人私密信息哦。)

核心功能:通过页面配置,把HTTP接口转化为标准MCP工具,并且提供MCP Client能直接访问的sse url。

1.首先进入首页,我们能看到已经创建好的两个示例的MCP Server,大家自己创建的MCP Server也会在这里展示。 image.png

因为该网址只为体验学习,不涉及用户登录,所以设置查看密钥来保护大家自己创建的MCP Server,可以在保存时自定义设置查看密钥。 image.png

2.进入新增/编辑页面 可以看到当前MCP Server的名称描述和下方提供的工具信息。其中请求url、请求方法、请求体就是需要转换为MCP工具的HTTP接口的信息。

目前仅支持GET和POST请求方式,GET真正请求时会将请求参数直接拼接在请求url上;POST请求则会转为json作为请求体,也就是仅支持application/json。

这里提供一个示例接口,内部是调用了高德地图的api。 image.png

点击查看sse访问url就可以看到当前MCP Server的访问url了。 image.png

3.进入cline使用我们的MCP Server,配置中新增我们的MCP Server配置。 image.png

在cline中使用我们的MCP Server。如果更新了我们的MCP Server,在cline中刷新也是能直接看到最新的信息的。 image.png


核心实现方式

Spring AI把McpServer作为Spring Bean进行了管理,所以Spring AI提供的MCP支持默认的就是一个java应用一个MCP Server。在这里我们对McpServer进行自主管理,做到一个java应用管理多个McpServer。

java
代码解读
复制代码
// 新增McpServer逻辑处理 // 对于每个新创建的MCP Server,生成一个随机字符串作为唯一标识 String randomStr = RandomUtil.randomString(6); // 为每个MCP Server创建一个单独的访问url,使用 /randomStr/sse 的格式确定访问url。 // 为这个新的MCP Server创建一个的协议,访问url添加刚刚生成的唯一标识字符串,确保每个MCP Server的唯一性 WebFluxSseServerTransportProvider transportProvider = new WebFluxSseServerTransportProvider(new ObjectMapper(), "", "/" + randomStr + "/sse/message", "/" + randomStr + "/sse"); McpSchema.Implementation serverInfo = new McpSchema.Implementation(mcpServer.getName(), "1.0.0"); io.modelcontextprotocol.server.McpServer.AsyncSpecification serverBuilder = io.modelcontextprotocol.server.McpServer.async(transportProvider).serverInfo(serverInfo); // 工具转换,把参数转化为Spring AI提供的ToolCallback,这里定义自己的RemoteMcpToolCallback List remoteMcpToolCallbacks = RemoteMcpUtil.convertToolCallback(detailVO.getTools()); // 工具转换,转换为符合MCP规范标准的工具类 List asyncToolSpecification = toAsyncToolSpecification(remoteMcpToolCallbacks); // 为新的MCP Server添加工具 serverBuilder.tools(asyncToolSpecification); McpSchema.ServerCapabilities build = McpSchema.ServerCapabilities.builder().tools(true).build(); serverBuilder.capabilities(build); McpAsyncServer asyncServer = serverBuilder.build(); // 添加到map集合中 以便后续对该MCP Server的更新和删除 serverMap.put(randomStr, asyncServer); toolSpecificationMap.put(randomStr, asyncToolSpecification); // 添加新的MCP Server路由 remoteMcpHandlerMapping.addMapping(randomStr, transportProvider.getRouterFunction());

每个MCP Server都有单独的路由url,自定义RemoteMcpHandlerMapping来实现各自的请求处理。

java
代码解读
复制代码
@Component public class RemoteMcpHandlerMapping extends AbstractHandlerMapping{ // 每个MCP Server的路由映射 private final Map> mappings = new HashMap<>(); // DispatcherHandler会调用此方法获取处理当前请求的handler @Override protected Mono getHandlerInternal(ServerWebExchange exchange) { // 获取路径中的随机字符串 MCP Server的唯一标识 String randomStr = exchange.getRequest().getURI().getPath().split("/")[1]; if (StrUtil.isBlank(randomStr) || !mappings.containsKey(randomStr)) { return Mono.empty(); } ServerRequest request = ServerRequest.create(exchange, this.messageReaders); // 使用特定的MCP Server的请求处理handler return mappings.get(randomStr).route(request).doOnNext((handler) -> this.setAttributes(exchange.getAttributes(), request, handler)); } // path:随机字符串,每个MCP Server的唯一标识 // mapping 路由 public void addMapping(String path, RouterFunction mapping) { mappings.put(path, mapping); } public void clear(String path) { mappings.remove(path); } }

自定义ToolCallback,用于处理工具调用的逻辑。

java
代码解读
复制代码
public class RemoteMcpToolCallback implements ToolCallback { private ToolDefinition toolDefinition; private ToolMetadata toolMetadata; private ToolVO toolVO; @Override public ToolDefinition getToolDefinition() { return toolDefinition; } @Override public ToolMetadata getToolMetadata() { return toolMetadata; } // 这里是简单的直接使用http工具类进行http请求,直接返回请求结果 @Override public String call(String toolInput) { JSONObject entries = JSONUtil.parseObj(toolInput); // 如果是GET请求,把参数拼在url上 if (StrUtil.equals(HttpMethod.GET.name(), toolVO.getMethod())) { StringBuilder url = new StringBuilder(toolVO.getUrl()); if (!entries.isEmpty()) { url.append("?"); for (Map.Entry entry : entries.entrySet()) { url.append(entry.getKey()).append("=").append(entry.getValue()).append("&"); } url = new StringBuilder(url.substring(0, url.length() - 1)); } return HttpUtil.get(url.toString()); } else { return HttpUtil.post(toolVO.getUrl(), entries.toString()); } } @Override public String call(String toolInput, ToolContext tooContext) { return call(toolInput); } }

最后

目前该项目仅完成了初版,已支持核心功能,但在业务逻辑处理和代码上还有很多不完善的地方,后续会新增oauth2验证等;如果存在代码逻辑错误等严重问题,还请多多指正,一起学习共同成长。

我相信,AI Agent结合MCP的未来一定是Local MCP Server与Remote MCP Server相辅相成。

注:本文转载自juejin.cn的super凹凸曼的文章"https://juejin.cn/post/7496341294568194099"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

109
人工智能
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2025 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top