资讯详情

AgentScope 学习系列 - 05:接入 MCP,让智能体拥有万千工具

📅 2026/10/15 14:09:34 | 华诺云谱 👁 阅读
AgentScope 学习系列 - 05:接入 MCP,让智能体拥有万千工具
1. MCP 的概念上一章我们用Tool注解和继承ToolBase自己写工具但真实业务里大部分能力比如地图、数据库、浏览器、GitHub早就有人封装好了。难道每接一个服务都要自己写一遍 toolMCPModel Context Protocol模型上下文协议就是为解决这个问题而生的。它是 Anthropic 提出的开放协议把工具怎么暴露给模型、怎么被调用标准化了服务方把能力包装成 MCP Server任何支持 MCP 的客户端agent 框架、IDE、聊天软件都能直接使用这些工具。Tool 要自己动手写MCP 则是直接接别人封装好的服务。1.1 AgentScope 中 MCP 的三个构件AgentScope Java 把 MCP 相关的构件组织成三个概念McpClientBuilder是连接构建器负责和 MCP Server 建立连接指定传输方式、鉴权、超时构建出客户端。McpClientWrapper持有连接提供listTools()、callTool()等基础能力实现了AutoCloseable用完要关。McpTool是继承自ToolBase的适配器。Toolkit 注册 MCP 客户端后会把 Server 上的每个工具包装成一个McpTool对 agent 来说它和上一章手写的 tool 没有任何区别。正因为McpTool也是ToolBase上一章讲的权限系统、Tool Group、事件流对 MCP 工具照样生效不用再学一套新东西。1.2 传输方式怎么选MCP 支持多种传输方式McpClientBuilder提供了三种接入方法后面每种方式都配一个完整的实战闭环传输方式连接对象适用场景streamableHttp远程 HTTP 服务云端 MCP 服务高德、GitHub 等首选sse远程 HTTP 服务旧协议只支持 SSE 的旧版 MCP Serverstdio本地子进程本地起进程的工具文件系统、本地脚本、npx 包选型上能用streamableHttp就用它这是 MCP 当前推荐的标准传输只有对接遗留服务才用sse工具必须跑在本机比如读写本地文件时才用stdio。2. Streamable HTTP 实战接入高德地图 MCP以高德地图为例走一遍完整的闭环连接、注册、调用、拿到结果。先看一下McpClientBuilder提供的常用方法后面三种传输方式都会用到方法说明create(String name)创建 buildername是客户端名称streamableHttpTransport(String url)Streamable HTTP 传输连接远程服务sseTransport(String url)SSE 传输连接旧版服务stdioTransport(String command, String...)stdio 传输第一个参数是可执行命令后面是启动参数header(String, String)/headers(Map)添加请求头用于鉴权queryParam(String, String)添加 URL 查询参数比如高德的keytimeout(Duration)请求超时时间initializationTimeout(Duration)初始化握手超时时间buildAsync()异步构建返回MonoMcpClientWrapperbuildSync()同步构建直接返回McpSyncClientWrapper2.1 第一步连接服务高德官方提供了 MCP 服务只需要一个 key。我们创建一个AMapMcp类来封装连接逻辑packagecom.maple.agent.demo.demo_05;importio.agentscope.core.tool.mcp.McpClientBuilder;importio.agentscope.core.tool.mcp.McpClientWrapper;publicclassAMapMcp{privatestaticStringamapUrlhttps://mcp.amap.com/mcp?key你的key;publicstaticMcpClientWrappergetAMapMcp(){McpClientBuilderbuilderMcpClientBuilder.create(amap-mcp).streamableHttpTransport(amapUrl);returnbuilder.buildAsync().block();}}短短几行就完成了创建 builder、指定 Streamable HTTP 传输、异步构建并阻塞等待连接建立这几步。key 直接拼在了 URL 上也可以拆出来用queryParam写更清晰一些McpClientBuilderbuilderMcpClientBuilder.create(http-server).streamableHttpTransport(https://mcp.amap.com/mcp).queryParam(key,你的key);key 属于敏感信息demo 里为了演示直接写在代码里实际项目建议放到环境变量不要提交到仓库。buildAsync()返回MonoMcpClientWrapperbuildSync()直接返回McpSyncClientWrapper。整个 AgentScope 的模型调用、事件流都建立在 Reactor 响应式流上建议统一用buildAsync()和框架保持一致同步包装器只在纯同步的简单场景下省事。2.2 第二步注册并调用连接建好了把它注册进Toolkit一行代码ToolkittoolkitnewToolkit();toolkit.registerMcpClient(AMapMcp.getAMapMcp()).block();registerMcpClient会拉取 Server 上的工具列表把每个工具包装成McpTool注册进 toolkit返回MonoVoid表示注册完成。之后 agent 构建完全复用上一章的代码publicstaticvoidmain(String[]args){PermissionContextStatepermCtxPermissionContextState.builder().mode(PermissionMode.BYPASS)// 跳过所有权限检查.build();ToolkittoolkitnewToolkit();toolkit.registerMcpClient(AMapMcp.getAMapMcp()).block();ReActAgentagentReActAgent.builder().name(笑小枫的地图助手).model(model).sysPrompt(你是笑小枫的地图助手可以帮助用户搜索具体的位置。).toolkit(toolkit).permissionContext(permCtx).build();agent.streamEvents(newUserMessage(user,从青岛到上海怎么去)).doOnNext(event-{if(eventinstanceofTextBlockDeltaEventdelta){System.out.print(delta.getDelta());}elseif(eventinstanceofToolCallStartEventtc){System.out.println(\n[tool] tc.getToolCallName());}elseif(eventinstanceofToolResultEndEventend){System.out.println([tool result stateend.getState()]);}}).blockLast();}有个点注意一下高德地图 MCP 需要权限确认这里为了方便直接用.mode(PermissionMode.BYPASS)跳过全部权限权限的事后面细聊。运行一下问它从青岛到上海怎么去从事件流里能看到模型连续调用了高德的多个工具完成路线规划我们没有写任何地图相关的代码agent 就拥有了地图能力。接入一个 MCP Server上面的所有工具就都能被 agent 调用。3. stdio 实战连接本地进程第二种闭环如果工具必须在本地运行比如读写本地文件、执行本地脚本就用stdio传输AgentScope 会帮你把子进程拉起来通过标准输入输出通信。3.1 第一步连接服务我们接入一个开源的 hello 演示包packagecom.maple.agent.demo.demo_05;importio.agentscope.core.tool.mcp.McpClientBuilder;importio.agentscope.core.tool.mcp.McpClientWrapper;publicclassHelloStdioMcp{publicstaticMcpClientWrapperhelloStdioMcp(){McpClientBuilderbuilderMcpClientBuilder.create(hello-mcp)// 使用 npx 自动下载并运行这个开源的 hello 演示包.stdioTransport(npx,-y,victox/hello-stdio,hello-mcp-server);returnbuilder.buildAsync().block();}}等价于在命令行执行npx -y victox/hello-stdio hello-mcp-server并把它当 MCP Server 用。第一个参数是命令后面全是启动参数环境变量用另一个重载stdioTransport(command, args, env)传入。3.2 第二步注册并调用注册方式和高德完全一样只是这次用DEFAULT模式 白名单规则只放行hello1这个工具PermissionContextStatepermCtxPermissionContextState.builder().mode(PermissionMode.DEFAULT).addAllowRule(hello1,newPermissionRule(hello1,// toolNamenull,// null 匹配该工具的所有调用PermissionBehavior.ALLOW,userSettings)).build();ToolkittoolkitnewToolkit();toolkit.registerMcpClient(HelloStdioMcp.helloStdioMcp()).block();ReActAgentagentReActAgent.builder().name(HelloStdio 演示).model(model).sysPrompt(你是一个友好的助手。).toolkit(toolkit).permissionContext(permCtx).build();agent.streamEvents(newUserMessage(user,hello)).doOnNext(event-{if(eventinstanceofTextBlockDeltaEventdelta){System.out.print(delta.getDelta());}elseif(eventinstanceofToolCallStartEventtc){System.out.println(\n[tool] tc.getToolCallName());}elseif(eventinstanceofToolResultEndEventend){System.out.println([tool result stateend.getState()]);}}).blockLast();这里展开说一下权限。上一章说过每次工具调用都要过checkPermissionsMCP 工具也一样。如果 agent 没有配置权限上下文MCP 工具调用可能被默认权限策略拦下来。高德的例子里我们为了省事直接 BYPASS但生产环境千万别这么做MCP 工具是外部能力擅自放行可能带来越权风险。DEFAULT模式 白名单的方式就稳妥得多模型调用hello1时直接放行调用其他未授权的工具则会被拦截。运行一下4. SSE连接旧版服务第三种传输就简单多了有些早期搭建的 MCP Server 只支持 SSE把传输方法换一下即可注册和调用的代码与前面完全一致McpClientWrappersseMcpMcpClientBuilder.create(sse-server).sseTransport(http://localhost:3000/sse).buildAsync().block();ToolkittoolkitnewToolkit();toolkit.registerMcpClient(sseMcp).block();三种传输方式过下来换传输方式只改一行 builder 配置后面的注册和调用流程完全复用这就是协议标准化的好处。5. 自定义MCP服务前面三节都是接别人发布好的 MCP Server这一节自己搭一个把公司的私有业务能力发布成标准 MCP 服务agent 就能像用高德一样用它们。用 Spring AI 的 MCP Server Starter整个过程只需要三步加依赖、写配置、打注解。5.1 第一步搭建 MCP Server新建一个普通的 Spring Boot 项目demo 用的是 Spring Boot 4.1.1 Spring AI 2.0.1引入 MCP Server 依赖dependencyManagementdependenciesdependencygroupIdorg.springframework.ai/groupIdartifactIdspring-ai-bom/artifactIdversion2.0.1/versiontypepom/typescopeimport/scope/dependency/dependencies/dependencyManagementdependenciesdependencygroupIdorg.springframework.ai/groupIdartifactIdspring-ai-starter-mcp-server-webmvc/artifactId/dependency/dependencies然后在application.properties里配置服务信息协议选 STREAMABLE端点设为/mcpserver.port8090 # MCP server (Streamable HTTP) spring.ai.mcp.server.protocolSTREAMABLE spring.ai.mcp.server.namemaple-mcp-demo spring.ai.mcp.server.version1.0.0 spring.ai.mcp.server.instructionsMaple MCP demo server, providing sample tools spring.ai.mcp.server.streamable-http.mcp-endpoint/mcp5.2 第二步定义工具McpTool 注解写一个Service类方法上加McpTool注解启动时注解扫描会自动把方法注册成 MCP 工具不用手写任何注册代码packagecom.maple.mcp.tool;importorg.springframework.ai.mcp.annotation.McpTool;importorg.springframework.ai.mcp.annotation.McpToolParam;importorg.springframework.stereotype.Service;importjava.time.LocalDateTime;importjava.time.format.DateTimeFormatter;ServicepublicclassDemoTools{privatestaticfinalDateTimeFormatterFORMATTERDateTimeFormatter.ofPattern(yyyy-MM-dd HH:mm:ss);McpTool(description获取两个整数的和)publicintadd(McpToolParam(description第一个加数,requiredtrue)inta,McpToolParam(description第二个加数,requiredtrue)intb){returnab;}McpTool(description获取服务器当前时间)publicStringcurrentTime(){returnLocalDateTime.now().format(FORMATTER);}}是不是很眼熟和上一章 AgentScope 的Tool注解几乎一个套路方法即工具McpToolParam描述参数注解自动生成 schema。区别只在于这里的工具暴露给了 MCP 协议任何 MCP 客户端都能用不局限于 AgentScope。启动项目后MCP 端点就是http://localhost:8090/mcp。可以先用 curl 握手验证一下服务活着没curl-s-XPOST http://localhost:8090/mcp\-HContent-Type: application/json-HAccept: application/json, text/event-stream\-d{jsonrpc:2.0,id:1,method:initialize,params:{protocolVersion:2025-11-25,capabilities:{},clientInfo:{name:curl,version:0}}}5.3 第三步AgentScope 客户端接入服务端就绪回到 agent 项目。连接代码和第 2 节的高德一模一样只是 URL 换成了本地服务packagecom.maple.agent.demo.demo_05;importio.agentscope.core.tool.mcp.McpClientBuilder;importio.agentscope.core.tool.mcp.McpClientWrapper;publicclassLocalMcp{publicstaticMcpClientWrapperlocalMcp(){McpClientBuilderbuilderMcpClientBuilder.create(local-mcp).streamableHttpTransport(http://localhost:8090/mcp);returnbuilder.buildAsync().block();}}注册和调用也完全复用前面的套路这次我们继续用DEFAULT模式 白名单只放行currentTimePermissionContextStatepermCtxPermissionContextState.builder().mode(PermissionMode.DEFAULT).addAllowRule(currentTime,newPermissionRule(currentTime,// toolNamenull,// null 匹配该工具的所有调用PermissionBehavior.ALLOW,userSettings)).build();ToolkittoolkitnewToolkit();toolkit.registerMcpClient(LocalMcp.localMcp()).block();ReActAgentagentReActAgent.builder().name(笑小枫 MCP 演示).model(model).sysPrompt(你是一个通用的助手。).toolkit(toolkit).permissionContext(permCtx).build();agent.streamEvents(newUserMessage(user,当前的时间是多少)).doOnNext(event-{if(eventinstanceofTextBlockDeltaEventdelta){System.out.print(delta.getDelta());}elseif(eventinstanceofToolCallStartEventtc){System.out.println(\n[tool] tc.getToolCallName());}elseif(eventinstanceofToolResultEndEventend){System.out.println([tool result stateend.getState()]);}}).blockLast();运行一下问它当前的时间是多少事件流里可以看到模型调用了currentTime工具返回的就是 MCP Server 那台机器的时间。到这里一个完整的自建闭环就跑通了Spring AI 三步发布服务AgentScope 一行接入。这个模式把工具实现方和 agent 开发方解耦双方不用关心对方的代码只通过 MCP 协议约定 schema。6. 进阶MCP 工具的更多细节6.1 MCP 工具在框架里的样子McpTool继承自ToolBase所以它天然具备上一章讲的全部属性isMcp()返回truegetMcpName()返回所属 MCP 客户端名参数 schema 由 Server 提供的 JSON Schema 直接转换。对ReActAgent来说它和Tool注解定义的本地工具没有任何区别可以混着注册ToolkittoolkitnewToolkit();toolkit.registerTool(newDemoTool());// 本地工具toolkit.registerTool(newSearchWeatherTool());// ToolBase 子类toolkit.registerMcpClient(AMapMcp.getAMapMcp()).block();// MCP 工具6.2 调试利器绕过模型直接调 MCP写代码前想先确认这个 MCP Server 到底有哪些工具、参数长什么样可以直接用McpClientWrapper不经过 agent 和模型McpClientWrapperamapAMapMcp.getAMapMcp();amap.initialize().block();// 列出所有工具amap.listTools().block().forEach(tool-System.out.println(tool.name() : tool.description()));// 直接调用某个工具amap.callTool(maps_weather,Map.of(city,上海)).block().forEach(content-System.out.println(content));先用listTools()把工具清单打出来看一眼再决定给 agent 配什么 system prompt比盲调高效得多。callTool的第一个参数是工具名第二个是参数 Map。本章小结最后回顾一下本文的核心内容构件有三个McpClientBuilder负责建连McpClientWrapper持有连接McpTool把远程工具适配成普通的ToolBase。传输有三种远程服务首选streamableHttp旧服务用sse本地进程用stdio每种都配了一个完整闭环的实战。注册只要一行toolkit.registerMcpClient(wrapper).block()之后 agent 的用法与本地工具完全一致换传输方式只改一行 builder 配置。调试技巧接入前先用listTools()看清单、用callTool()直调验证确认无误再交给 agent。进阶玩法用 Spring AI 的McpTool注解三步自建 MCP Server把私有业务能力发布成标准服务AgentScope 一行接入。安全底线学习可以 BYPASS 权限生产用DEFAULT模式 白名单规则key 永远不进代码仓库。自己写 Tool 是造轮子接 MCP 是用轮子。这两章下来agent 既能封装私有业务逻辑也能接入生态里的公开能力工具接入这块就齐了。本系列源码https://gitee.com/hack-feng/maple-agent-demo
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