- 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.
Model Context Protocol(MCP)是连接大语言模型与外部服务/工具的标准协议。本指南聚焦于 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 服务器 ID;mapping/目录用于存放工具输入/输出 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 Process(Yao 内部进程)
将 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 HTTP(REST API)
对接部署在远程的 MCP HTTP 端点:
{ "transport": "http", "url": "https://mcp.example.com/api", "authorization_token": "$ENV.TOKEN" }2.4 SSE(Server-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 响应包装对象。底层parseToolResponseContent(agent/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(输出 Schema):
mcps/ └── 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 修复机会。
- 不可重试(MCP 内部问题,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.ts
function 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 = 20(agent/assistant/mcp.go 第 19 行),超过时按服务器配置顺序截断并记录 warning,避免工具定义过多导致 LLM 上下文超限。
如果服务器声明了tools过滤列表(如["search"]),buildMCPTools会先通过ListTools拉取全部工具,再按白名单过滤,最终只把命中的工具转换为MCPTool(Name/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.
相关推荐
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 智能体框架,而 MCP(Model Co
人工智能大模型AI AgentAgent 框架自主智能体多智能体工具调用MCP 服务浏览器控制Hive Agent Builder MCP 工具集成指南:为 Agent 注册外部 MCP 服务器并自动生成配置
Hive Agent Builder MCP 工具集成指南:为 Agent 注册外部 MCP 服务器并自动生成配置 本指南围绕 Hive Core Framew
人工智能AI Agent多智能体MCP 服务工具调用浏览器控制
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考