mcpField
M
MusicXML Comparer

MusicXML Comparer

本地服务
github.com/raulkivi媒体与设计12 天前更新

关于 MusicXML Comparer

MusicXML Comparer 是用于结构化、音乐感知乐谱比较的 MCP 服务。它面向需要检查编曲、OMR 输出、格式转换或乐谱编辑的音乐工作者和开发者,可从整体相似度比较到单个音符差异。

主要功能

  1. 01比较 MusicXML 文本或文件
  2. 02计算相似度并汇总变化
  3. 03按声部或小节查看音符差异
  4. 04生成易读的比较报告
  5. 05导出带颜色差异标注的 MusicXML
  6. 06描述乐谱结构和元数据

适用场景

  1. 01比较同一作品的不同版本或编曲
  2. 02根据参考乐谱评估 OMR 输出
  3. 03检查 MusicXML 转换往返结果
  4. 04验证乐谱编辑并发现回归问题

MCP 相关

向 MCP 客户端提供乐谱比较、报告、标注、描述和健康检查工具。乐谱可直接以内联内容或允许目录中的文件路径提供。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"raulkivi-comparer": {
"command": "uvx",
"args": [
"comparer-mcp"
]
}
}
}
启动命令uvx comparer-mcp

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
pypicomparer-mcp0.2.1

工具

8

收录的工具列表 · 更新于 2 周前

参数类型必填说明
optionsobject否比较选项(docs/architecture.md §8)。expand_repeats 默认为 false(选择启用——参见 docs/PLAN.md 'Changed decisions');normalize_pitch、ignore_articulations、part_filter、measure_range 均默认为关闭/未设置。
options.part_filterarray否
options.measure_rangearray否
options.expand_repeatsboolean否
options.normalize_pitchboolean否
options.ignore_articulationsboolean否
target_xmlstring是作为字符串提供的目标 MusicXML 文档,与参考文档进行比较
reference_xmlstring是作为字符串提供的参考 MusicXML 文档

详细介绍

comparer-mcp

用于感知音乐内容并比较 MusicXML 文件的 MCP 服务。提供结构化的多层级差异, 报告两个乐谱之间的变化,从整体相似度到单个音符。

功能

  • 版本/编曲比较 — 比较同一作品的不同版本、编曲或简化版本
  • OMR 质量评估 — 将 omr-mcp 的输出与已知的优质参考进行比较
  • 往返保真度 — 通过 musicxml-abc-mcp 验证 MusicXML → ABC → MusicXML 转换
  • 回归测试 — 检测 OMR 模型或转换逻辑变更时是否出现回归
  • 乐谱编辑验证 — 确认由 LLM 驱动的编辑只更改了预期元素

安装

bash install.sh

有关客户端配置示例(Claude Desktop、Cursor、Windsurf、Continue、Zed),请参阅 SETUP.md; 如果遇到问题,请参阅 TROUBLESHOOTING.md。

MCP 工具

工具描述
compare_musicxml对两个乐谱进行完整差异比较,可内联传入或通过路径指定 → 结构化 ComparisonResult JSON
compare_musicxml_files对允许文件夹中的两个 MusicXML 文件路径(.musicxml、.xml 或 .mxl)进行完整差异比较 → 结构化 ComparisonResult JSON
quick_similarity仅返回相似度分数(0.0–1.0)和摘要统计信息,不含逐音符详情
list_changes音符级差异(操作不等于 MATCH),可按声部名称和/或小节范围筛选
generate_comparison_report易读的版本比较报告——相似度摘要、缺失/额外的声部和小节、调号/拍号变化,以及按小节范围分组的音符级差异(例如“小节 17-24 中移调了 3 个半音”)
export_annotated_musicxml为 MusicXML 添加逐音符颜色标注以标记差异。较小的结果会内联返回(reference_annotated_musicxml + target_annotated_musicxml);较大的结果会写入文件,并作为 *_path 字段及 score_summary 返回(return:auto/path/inline)。将路径作为 musicxml_path 传给 render-mcp 的 render_to_pdf/render_to_image
describe_score返回乐谱的标题、调号、拍号、速度、声部(ID、名称、谱号、音域)、小节数和时长,但不返回乐谱本身
health_check服务状态——验证 music21 可导入,并运行自比较冒烟测试
list_capabilities按项目约定返回服务元数据

每份乐谱都可以内联传入(reference_xml、target_xml),也可以通过文件路径指定 (reference_path、target_path;.musicxml、.xml 或 .mxl),每组参数必须且只能指定一个。使用路径 可避免在对话中复制整份乐谱。路径必须位于输出文件夹(SHEET_MUSIC_OUTPUT_ROOT,默认为工作目录)、客户端的根目录之一,或 SHEET_MUSIC_INPUT_ROOTS 中列出的文件夹内。

// Compare two MusicXML strings
{
  "tool": "compare_musicxml",
  "arguments": {
    "reference_xml": "<score-partwise>...</score-partwise>",
    "target_xml": "<score-partwise>...</score-partwise>"
  }
}

// Compare two files
{
  "tool": "compare_musicxml_files",
  "arguments": {
    "reference_path": "/path/to/reference.musicxml",
    "target_path": "/path/to/omr_output.musicxml"
  }
}

