mcpField
M
MusicXML Synthesizer

MusicXML Synthesizer

Local
github.com/raulkiviMedia & Design1Updated 2d ago

About MusicXML Synthesizer

MusicXML Synthesizer is an MCP server for choir singers that turns MusicXML scores into WAV audio. It supports voice-part selection, tempo changes, and practice options.

Key features

  1. 01Parse scores and list voice parts
  2. 02Synthesize WAV audio
  3. 03Filter playback by voice part
  4. 04Adjust tempo and timbre
  5. 05Add metronome and count-in
  6. 06View score summary and starting pitches

Use cases

  1. 01Practice one choir part on its own
  2. 02Repeat a selected range of measures
  3. 03Check pitch using starting notes

MCP support

It exposes score inspection, part selection, and audio synthesis tools to MCP clients.

Configuration

Local server config is the same for every client. Copy it into your client’s MCP config file.

mcp.json · Universal config
{
"mcpServers": {
"raulkivi-synth": {
"command": "uvx",
"args": [
"synth-mcp"
],
"env": {
"SYNTH_SOUNDFONT_PATH": "<SYNTH_SOUNDFONT_PATH>"
}
}
}
}
Run commanduvx synth-mcp
Environment variables to set
SYNTH_SOUNDFONT_PATHPath to an SF2 soundfont file

Local servers need a runtime on your machine (e.g. Node.js 18+). Config file locations differ by client; see your client’s docs.

Packages
pypisynth-mcp0.2.3

Tools

4

Saved tool list · updated 2w ago

ParameterTypeRequiredDescription
musicxmlstringYesMusicXML document as a string

Details

From the project README

synth-mcp

MCP server that synthesizes audio from MusicXML. Supports voice part selection (Soprano, Alto, Tenor, Bass) and tempo control.

What it does

Takes a MusicXML score, optionally filters to one or more voice parts, and renders a WAV audio file using FluidSynth. Useful for choir singers who want to practice a specific voice part.

Tools

ToolDescription
get_partsList all voice parts in a score — returns part name, ID, and measure count
synthesizeRender the score (or selected parts) to a WAV file, with optional tempo adjustment and practice options (bars, repeats, count-in, metronome, timbre, part volumes)
starting_pitchesEach part's first note as text ("S: D5, A: A4, T: F#4, B: D3") and a short piano clip
describe_scoreSummarize a score cheaply: title, key, time, tempo, parts (ID, clef, range), measures, duration
list_capabilitiesReturn server metadata: backend version, soundfont status, FluidSynth availability
health_checkCheck that the soundfont, FluidSynth, and music21 are all available and ready

Installation

cd synth-mcp
uv sync

System library required:

# Ubuntu / Debian
sudo apt install libfluidsynth-dev

# macOS
brew install fluid-synth

A soundfont (SF2) file is also required. Free options:

SoundfontSizeNotes
TimGM6mb~6 MBShips with Ubuntu (/usr/share/sounds/sf2/TimGM6mb.sf2)
MuseScore General~200 MBBetter quality; download from musescore.org
GeneralUser GS~30 MBDownload from schristiancollins.com
Quick install

Prefer not to do the above by hand? Run ./install.sh — it installs uv, the system libfluidsynth package, and a soundfont automatically. See SETUP.md for a non-technical walkthrough, and TROUBLESHOOTING.md if something goes wrong. Ready-made client configs (Claude Desktop, Cursor, Windsurf, Continue, Zed) are in examples/.

Running

SYNTH_SOUNDFONT_PATH=/usr/share/sounds/sf2/TimGM6mb.sf2 uv run synth-mcp

Configuration

VariableRequiredDescription
SYNTH_SOUNDFONT_PATHYesPath to an SF2 soundfont file
SHEET_MUSIC_OUTPUT_ROOTNoFolder output_path must be inside; also readable by musicxml_path (default: working directory)
SHEET_MUSIC_INPUT_ROOTSNoExtra folders musicxml_path may read (:-separated; ; on Windows)

Claude Desktop configuration

