2026年7月4日 3 分钟阅读

Ocarina 完全指南:用 Rondo 为 MCP 服务器编写确定性自动化测试

tinyash 0 条评论

MCP(Model Context Protocol)生态正在快速膨胀——如今已有数千个 MCP 服务器,涵盖数据库、GitHub、文件系统、浏览器、3D 渲染等各类场景。每个服务器都暴露一组工具(get_issuesquery_databasecreate_file),供 AI 编码 Agent 调用。

但这里有一个核心痛点:你如何知道 MCP 服务器正常工作? 当你在 CI 流水线中依赖某个 MCP 服务器时,怎么确保它下次返回的结果依然正确?

现有方案要么引入另一个 LLM 来做”智能验证”(成本高、结果不稳定),要么根本不验证。Ocarina 选择了第三条路——用 YAML 编写确定性测试,无需 LLM 参与,每次运行结果完全可复现。

Ocarina 是什么?

Ocarina 是一个 MCP 服务器的自动化框架,核心思想很简单:用 YAML 文件(称为 Rondo)描述你要调用的工具、传入的参数、期望的输出,然后让 Ocarina 执行它。 不调语言模型,不消耗 Token,每次运行结果一致。

它的作者 msradam 从 Ansible 获得了灵感——正如 Ansible Playbook 让基础设施变成代码,Ocarina Rondo 让 MCP 测试变成代码。

server:
  command: uvx
  args: [mcp-server-time]

rondo:
  - name: what time is it in Tokyo
    tool: get_current_time
    args:
      timezone: Asia/Tokyo
    expect:
      contains: datetime

这个 Rondo 做了三件事:启动一个 MCP 服务器(mcp-server-time),调用它的 get_current_time 工具,验证输出中包含 datetime。全部是确定性的——同样的 YAML,同样的结果。

安装

Ocarina 是一个 Go 单二进制文件,安装非常简单:

go install github.com/msradam/ocarina@latest

如果没有 Go 环境,可以从 GitHub Releases 页面下载预编译的二进制文件。需要 Go 1.26+(从源码构建时)。

核心命令

Ocarina 提供了 9 个命令,覆盖了 MCP 服务器自动化的全生命周期:

命令功能
play执行 Rondo 中的每一步,验证断言
validate检查 Rondo 格式、工具名、参数类型,不实际调用
serve把 Rondo 暴露为复合 MCP 工具
diff对比 Rondo 中的工具与当前服务器 Schema 的差异
lock快照当前工具 Schema,--check 模式下检测漂移
load对 Rondo 执行并发负载测试
record代理客户端会话,把实际调用录制成 Rondo
docs生成 MCP 服务器的 Markdown 文档
hum单次调用一个工具并打印结果

深入 Rondo 格式

Rondo 的威力远超简单的”调用-验证”。它支持变量插值、多步骤流水线、条件执行、循环、错误处理,以及可复用的片段(Motif)。

变量与数据流

Rondo 支持通过 keys 定义顶层变量,用 echo 在步骤间传递数据,用 grab 从 JSON 输出中提取特定字段:

keys:
  owner: pytorch
  repo: pytorch

server:
  command: npx
  args: [-y, "@modelcontextprotocol/server-github"]

rondo:
  - name: recent commits
    tool: list_commits
    args:
      owner: "{{owner}}"
      repo: "{{repo}}"
    grab: ".0.sha"       # 取第一个 commit 的 SHA
    echo: latest_sha      # 保存为变量

  - name: commit detail
    tool: get_commit
    args:
      sha: "{{latest_sha}}"
    expect:
      contains: "feat"

{{key}} 语法用于变量插值,支持从 keysecho 输出和 {{env.NAME}} 环境变量读取数据。

断言系统

断言是 Rondo 的”测试断言”。Ocarina 支持四种断言方式:

- name: check output
  tool: some_tool
  args: {input: "hello"}
  expect:
    contains: "expected substring"    # 子串匹配
    matches: "^[A-Z].*"               # 正则匹配
    equals: "exact output"            # 精确匹配
    is_error: false                   # 是否期望错误
    rule: "output.total == 2"         # CEL 表达式
    max_duration: "500ms"             # 超时门控

rule 使用 CEL(Common Expression Language)编写表达式,当工具返回结构化 JSON 时,可以直接操作对象字段。

错误处理:Block / Rescue / Always

Ocarina 借鉴了 Ansible 的错误处理模式——block 执行一组步骤,任一失败时跳转到 rescuealways 块无论如何都会执行:

rondo:
  - name: provision with rollback
    block:
      - tool: create_directory
        args: {path: "{{dir}}"}
      - tool: write_file
        args: {path: "{{dir}}/config", content: "data"}
    rescue:
      - tool: write_file
        args: {path: "/logs/failure", content: "failed"}
    always:
      - tool: list_directory
        args: {path: "{{dir}}"}

这种模式非常适合测试需要事后清理的场景——测试失败时自动回收资源。

可复用片段:Motif

Motif 是 Rondo 的可复用片段,相当于 Ansible 的 Role 或 pytest 的 Fixture。定义一个 Motif 文件,然后在多个 Rondo 中引用:

keys:
  zone: UTC