// Quick similarity check
{
  "tool": "quick_similarity",
  "arguments": {
    "reference_xml": "<score-partwise>...</score-partwise>",
    "target_xml": "<score-partwise>...</score-partwise>"
  }
}
// → {"similarity_score": 0.87, "summary": {...}}

// Filtered changes, e.g. "what changed in the Alto, measures 17-24?"
{
  "tool": "list_changes",
  "arguments": {
    "reference_xml": "<score-partwise>...</score-partwise>",
    "target_xml": "<score-partwise>...</score-partwise>",
    "part": "Alto",
    "measures": [17, 24]
  }
}
// → {"changes": [{"measure_number": 18, "operation": "PITCH_CHANGE", "part_name": "Alto", ...}], "count": 1}

// Human-readable report
{
  "tool": "generate_comparison_report",
  "arguments": {
    "reference_xml": "<score-partwise>...</score-partwise>",
    "target_xml": "<score-partwise>...</score-partwise>"
  }
}
// → {"report": "Overall similarity: 87% (minor differences)\n...", "similarity_score": 0.87}

// Colored MusicXML diff export — chain straight into render-mcp to visualize
{
  "tool": "export_annotated_musicxml",
  "arguments": {
    "reference_xml": "<score-partwise>...</score-partwise>",
    "target_xml": "<score-partwise>...</score-partwise>"
  }
}
// → {"reference_annotated_musicxml": "...", "target_annotated_musicxml": "...",
//    "similarity_score": 0.87, "legend": {"PITCH_CHANGE": "#FF8800", ...}}
// For scores over 8 KB (return: "auto", the default):
// → {"reference_annotated_musicxml_path": ".../scores/annotated-reference_annotated_musicxml-....musicxml",
//    "target_annotated_musicxml_path": "...", "similarity_score": 0.87, "legend": {...},
//    "score_summary": {"reference_annotated_musicxml": {...}, "target_annotated_musicxml": {...}}}

// Paths instead of inline text
{
  "tool": "quick_similarity",
  "arguments": {
    "reference_path": "scores/reference.musicxml",
    "target_path": "scores/omr_output.mxl"
  }
}

compare_musicxml、compare_musicxml_files、generate_comparison_report 和 export_annotated_musicxml 均接受可选的 options 对象:

{
  "expand_repeats": false,        // unfold repeats before comparing (default: false — opt-in)
  "normalize_pitch": false,       // transpose transposing instruments to concert/sounding pitch
  "ignore_articulations": false,  // exclude articulations from NoteInfo/diffs
  "parts": ["Soprano"],           // compare only these parts: IDs, names or voices ("P1", "S");
                                  //   part_filter is a deprecated alias
  "measures": [1, 32]             // only differences in measures 1-32, inclusive (scores are not
                                  //   cut); measure_range is a deprecated alias
}

直接使用引擎

比较引擎(src/comparer_mcp/engine.py)不依赖 MCP,可作为普通 Python 库独立使用,无需启动 MCP 服务:

cd comparer-mcp
uv sync
from comparer_mcp.engine import compare, compare_files

# Compare two MusicXML strings
result = compare(reference_xml, target_xml)

# Compare two files (.musicxml, .xml, or compressed .mxl)
result = compare_files("reference.musicxml", "omr_output.mxl")

print(result.similarity_score)   # float, 0.0-1.0
print(result.summary)            # ComparisonSummary: parts/measures/notes matched, missing, changed
print(result.part_diffs)         # list[PartDiff] -> list[MeasureDiff] -> list[NoteDiff]

错误会以 comparer_mcp.engine.ProcessingError 的形式抛出(例如文件缺失或 MusicXML 无效时),并带有 .error_code 属性(FILE_NOT_FOUND、INVALID_INPUT 等),与 MCP 工具返回的格式一致。

测试

# Unit tests
VIRTUAL_ENV= .venv/bin/pytest tests/ -v -m "not integration"

# Integration tests (real .mxl SATB fixtures shared with omr-mcp)
VIRTUAL_ENV= .venv/bin/pytest tests/ -v -m integration

# Install dependencies
uv sync

依赖项

  • music21 — MusicXML 解析、乐谱对象模型、流对齐
  • numpy — 用于音符对齐的距离矩阵(由 music21 间接依赖)
  • mcp — MCP 协议

系统要求

  • Python 3.11+
  • 无需系统库

阶段状态

阶段状态
阶段 1 — 核心比较(MVP)已完成 — 45/45 项测试通过(43 项单元测试 + 2 项集成测试)
阶段 2 — 丰富细节(调号/拍号差异、感知声部的对齐、演奏法)已完成 — 67/67 项测试通过(65 项单元测试 + 2 项集成测试)
阶段 3 — MCP 服务与集成(server.py、全部 6 个工具、install.sh、SETUP.md、客户端配置示例)已完成 — 94/94 项测试通过(90 项单元测试 + 4 项集成测试)
阶段 4 — 高级功能(options 接线、generate_comparison_report、export_annotated_musicxml)已完成 — 134/134 项测试通过(127 项单元测试 + 7 项集成测试)
UX 第 2 波 — 乐谱引用(reference_path/target_path、用于标注导出的 return、describe_score)已完成 — 239 项单元测试通过(+7 项集成测试)

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。