内容
">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="assets/whistle-dark.svg">
<img src="assets/whistle-light.svg" alt="Ocarina" width=" </picture>
h1>Ocarina</h1>
<p><CP 服务器自动化框架。</strong> 编写 YAML 脚本性地重放它,不需要 LLM。</p>
<a href="https://github.com/msradam/blender-mcp-ocarina">
<img src="assets/blender-demo.gif" alt="Ocarina 在 Blender 中构建 3D 场景,一步一步" width="100%">
</a>
<p><sub>驱动 <a href="https://github.com/ahujasid/blender-mcp">blender-mcp</a>:放置一个平面,放置体,堆叠一个,添加一个圆锥,然后验证场景。相同的 YAML,相同的结果,每次运行。无需模型。克隆 <a href="https://github.com/msradam/blender-mcp-ocarina">blender-mcp-ocarina</a> 以自行运行。</sub></p>
</div>
MCP 生态系统已经非常庞大:数千个服务器通过类型化的工具、可读的资源和的合约公开提供真实服务,并且已经部署好,可以调用carina 是一个适用于所有这些服务器的自动化框架。编写一个 YAML 脚本,驱动一个或多个服务器上的工具,在步骤之间,分支,循环和重试,并且每次运行方式都相同 LLM,因此每次运行都是可重复的,并且无需花费。
这些工具的设计初衷是让语言模型能够读取,而语言模型是基于人类语言训练的,因此这些工具对人类来说也很容易阅读。服务器公开诸如 `get_issues` 或 `query_database类的命名合约,而不是您在代码中连接的端点。任何人构建的 AI 助手服务器都是您可以驱动的服务器。
您编写的是一个剧本(playbook):一个便携式工件,用于捕获跨服务器的自动化工作流,MCP 作为线协议。您可以阅读它,在拉取请求中审查它,对其进行版本控制,并在服务器可达的任何地方运行它。您可以手动编写它,也可以让代理生成它。无论哪种方式,它在每次执行时都运行相同,无需采样,无需令牌,也无需在文件和结果之间进行推断。
## 安装
```bash
go install github.com/msradam/ocarina@latest
```
二进制文件可在 [发布页面](https://github.com/msradam/ocarina/releases) 上找到。从源代码构建需要 Go 1.26+。
## 使用
为服务器生成 Markdown 文档:
```bash
ocarina docs uvx mcp-server-sqlite --db-path mydb.sqlite
ocarina docs npx -y @modelcontextprotocol/server-github > docs/github.md
```
运行一个剧本(rondo):
```bash
ocarina play db-audit.yaml
ocarina play db-audit.yaml --dry-run
ocarina play db-audit.yaml -e db=/tmp/other.sqlite # 在运行时重写一个键
```
在不运行任何工具的情况下,验证剧本是否符合实时服务器的要求:
```bash
ocarina validate db-audit.yaml
```
## 设计原则
- **确定性**。相同的剧本每次运行都会产生相同的结果。无需采样,无需随机性。
- **协议原生**。通过 `tools/call`、`resources/read `resources/list` 直接与 MCP 通信。与任何符合协议的服务器一起工作。
- **断言是一等公民**。如果任何 `expect:` 检查失败,则 `play` 以非零退出。剧本开箱即用,可作为 CI 健康检查 **脚本中不包含凭证**。服务器连接和环境变量保留在剧本文件之外。
- **一个剧本,任意机器**。如果 MCP 服务器可用,则剧本就会运行。
## 剧本格式
剧本是一个 YAML 文件,包含三个部分。
```yaml
keys:
owner: acme
repo: api
server:
command: npx
args: [-y, "@modelcontextprotocol/server-github"]
rondo:
- name: recent commits
tool: list_commits
args:
owner: "{{owner}}"
repo: "{{repo}}"
grab: ".0.sha"
echo: latest_sha
- name: commit detail
tool: get_commit
args:
owner: "{{owner}}"
"{{repo}}"
sha: "{{latest_sha}}"
expect:
contains: "feat 步骤字段
| 字段 | 描述 |
|---|---|
| ` | 运行此步骤的服务器(`servers图中的一个键);默认为唯一/第一个服务器 |
| `tool` | 要调用的工具名称 |
| `resource` | 要读取的资源 URI (`resources/read`) |
| `list_resources` | 要列出的资源的前缀;输出为 JSON URI 数组 |
| `args` | 工具参数。`{{key}}` 从 `keys` 或之前的 `echo` 捕获中插入 |
| `echo` | 在后续步骤中使用此步骤的输出键 |
| `grab JSON 输出的点路径,在存储之前:`.0、`.name`、`.items.0.id` |
| `loop` | 将 JSON 数组键扩展为重复迭代设置 `{{item}}` |
| `expect.contains` | 断言输出包含 |
| `expect.matches`断言输出与表达式匹配 |
|.equals` | 断言输出字符串(修剪空格) |
| `expect.is | 断言工具 `isError: |
| `ignore_errors 继续执行而不是停止 |
tags` | 为 `-- / `--skip-tags筛选标记此步骤{{env.NAME}}` 从进程环境中解析,并且 `{{key}}` 处都有效。
来自 Ansible?:` 被接受为ondo:` 的别名,而:` 被接受为 `echo:` 的别名。
## 多个服务器
单个剧本可以与多个服务器通信。在 `servers:` 下声明它们,并在每个步骤上设置 `server:`。省略 `server:`使用第一个条目。
servers:
time: {command: uvx: [mcp-server fetch: {command, args:, "@modelcontextprotocol"]}
rondo:
: get time
server: time
get_current_time
: {timezone: UTC}
name: fetch page
server: fetch
fetch
args: {url: "https://example.com"}
```
输出和 `diff` 命名空间工具名称按服务器(`time.get_current_time`)。单个 `server:` 块仍然适用于单服务器剧本。
## 远程服务器
给服务器一个 `url:` 而不是 `command:`,使用 Streamable HTTP 传输代替本地子进程。每个请求都发送头部,因此 bearer token 可以通过 `{{env.X}}` 工作:
```yaml
server:
: https://copilot.com/mcp/
headers:
Authorization: "Bearer {{env.GITHUB_TOKEN}}"
rondo:
- name: who am I
tool: get_me
args: {}
expect:
contains: "login"
```
这与驱动本地服务器一样,访问托管的 MCP 服务器。当工具返回 `structuredContent` 时,`grab` 和 `expect` 在该类型化的 JSON 上运行,而不是解析文本块。
## 命令
**`ocarina docs <command> [args...]`**:为服务器公开的每个工具、资源和资源模板生成 Markdown 文档。
**`ocarina play <rondo.yaml>`**:针对实时服务器执行每个步骤。标志:`--output json` 用于机器可读的报告,`--trace` 用于记录每个 JSON-RPC 帧,`--dry-run`,`-e key=value`,`--tags`/`--skip-tags`。
**`ocarina validate <rondo.yaml>`**:在不进行任何调用的情况下,检查工具名称、必需参数、模式类型和 `{{key}}` 数据流。
**`ocarina diff <rondo.yaml>`**:比较剧本的工具与服务器的当前模式。
**`ocarina lock <rondo.yaml>`**:将完整的工具模式快照到锁定文件。`--check` 将实时服务器与之比较,并在漂移时失败,包括重新措辞的工具描述。
**`ocarina hum <command> [args...] -- <tool> [key=value ...]`**:调用单个工具并打印结果。
**`ocarina record <output.yaml> <command> [args...]`**:代理模式;将实时 MCP 客户端会话中的每个工具调用记录到剧本文件中。
## 服务器名称
创建一个 `.mcp.json`(或 `~/.mcp.json` 用于凭证),并在剧本和命令行中按名称引用服务器:
```json
{
"mcpServers": {
"github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": { "GITHUB_PERSONAL_ACCESS_TOKEN": "ghp_..." }
}
}
}
```
```yaml
server: github
```
```bash
ocarina hum github -- list_commits owner=pytorch repo=pytorch per_page=1
```
参见 `mcp.json.example` 获取启动模板。Ocarina 还从 Claude Desktop 配置(`~/Library/Application Support/Claude/claude_desktop_config.json`)中发现服务器。
## 示例
50 多个 MCP 服务器的可用剧本位于 [`examples/`](examples/) 中。精选:
| 剧本 | 服务器 | 执行操作 |
|---|---|---|
| `sqlite-audit.yaml` | `mcp-server-sqlite` | 模式检查、行计数、引用完整性断言 |
| `github-investigation/re.yaml` | `github-mcp-server` | 提交历史、开放问题、贡献者活动 |
| `github-investigation/resource-audit.yaml` | `github-mcp-server` | 通过 `resource:` 步骤直接读取仓库文件 |
| `postgres/query-workflow.yaml` | `mcp-server-postgres` | 多步骤查询和结果验证 |
| `docker/docker.yaml` | `mcp-server-docker` | 容器列表、镜像审计、资源使用检查 |
| `elasticsearch/cluster-search.yaml` | `mcp-server-elasticsearch` | 索引健康、搜索、文档计数断言 |
| `playwright-browser/page-audit.yaml` | `mcp-server-playwright` | 导航、提取内容、对页面状态进行断言 |
| `yahoo-finance/portfolio-health.yaml` | `mcp-yahoo-finance` | 价格获取、收入报表,按 ticker 参数化 |
参见 [docs/tested-servers.md](docs/tested-servers.md) 获取完整列表。
## 示范
您可以克隆和运行的独立仓库,每个都是一个适用于不同 MCP 服务器的真实工作环境:
- [duckdb-mcp-ocarina](https://github.com/msradam/duckdb-mcp-ocarina):针对 DuckDB 数据库的数据完整性、迁移和回归测试。克隆并运行,无需凭证。
- [chrome-devtools-mcp-ocarina](https://github.com/msradam/chrome-devtools-mcp-ocarina):通过 Google 的 Chrome DevTools MCP 进行合成网页健康检查。如果出现控制台错误或请求失败,则失败。
- [github-mcp-ocarina](https://github.com/msradam/github-mcp-ocarina):通过 GitHub MCP 服务器将仓库治理作为测试。断言仓库提供许可证、文档齐全且有历史记录。
- [blender-mcp-ocarina](https://github.com/msradam/blender-mcp-ocarina):在 Blender 中自动化并快照测试 3D 场景,一个没有外部 API 的应用程序。
## 在 CI 中使用
如果所有 `expect:` 断言都通过,则 `play` 以 0 退出,否则以非零退出。在任何 CI 流水线中添加一个剧本:
```yaml
- name: Database health check
run: ocarina play rondos/db-audit.yaml
```
一个复合 GitHub Action 安装 Ocarina 并重放一个剧本:
```yaml
- uses: msradam/ocarina@v1
with:
rondo: tests/mcp-smoke.yaml
```
参见 [`action.yml`](action.yml) 和 [`.github/workflows/example.yml`](.github/workflows/example.yml)。
## 许可证
MIT。[Whistle](https://thenounproject.com/browse/icons/term/whistle/) 图标由 Alessio Capponi 来自 [Noun Project](https://thenounproject.com) (CC BY 3.0)。