rondo:
  - tool: get_current_time
    args: {timezone: "{{zone}}"}
    expect: {contains: datetime}

引用 Motif 并覆盖参数:

rondo:
  - name: default zone
    motif: motifs/time-probe.yaml
  - name: tokyo
    motif: motifs/time-probe.yaml
    with:
      zone: Asia/Tokyo

CI 集成:让 MCP 服务器测试进入流水线

Ocarina 最实用的场景之一是 CI 集成。play 命令在所有断言通过时返回 0,任何断言失败返回非零:

- name: MCP smoke test
  run: ocarina play tests/mcp-smoke.yaml

Ocarina 还提供了 GitHub Action:

- uses: msradam/ocarina@v1
  with:
    rondo: tests/mcp-smoke.yaml

快照测试

Ocarina 的快照测试工作流与 Jest 类似:

ocarina record session.yaml uvx mcp-server-fetch

ocarina play session.yaml --snapshot

ocarina play session.yaml --update

这在 CI 中特别有用——--snapshot 确保任何意外的输出变化都会阻断流水线,而 --update 只在开发者主动修改后才重新生成基准。

多种输出格式

Ocarina 支持 JUnit XML 和 JSON 输出格式,方便集成到各种 CI 报告系统:

ocarina play tests/mcp-smoke.yaml --output junit
ocarina play tests/mcp-smoke.yaml --output json

此外还支持 OpenTelemetry 追踪——设置 OTEL_EXPORTER_OTLP_ENDPOINT 后,每个步骤的调用都会作为 span 导出。

高级功能

复合 MCP 工具(Serve)

ocarina serve 可以把一个 Rondo 暴露为单个 MCP 工具。这意味着你可以把多步操作封装成一个原子工具,Agent 只需要调用一次:

name: provision_workspace
description: Create a workspace and seed it with config files
params:
  - name: dir
    type: string
    required: true
return: listing
server:
  command: npx
  args: [-y, "@modelcontextprotocol/server-filesystem", /tmp]
rondo:
  - tool: create_directory
    args: {path: "{{dir}}"}
  - tool: write_file
    loop: '["alpha.conf", "beta.conf"]'
    args: {path: "{{dir}}/{{item}}", content: "managed by ocarina"}
  - tool: list_directory
    args: {path: "{{dir}}"}
    echo: listing

启动复合工具:

ocarina serve provision.yaml              # stdio 模式
ocarina serve provision.yaml --http :8080  # HTTP 模式

安全模式

play --safeserve --safe 模式会拒绝调用任何非只读工具(根据 MCP 的 readOnlyHint 标注)。这让你可以放心地在不信任的服务器上执行只读检查:

ocarina play audit.yaml --safe

多服务器支持

一个 Rondo 可以驱动多个 MCP 服务器:

servers:
  time: {command: uvx, args: [mcp-server-time]}
  fetch: {command: uvx, args: [-y, "@modelcontextprotocol/server-fetch"]}

rondo:
  - server: time
    tool: get_current_time
    args: {timezone: UTC}
  - server: fetch
    tool: fetch
    args: {url: "https://example.com"}

数据驱动测试

从 CSV 或 JSON 文件注入多行数据,每行作为一次独立运行:

ocarina play zone-check.yaml --data timezones.csv

每行 CSV 的列名作为 {{key}} 注入 Rondo 的变量。

远程服务器支持

Ocarina 支持通过 Streamable HTTP 协议连接远程 MCP 服务器:

server:
  url: https://api.githubcopilot.com/mcp/
  headers:
    Authorization: "Bearer {{env.GITHUB_TOKEN}}"
rondo:
  - tool: get_me
    expect: {contains: login}

实际应用场景

场景一:CI 中验证 MCP 服务器不出现回归

在每次部署前,运行一组 Rondo 检查所有关键 MCP 工具是否按预期工作:

server:
  command: uvx
  args: [-y, "@modelcontextprotocol/server-github"]

rondo:
  - tool: list_issues
    args: {owner: myorg, repo: myrepo, state: open}
    expect: {contains: title}
  - tool: get_repository
    args: {owner: myorg, repo: myrepo}
    expect: {contains: myrepo}

场景二:生成 MCP 服务器文档

ocarina docs uvx mcp-server-time > mcp-time-docs.md

场景三:代理录制真实会话用于故障排查

ocarina record session.yaml uvx mcp-server-github

然后重放录制的 Rondo,对比输出是否与录制时一致。

总结

Ocarina 填补了 MCP 生态中的一个关键空白——确定性测试和自动化。当 AI 编码 Agent 的可靠度越来越依赖底层 MCP 服务器的正确性时,一个能反复验证、不依赖 LLM、可嵌入 CI 的测试框架就变得不可或缺。

它的 Rondo 语法借鉴了 Ansible 的设计哲学,降低了学习曲线;快照测试和 CI 集成让它适合生产环境;Serve 功能更是把自动化测试的概念扩展到了复合工具层面。

如果你在使用或开发 MCP 服务器,Ocarina 值得一试——它可能是你工具箱里最不起眼但最实用的小工具。

相关链接:

发表评论

你的邮箱地址不会被公开,带 * 的为必填项。