Generate music scores as MusicXML using music21 Python scripts. Use when the user says "create a score", "generate a chart", "write a lead sheet", "make an arrangement", "write out parts", or describes a musical piece to notate. Do NOT use for live MuseScore manipulation (use the mcp-score MCP bridge tools).
Generate music scores by writing and executing music21 Python scripts that export MusicXML.
/tmp/generate_score.pymcp-score run /tmp/generate_score.py
Default output location: ~/Desktop/<Title>.musicxml
music21 uses - for flats in note names, key names, and chord symbol roots. This is the most common source of bugs:
# WRONG — "Bb7" is parsed as B root with a b7 alteration, NOT Bb dominant 7th
harmony.ChordSymbol("Bb7") # B major + flat-7 — wrong!
# CORRECT — use '-' for flats in the root
harmony.ChordSymbol("B-7") # Bb dominant 7th
harmony.ChordSymbol("E-7") # Eb dominant 7th
harmony.ChordSymbol("A-maj7") # Ab major 7th
harmony.ChordSymbol("D-9") # Db dominant 9th
# Sharps use '#' as expected in roots
harmony.ChordSymbol("F#m7") # F# minor 7th
harmony.ChordSymbol("C#7") # C# dominant 7th
# In extensions/alterations, 'b' and '#' work normally
harmony.ChordSymbol("Cm7b5") # C half-diminished
harmony.ChordSymbol("Cmaj7#11") # C major 7 sharp 11
harmony.ChordSymbol("G7b9") # G dominant 7 flat 9
harmony.ChordSymbol("C7#5") # C augmented dominant 7
Rule: - for flats in the root/bass only. b/# for alterations in extensions.
The same - convention applies to note names and keys:
note.Note("B-4") # Bb4
key.Key("B-") # Bb major
key.Key("e-") # Eb minor (lowercase = minor)
key.Key("F#") # F# major
key.Key("f#") # F# minor
When the same chord spans multiple consecutive bars, do NOT notate it every bar:
Example — 12-bar blues in Bb, each | is a bar:
Bb7 | | | | Eb7 | | Bb7 | | F7 | Eb7 | Bb7 | F7
Chord symbols appear on bars 1, 5, 6, 7, 9, 10, 11, 12 — NOT every bar.
Always set title and any provided metadata using metadata.Metadata:
from music21 import metadata
score.metadata = metadata.Metadata()
score.metadata.title = "Score Title"
score.metadata.composer = "Composer Name" # if provided
score.metadata.movementName = "Subtitle Here" # subtitle (shows below title in MusicXML)
# Arranger and copyright are set via Contributor and Copyright objects:
from music21 import metadata as md
score.metadata.addContributor(md.Contributor(role="arranger", name="Arranger Name"))
score.metadata.copyright = md.Copyright("© 2026 Author Name")
from music21 import bar
# Repeat signs — use bar.Repeat, NOT bar.Barline
measure.leftBarline = bar.Repeat(direction='start')
measure.rightBarline = bar.Repeat(direction='end')
# Standard barlines
measure.rightBarline = bar.Barline('double')
measure.rightBarline = bar.Barline('final')
Use spanner.RepeatBracket for volta brackets. Spanners must be appended to the Part, not the Measure.
from music21 import spanner
# After building all measures and adding parts to score:
for part in score.parts:
m_first = part.measure(15) # 1st ending measure
m_second = part.measure(16) # 2nd ending measure
part.append(spanner.RepeatBracket(m_first, number=1))
part.append(spanner.RepeatBracket(m_second, number=2))
Volta brackets work with repeat barlines:
rightBarline = bar.Repeat(direction='end') (player repeats back)For multi-measure endings, pass a list of measures:
part.append(spanner.RepeatBracket([m13, m14, m15], number=1))
Important: Add volta brackets to all parts, not just the first part. Standard MusicXML — works in MuseScore, Dorico, and Sibelius.
Each part needs its own key signature and time signature on measure 1:
for part in all_parts:
first_measure = part.measure(1)
first_measure.insert(0.0, key.Key("B-"))
first_measure.insert(0.0, meter.TimeSignature("4/4"))
Tempo marks and rehearsal marks go on the first part only — they apply to the full score.
music21 handles transposition automatically when using the correct instrument class.
A Trumpet() is in Bb — music21 will write concert pitch internally and produce
the correct transposed part in MusicXML. Write notes at concert pitch in the script.
For the full instrument list with transposition details, read:
references/instruments.md (relative to this skill directory).
See references/template.py for a complete, runnable template. Key patterns:
stream.Score(), set metadatastream.Part(), assign instrument classespart.measure(n).insert(offset, harmony.ChordSymbol(...))part.measure(n).insert(0.0, expressions.RehearsalMark(...))score.write("musicxml", fp=output_path)Script creates:
~/Desktop/Blues in Bb.musicxmlScript creates:
~/Desktop/Big Band Chart.musicxmlFlat chords showing wrong extension (e.g. B(b7) instead of Bb7)
Cause: Using "Bb7" instead of "B-7". Fix: always use - for flats in roots.
Title not showing in MuseScore
Cause: Metadata not set properly. Fix: use metadata.Metadata() directly.
Subtitle or arranger not showing in MuseScore
Cause: music21 correctly exports <movement-title> and <creator type="arranger"> in the MusicXML, but MuseScore 4 doesn't display them visually. This is a known MuseScore limitation — it expects <credit> elements for visual layout, which music21 doesn't generate from metadata. The data is in the file; the user can add subtitle/arranger text manually in MuseScore after import. Dorico and Sibelius may handle these fields better.
Repeat barlines not appearing
Cause: Using bar.Barline('repeat-start'). Fix: use bar.Repeat(direction='start').
music21 not found
Cause: Wrong Python. Fix: use mcp-score run which uses the bundled interpreter.
Notes sound wrong for transposing instruments Cause: Writing transposed pitch instead of concert pitch. Fix: always write concert pitch — music21 transposes automatically based on the instrument class.