{
  "mcpServers": {
    "synth": {
      "command": "uv",
      "args": ["--directory", "/absolute/path/to/synth-mcp", "run", "synth-mcp"],
      "env": {
        "SYNTH_SOUNDFONT_PATH": "/absolute/path/to/soundfont.sf2"
      }
    }
  }
}

Usage examples

// List parts in a score
{"tool": "get_parts", "arguments": {"musicxml": "<score-partwise>...</score-partwise>"}}

// The same, reading a file instead of copying the score into the conversation
{"tool": "get_parts", "arguments": {"musicxml_path": "scores/chorale.mxl"}}

// Synthesize the full score
{
  "tool": "synthesize",
  "arguments": {
    "musicxml": "<score-partwise>...</score-partwise>",
    "output_path": "/tmp/full.wav"
  }
}

// Synthesize Soprano part only at 80% tempo
{
  "tool": "synthesize",
  "arguments": {
    "musicxml": "<score-partwise>...</score-partwise>",
    "output_path": "/tmp/soprano.wav",
    "parts": ["Soprano"],
    "tempo_factor": 0.8
  }
}

// Practice track: Alto loud, others soft, bars 17-24 three times, one bar of count-in
{
  "tool": "synthesize",
  "arguments": {
    "musicxml_path": "scores/chorale.mxl",
    "preset": "learning",
    "focus_part": "Alto",
    "measures": [17, 24],
    "repeat": 3,
    "count_in_bars": 1
  }
}

// Starting notes before singing
{"tool": "starting_pitches", "arguments": {"musicxml_path": "scores/chorale.mxl"}}

parts accepts part IDs from get_parts ("P1"), part names ("Soprano", any case) or voices ("S", "Alto", "Alt", "A1" for divisi); an unknown part returns the valid choices. part_ids still works as a deprecated alias for one minor release.

Every tool that takes musicxml also takes musicxml_path instead (exactly one of the two): a .musicxml, .xml or compressed .mxl file inside the output root, a folder the client shares as an MCP root, or a folder in SHEET_MUSIC_INPUT_ROOTS. Prefer it, and pass on paths other servers return. describe_score reports part IDs, ranges and duration without returning the score.

tempo_factor range: 0.25–4.0. Values below 1.0 slow down; above 1.0 speed up. Does not affect pitch.

Practice options on synthesize (all optional; leaving them out gives the plain track):

OptionValuesEffect
measures[start, end]Only these printed bars (a pickup is 0)
repeat1–20Play the selection this many times
count_in_bars0–4Wood-block clicks before the music
metronometrue / falseClicks on every beat of the music too
timbrescore, piano, choir, organSound for every part (score keeps the score's instruments)
preset + focus_partlearning (focus 1.5, others 0.5), karaoke (focus muted), equalPart volumes
part_gainspart → 0.0–2.0Per-part volume, overrides the preset

starting_pitches returns the text always; the clip (mono 16 kHz WAV, inline when ≤ 200 KB) needs the soundfont and FluidSynth. Without them the result says why in audio_unavailable.

Testing

# Unit tests (no soundfont required)
VIRTUAL_ENV= .venv/bin/pytest tests/ -v

# Integration tests (synthesizes real audio)
VIRTUAL_ENV= SYNTH_SOUNDFONT_PATH=/usr/share/sounds/sf2/TimGM6mb.sf2 \
  .venv/bin/pytest tests/ -v -m integration

Dependencies

  • music21 — score parsing and MIDI export
  • pyfluidsynth — Python bindings for FluidSynth
  • mcp — MCP protocol

Known limitations

  • music21's MIDI export may drop some articulations and dynamics
  • Audio output is always WAV; convert with ffmpeg -i out.wav out.mp3 if needed
  • Large scores (100+ measures) may take several seconds to synthesize

System requirements

  • Python 3.11+
  • libfluidsynth shared library (libfluidsynth.so.3 on Linux)
  • An SF2 soundfont file

Comments

Markdown supported

New to MCP?

From what the protocol is to installing your first server, these answers cover most first questions.

An open protocol that defines how AI applications connect to external tools and data in a uniform way. Clients talk to the model; MCP servers provide tools, resources and prompt templates. They exchange standard messages, so one server can be reused by many clients.