首页 / 资讯中心 / 文章详情

Yao Agent MCP 集成实战:为智能助手接入外部工具、资源与跨服务器并发调用

Yao Agent MCP 集成实战:为智能助手接入外部工具、资源与跨服务器并发调用 ★ FEATURED ARTICLE
Agent 框架后端低代码RAG【免费下载链接】yao✨ All your agents and workspaces in one place, on every device you own. Track tasks on a board, accessible from desktop, mobile, browser, or API. Self-hosted.项目地址https://gitcode.com/gh_mirrors/ya/yao点击查看免费下载Model Context ProtocolMCP是连接大语言模型与外部服务/工具的标准协议。本指南聚焦于 Yao 仓库中agent/模块的 MCP 集成能力讲解如何在助手Assistant中定义 MCP 服务器、通过package.yao与 Hook 启用工具、调用工具与资源以及利用All/Any/Race实现跨服务器并发编排。读完本文你将掌握一套完整的、可直接落地的 MCP 接入方案并理解其底层实现原理。1. 目录结构与命名空间约定在 Yao Agent 中每个助手Assistant可以在自身的mcps/目录下定义独立的 MCP 服务器并自动以agents.assistant-id.前缀加载。标准目录结构如下assistants/ └── my-assistant/ ├── package.yao └── mcps/ ├── tools.mcp.yao # → agents.my-assistant.tools ├── calculator.mcp.yao # → agents.my-assistant.calculator └── mapping/ └── tools/ └── schemes/ ├── search.in.yao └── search.out.yaotools.mcp.yao文件会被注册为agents.my-assistant.tools这一 MCP 服务器 IDmapping/目录用于存放工具输入/输出 Schema 映射文件详见第 6 节一个助手可以同时拥有多个 MCP 服务器文件tools、calculator等相互之间命名空间隔离。在源码层面配置解析位于 agent/assistant/load.go约第 763-769 行package.yao中的mcp字段会被转换为store.MCPServers结构并挂载到 Assistant 上。2. 定义 MCP 服务器与四种传输方式在助手目录中创建mcps/tools.mcp.yao即可定义一个 MCP 服务器。最基础的形式如下{ label: Tools, description: Custom tools for the assistant, transport: process, tools: { search: scripts.tools.Search, create: models.data.Create } }其中tools是「工具名 → Yao Process」的映射。MCP 支持四种transport类型分别面向不同的外部服务接入场景2.1 ProcessYao 内部进程将 Yao Process 直接映射为 MCP 工具无需启动外部进程{ transport: process, tools: { search: models.data.Paginate, create: models.data.Create }, resources: { detail: models.data.Find } }resources字段将 MCP 资源resource映射到 Process供ReadResource调用。这是与 Yao 自身能力模型、脚本集成最紧密的传输方式。2.2 STDIO本地子进程启动本地命令与 MCP 服务器通信适合 Python/Node 等语言编写的 MCP Server{ transport: stdio, command: python, arguments: [mcp_server.py], env: { API_KEY: $ENV.API_KEY } }env支持$ENV.XXX占位符语法可从运行环境注入密钥避免明文写入配置文件。2.3 HTTPREST API对接部署在远程的 MCP HTTP 端点{ transport: http, url: https://mcp.example.com/api, authorization_token: $ENV.TOKEN }2.4 SSEServer-Sent Events对接基于 SSE 推送的 MCP 服务{ transport: sse, url: https://mcp.example.com/events, authorization_token: $ENV.TOKEN }说明以上authorization_token同样支持$ENV.占位符注入适合存放 API Key、Token 等敏感凭据。3. 在 package.yao 中启用 MCP 服务器定义好mcps/*.mcp.yao后还需要在package.yao的mcp.servers中声明启用哪些服务器有三种形态3.1 启用全部工具{ mcp: { servers: [tools] } }3.2 只启用指定工具{ mcp: { servers: [{ server_id: tools, tools: [search, calculate] }] } }3.3 同时启用工具与资源{ mcp: { servers: [ { server_id: data, tools: [query], resources: [data://users/*] } ] } }resources使用 MCP URI 通配符如data://users/*指定允许读取的资源范围未列出的资源在 Hook 中调用ReadResource时会被拦截。3.4 多格式解析原理从源码看MCPServerConfig的反序列化支持四种输入格式见 agent/store/types/types.go 第 298-357 行的UnmarshalJSON纯字符串server_id标准对象{server_id: server1, resources: [...], tools: [...]}工具数组对象{server_id: [tool1, tool2]}完整配置对象{server_id: {resources: [...], tools: [...]}}反序列化时依次尝试「字符串 → 标准对象 → 单键对象」因此第 3.1 节的简写[tools]与 3.2/3.3 节的对象写法在语义上等价可混用。对应的解析器store.ToMCPServers由 agent/assistant/load.go 在加载package.yao时调用。4. 在 Hook 中动态配置 MCP 服务器除了静态配置还可以在 Hook 的Create阶段按消息内容动态决定启用哪些 MCP 服务器。返回字段mcp_servers会在本次对话周期内生效function Create(ctx: agent.Context, messages: agent.Message[]): agent.Create { return { messages, mcp_servers: [ { server_id: tools, tools: [search] }, { server_id: data, resources: [data://reports] }, ], }; }动态配置与静态配置的优先级关系在 agent/assistant/mcp.go 的buildMCPTools方法第 75-96 行中有明确实现Hook 返回的mcp_servers优先只要Create响应携带了 MCP 服务器配置就完全覆盖override静态配置否则回退到package.yao中配置的ast.MCP.Servers两者都没有时跳过 MCP 工具构建。这为「根据用户问题智能启用工具」提供了标准入口例如仅在检测到数学表达式时才加载计算器工具。5. 在 Hook 中调用 MCP工具、资源与提示词Hook 通过ctx.mcp访问 MCP 客户端能力。所有方法在 agent/context/jsapi_mcp.go 中注册底层实现在 agent/context/mcp.go。5.1 列出可用工具const tools ctx.mcp.ListTools(server-id); // { tools: [{ name: search, description: ..., inputSchema: {...} }] }ListTools支持可选的游标参数cursor用于分页遍历大型工具集见mcpListToolsMethod位于 agent/context/jsapi_mcp.go 第 78-105 行。5.2 调用单个工具// Returns parsed result directly - no wrapper object const result ctx.mcp.CallTool(server-id, search, { query: example, limit: 10, }); console.log(result.items); // Direct access to parsed data关键行为CallTool返回的是解析后的结果本身而非 MCP 响应包装对象。底层parseToolResponseContentagent/context/mcp.go 第 788-833 行按内容类型处理text类型先尝试按 JSON 解析解析失败则原样返回字符串image类型返回{ type: image, data, mimeType }resource类型直接返回 Resource 对象若内容仅一项则直接返回该项多项则返回数组。5.3 批量调用工具顺序批量按顺序逐个执行// Sequential - returns array of parsed results const results ctx.mcp.CallTools(server-id, [ { name: step1, arguments: { input: a } }, { name: step2, arguments: { input: b } }, ]); results.forEach(r console.log(r));并行批量同一服务器内的工具并发执行// Parallel - returns array of parsed results const results ctx.mcp.CallToolsParallel(server-id, [ { name: api1, arguments: {} }, { name: api2, arguments: {} }, ]); results.forEach(r console.log(r));5.4 读取资源const resources ctx.mcp.ListResources(server-id); const data ctx.mcp.ReadResource(server-id, data://users/123);5.5 获取提示词const prompts ctx.mcp.ListPrompts(server-id); const prompt ctx.mcp.GetPrompt(server-id, system, { role: helper });5.6 跨服务器并发调用All / Any / Race当需要同时编排多个 MCP 服务器上的工具时ctx.mcp提供了三个 Promise 语义的并发原语实现见 agent/context/mcp.go 第 625-760 行// Wait for all (like Promise.all) const results ctx.mcp.All([ { mcp: server1, tool: search, arguments: { q: query } }, { mcp: server2, tool: analyze, arguments: { data: input } } ]); // First success (like Promise.any) - good for fallback const results ctx.mcp.Any([ { mcp: primary, tool: fetch, arguments: { id: 1 } }, { mcp: backup, tool: fetch, arguments: { id: 1 } } ]); // First complete (like Promise.race) - good for latency const results ctx.mcp.Race([ { mcp: region-us, tool: ping, arguments: {} }, { mcp: region-eu, tool: ping, arguments: {} } ]); // Access results results.forEach(r { if (r.error) { console.log(${r.mcp}/${r.tool} failed: ${r.error}); } else { console.log(${r.mcp}/${r.tool} result:, r.result); } });各方法的语义差异值得注意All等待所有请求完成按请求顺序返回结果CallToolAll用 channel 收集后按索引归位Any一旦出现任一成功即返回适合主备切换、容灾回退底层用缓冲 channel 收集找到首个成功即停止等待其余结果在后台排空Race返回第一个完成无论成功失败的结果适合多地域择优、追求低延迟。每个请求对象包含mcp服务器 ID、tool工具名、arguments可选参数其中mcp与tool为必填校验见 agent/context/jsapi_mcp.go 的parseMCPToolRequests。结果对象统一为{ mcp, tool, result?, error? }成功时result为解析后的数据失败时error携带错误信息。6. 工具 Schema 映射x-process-args对于process传输方式MCP 参数需要映射到 Yao Process 的参数。在mcps/mapping/server-id/schemes/下按工具名放置*.in.yao输入 Schema与可选的*.out.yao输出 Schemamcps/ └── mapping/ └── server-id/ └── schemes/ ├── search.in.yao # Input schema └── search.out.yao # Output schema (optional)mapping/tools/schemes/search.in.yao{ type: object, description: Search data, properties: { keyword: { type: string }, page: { type: integer } }, x-process-args: [:arguments] }x-process-args声明 MCP 参数到 Yao Process 参数的映射方式支持两种取值:arguments将整个参数对象原样传给 Process$args.field从参数对象中提取指定字段如$args.keyword再传给 Process。6.1 嵌套对象 Schema当工具需要结构化输入时可以使用完整的 JSON Schema 定义{ type: object, description: Extract structured data from input, properties: { intent: { type: string, enum: [query, create, update], description: Operation intent }, items: { type: array, items: { type: object, properties: { name: { type: string }, value: { type: number } }, required: [name, value] } } }, required: [intent], x-process-args: [:arguments] }该 Schema 会在工具调用前被用作参数校验依据从源码看执行路径会先用gouJson.Parse解析 LLM 生成的参数再用gouJson.Validate与工具的InputSchema比对见 agent/assistant/mcp.go 第 344-357 行。校验失败会被标记为可重试错误交由 LLM 修正参数后重试。7. 使用助手自有模型作为 MCP 工具MCP 工具可以引用助手自身的模型把领域模型操作暴露为标准化工具。例如mcps/data.mcp.yao{ label: Data Tools, transport: process, tools: { list_orders: models.agents.my-assistant.order.Paginate, get_order: models.agents.my-assistant.order.Find, create_order: models.agents.my-assistant.order.Create, custom_query: agents.my-assistant.orders.Query } }注意这里 Process 的完整路径为models.agents.my-assistant.order.*——即助手命名空间下的模型与第 1 节的agents.assistant-id.前缀约定一致。自定义脚本如agents.my-assistant.orders.Query同样可以暴露为 MCP 工具。助手模型的定义方式参见 Models 文档。8. 错误处理与可重试机制在NextHook 中处理工具执行结果时需要区分工具级错误并决定是否交给 LLM 修复function Next(ctx: agent.Context, payload: agent.Payload): agent.Next { const { tools } payload; if (tools) { for (const tool of tools) { if (tool.error) { ctx.trace.Error(Tool ${tool.tool} failed: ${tool.error}); // Handle error } else { // Process result console.log(tool.result); } } } return null; }源码层的容错设计更细致。在 agent/assistant/mcp.go 中executeToolCalls第 223-237 行采用智能执行策略单工具走CallTool多工具先尝试并行CallToolsParallel遇到参数类错误再降级为顺序执行shouldRetrySequential第 538-548 行isRetryableToolError第 484-535 行通过错误文本模式区分两类错误不可重试MCP 内部问题LLM 无法修复network、timeout、connection、unauthorized、forbidden、unavailable、context canceled、server error等可重试参数/校验问题LLM 可修正invalid、required、missing、validation、schema、parse、argument等未匹配任何模式时默认按可重试处理给 LLM 修复机会。ToolCallResult携带IsRetryableError标记见 agent/assistant/types.go 第 50-58 行供上层决定是否让 LLM 重新尝试。此外每条工具调用都会写入 trace成功调用记录在trace.Add节点上标记为mcp_tool类型并Complete失败则Fail见 agent/assistant/mcp.go 第 294-311 行便于排查与复盘。9. 完整示例一个带计算器工具的数学助手下面是一个端到端的完整示例展示了「定义服务器 → 静态/动态启用 → Hook 调用与结果处理」的完整链路。mcps/calculator.mcp.yao{ label: Calculator, description: Math operations, transport: process, tools: { add: scripts.math.Add, multiply: scripts.math.Multiply } }package.yao{ name: Math Assistant, connector: gpt-4o, mcp: { servers: [{ server_id: calculator, tools: [add, multiply] }] } }src/index.tsfunction Create(ctx: agent.Context, messages: agent.Message[]): agent.Create { // Check if calculation is needed const query messages[messages.length - 1]?.content || ; if (/\d\s*[\\-\*\/]\s*\d/.test(query)) { // Enable calculator return { messages, mcp_servers: [{ server_id: calculator }], }; } return { messages }; } function Next(ctx: agent.Context, payload: agent.Payload): agent.Next { const { tools } payload; if (tools?.length 0) { const calcResult tools.find((t) t.server calculator); if (calcResult?.result) { return { data: { answer: calcResult.result, expression: calcResult.arguments, }, }; } } return null; }这个示例演示了两个关键设计模式按需启用CreateHook 用正则检测用户输入中是否含四则运算表达式只有命中时才在mcp_servers中加载计算器避免无关请求浪费上下文结果提取NextHook 从tools数组中按server calculator定位结果将其包装进返回的data。10. 工具命名规范与数量上限源码细节使用 MCP 时有两个容易踩坑的实现细节值得了解见 agent/assistant/mcp.go 第 17-71 行命名规范暴露给 LLM 的工具名格式为server_id__tool_name双下划线分隔server_id中的点号会被替换为单下划线。例如github.enterprise服务器上的search工具最终名为github_enterprise__search。反向解析ParseMCPToolName在工具调用时负责还原服务器 ID。由于该格式约定server_id不能包含下划线仅允许点、字母、数字、连字符数量上限单次对话中加载的 MCP 工具总数上限为MaxMCPTools 20agent/assistant/mcp.go 第 19 行超过时按服务器配置顺序截断并记录 warning避免工具定义过多导致 LLM 上下文超限。如果服务器声明了tools过滤列表如[search]buildMCPTools会先通过ListTools拉取全部工具再按白名单过滤最终只把命中的工具转换为MCPToolName/Description/Parameters见 agent/assistant/types.go 第 42-46 行注入请求。另外如果 MCP 服务器提供了工具使用样例Samples构建工具时会自动把每个工具最多 3 条样例组织为「MCP Tool Usage Examples」段落拼入系统提示词帮助 LLM 更准确地调用工具见 agent/assistant/mcp.go 第 161-203 行。相关行为在 agent/assistant/mcp_integration_test.go 中有集成测试覆盖。11. 总结Yao Agent 的 MCP 集成提供了从「声明式服务器定义」到「Hook 内程序化调用」的完整能力矩阵接入面process、stdio、http、sse四种传输方式覆盖内部 Process、本地子进程与远程服务三类场景配置面package.yao静态配置支持字符串/对象多形态写法HookCreate返回mcp_servers可实现按需动态启用调用面ctx.mcp提供工具单个/顺序批量/并行批量、资源、提示词三类操作All/Any/Race将跨服务器并发编排与主备容灾变成几行代码健壮性参数 Schema 校验、可重试错误分类、并行失败降级顺序执行与全链路 trace 共同保障了生产可用性。接入新工具时推荐遵循「先建mcps/*.mcp.yao定义服务器再在package.yao或 Hook 中声明启用最后在 Hook 中调用与处理结果」的三步流程并可对照第 9 节完整示例快速起步。赞分享Agent 框架后端低代码RAG【免费下载链接】yao✨ All your agents and workspaces in one place, on every device you own. Track tasks on a board, accessible from desktop, mobile, browser, or API. Self-hosted.项目地址https://gitcode.com/gh_mirrors/ya/yao点击查看免费下载相关推荐VoltAgent MCP 集成实战接入外部 MCP 服务器与将 Agent 暴露为 MCP 服务VoltAgent MCP 集成实战接入外部 MCP 服务器与将 Agent 暴露为 MCP 服务 本文基于 VoltAgent 官方配方 website/r人工智能AI AgentAgent 框架后端多智能体RAG工具调用Agent 记忆Agent 工作流AI 评测MCP 服务MCP Clients语音Agent Zero MCP 接入实战指南为 AI 框架桥接外部工具与服务Agent Zero MCP 接入实战指南为 AI 框架桥接外部工具与服务 Agent Zero 是一个通用的 AI 智能体框架而 MCPModel Co人工智能大模型AI AgentAgent 框架自主智能体多智能体工具调用MCP 服务浏览器控制Hive Agent Builder MCP 工具集成指南为 Agent 注册外部 MCP 服务器并自动生成配置Hive Agent Builder MCP 工具集成指南为 Agent 注册外部 MCP 服务器并自动生成配置 本指南围绕 Hive Core Framew人工智能AI Agent多智能体MCP 服务工具调用浏览器控制上一篇如何开发Day.js插件从零开始构建自定义日期功能扩展下一篇Forge中的自动化测试生成和执行测试用例的LLM工作流创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
阅读完成 · 觉得有帮助?
咨询建站