The `process` transport is the simplest way to build MCP tools in Yao. Instead of running a separate server, you map tool names directly to Yao Process names in a `.mcp.yao` file.
## File Layout
```
assistants/myns/myagent/
├── package.yao
├── mcps/
│ ├── store.mcp.yao ← MCP server definition
│ └── mapping/
│ └── store/
│ └── schemes/
│ ├── save_record.in.yao ← input schema for save_record tool
│ ├── get_record.in.yao
│ └── search_records.in.yao
```
## The `.mcp.yao` File
```json
{
"label": "My Agent Store",
"description": "Record storage, retrieval, and search tools",
"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"
}
}
```
Each key in `tools` is the **tool name** the LLM uses when calling the tool. The value is the **Yao Process** that handles the call.
### Fields
| Field | Description |
|-------|-------------|
| `label` | Human-readable server name |
| `description` | Server description (shown in agent UIs) |
| `transport` | `"process"` for Yao Process transport |
| `capabilities.tools.listChanged` | Set `false` unless you dynamically change the tool list |
| `tools` | Map of `tool_name → process_name` |
## Input Schemas
Each tool needs an input schema so the LLM knows what arguments to pass. Create a `.in.yao` file (JSON Schema) at:
```
mcps/mapping/<server-name>/schemes/<tool-name>.in.yao
```
The `<server-name>` is derived from the `.mcp.yao` filename: `store.mcp.yao` → `store`.
**Example: `schemes/save_record.in.yao`**
```json
{
"type": "object",
"description": "Create or update a record.",
"properties": {
"title": {
"type": "string",
"description": "Record title"
},
"content": {
"type": "string",
"description": "Record content"
},
"status": {
"type": "string",
"description": "Record status",
"enum": ["active", "archived"]
}
},
"required": ["title", "content"],
"x-process-args": [":arguments"]
}
```
### `x-process-args`
This field controls how the tool's arguments are passed to the Yao Process:
| Value | Behavior |
|-------|----------|
| `[":arguments"]` | Pass the entire tool call argument object as a single parameter |
| `["$args.title", "$args.content"]` | Extract specific fields and pass them as positional arguments |
Most MCP adapter functions use `[":arguments"]` — the function receives one object containing all the fields the LLM provided.
## Register in `package.yao`
Add the MCP server to the agent's `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"]
}
]
}
}
```
The `server_id` is the dot-path derived from the `.mcp.yao` file location:
- `assistants/myns/myagent/mcps/store.mcp.yao` → `agents.myns.myagent.store`
`tools` limits which tools from this server the LLM can call. Omit the field to allow all tools.
## How It Works End-to-End
```
LLM decides to call "save_record" with { title: "...", content: "..." }
│
▼
Yao reads mcps/store.mcp.yao
→ tool "save_record" maps to process "agents.myns.myagent.logic.MCPSave"
│
▼
Yao reads mcps/mapping/store/schemes/save_record.in.yao
→ x-process-args: [":arguments"]
→ passes the full argument object to MCPSave({ title, content, ... })
│
▼
MCPSave() in src/logic.ts:
1. validates required fields
2. calls Authorized() to get team_id (LLM did not provide this)
3. calls Save(teamId, data) → saves to database
4. returns result to LLM
```
## Multiple MCP Servers
An agent can have multiple `.mcp.yao` files — one per functional group:
```
mcps/
├── tools.mcp.yao ← planning / orchestration tools
├── store.mcp.yao ← data CRUD tools
└── webfetch.mcp.yao ← web fetch tools
```
You can register all servers statically in `package.yao`, or have the Create Hook add them dynamically:
```typescript
// src/index.ts
export function Create(ctx, messages) {
// dynamically select MCP servers based on runtime context
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 };
}
```
The `mcp_servers` field in the Create Hook response overrides the static `mcp.servers` in `package.yao`.
## What's Next
With data and tools in place, add a sidebar UI:
- **[SUI Pages →](./pages)**