`process` transport 是在 Yao 中构建 MCP 工具的最简方式。无需运行独立服务器,只需在 `.mcp.yao` 文件中将工具名直接映射到 Yao Process 名称即可。
## 文件结构
```
assistants/myns/myagent/
├── package.yao
├── mcps/
│ ├── store.mcp.yao ← MCP 服务定义
│ └── mapping/
│ └── store/
│ └── schemes/
│ ├── save_record.in.yao ← save_record 工具的输入 Schema
│ ├── get_record.in.yao
│ └── search_records.in.yao
```
## `.mcp.yao` 文件
```json
{
"label": "My Agent Store",
"description": "记录的存储、检索和搜索工具",
"transport": "process",
"capabilities": { "tools": { "listChanged": false } },
"tools": {
"save_record": "agents.myns.myagent.logic.MCPSave",
"get_record": "agents.myns.myagent.logic.MCPGet",
"search_records": "agents.myns.myagent.logic.MCPSearch",
"delete_record": "agents.myns.myagent.logic.MCPDelete"
}
}
```
`tools` 中每个键是 LLM 调用工具时使用的**工具名**,值是处理该调用的 **Yao Process**。
### 字段说明
| 字段 | 说明 |
|------|------|
| `label` | 可读的服务名称 |
| `description` | 服务描述(在 Agent UI 中展示) |
| `transport` | `"process"` 表示 Yao Process transport |
| `capabilities.tools.listChanged` | 除非动态变更工具列表,否则设为 `false` |
| `tools` | `工具名 → Process 名称` 的映射 |
## 输入 Schema
每个工具需要一个输入 Schema,让 LLM 知道该传什么参数。在以下路径创建 `.in.yao` 文件(JSON Schema):
```
mcps/mapping/<server-name>/schemes/<tool-name>.in.yao
```
`<server-name>` 从 `.mcp.yao` 文件名推导:`store.mcp.yao` → `store`。
**示例:`schemes/save_record.in.yao`**
```json
{
"type": "object",
"description": "创建或更新一条记录。",
"properties": {
"title": {
"type": "string",
"description": "记录标题"
},
"content": {
"type": "string",
"description": "记录内容"
},
"status": {
"type": "string",
"description": "记录状态",
"enum": ["active", "archived"]
}
},
"required": ["title", "content"],
"x-process-args": [":arguments"]
}
```
### `x-process-args`
该字段控制工具参数如何传递给 Yao Process:
| 值 | 行为 |
|----|------|
| `[":arguments"]` | 将整个工具调用参数对象作为单个参数传入 |
| `["$args.title", "$args.content"]` | 提取指定字段,作为位置参数依次传入 |
大多数 MCP 适配函数使用 `[":arguments"]`——函数接收一个包含 LLM 提供的所有字段的对象。
## 在 `package.yao` 中注册
将 MCP 服务添加到 Agent 的 `package.yao`:
```json
{
"name": "My Agent",
"connector": "$ENV.DEFAULT_CONNECTOR",
"mcp": {
"servers": [
{
"server_id": "agents.myns.myagent.store",
"tools": ["save_record", "get_record", "search_records", "delete_record"]
}
]
}
}
```
`server_id` 从 `.mcp.yao` 文件位置推导:
- `assistants/myns/myagent/mcps/store.mcp.yao` → `agents.myns.myagent.store`
`tools` 限制 LLM 可调用该服务中的哪些工具。省略此字段则允许所有工具。
## 端到端流程
```
LLM 决定调用 "save_record",参数为 { title: "...", content: "..." }
│
▼
Yao 读取 mcps/store.mcp.yao
→ 工具 "save_record" 映射到 Process "agents.myns.myagent.logic.MCPSave"
│
▼
Yao 读取 mcps/mapping/store/schemes/save_record.in.yao
→ x-process-args: [":arguments"]
→ 将完整参数对象传给 MCPSave({ title, content, ... })
│
▼
src/logic.ts 中的 MCPSave():
1. 校验必填字段
2. 调用 Authorized() 获取 team_id(LLM 未提供)
3. 调用 Save(teamId, data) → 保存到数据库
4. 返回结果给 LLM
```
## 多个 MCP 服务
一个 Agent 可以有多个 `.mcp.yao` 文件——每个功能组一个:
```
mcps/
├── tools.mcp.yao ← 规划/编排工具
├── store.mcp.yao ← 数据 CRUD 工具
└── webfetch.mcp.yao ← 网页抓取工具
```
可以在 `package.yao` 中静态注册所有服务,也可以在 Create Hook 中动态添加:
```typescript
// src/index.ts
export function Create(ctx, messages) {
// 根据运行时上下文动态选择 MCP 服务
const servers = [{ server_id: "agents.myns.myagent.store" }];
if (ctx.config?.webfetch_enabled) {
servers.push({ server_id: "agents.myns.myagent.webfetch" });
}
return { messages, mcp_servers: servers };
}
```
Create Hook 响应中的 `mcp_servers` 字段会覆盖 `package.yao` 中静态配置的 `mcp.servers`。
## 下一步
数据和工具都就绪后,添加侧边栏 UI:
- **[SUI 页面 →](./pages)**