music21-mcp
by cclawton
README.md
# music21-mcp
Symbolic music analysis and editing tools exposed through MCP, built on music21. The server works with user-supplied MIDI and supports analysis, transformation, and basic accompaniment generation.
The current implementation registers 16 MCP tools and has 120 automated tests.
## What it does
Give an AI agent a MIDI file and it can:
- **Read** — parse MIDI, detect key, analyze chord progressions
- **Edit** — transpose, change velocity, filter notes, replace chords, merge files, quantize timings
- **Generate** — reharmonize progressions, harmonize melodies
- **Analyze** — detect modulations, extract melody, identify song form, search for patterns
## Tools
The MCP-facing names currently use an `mcp_` prefix, such as `mcp_analyze_key` and `mcp_transpose_midi`. The underlying Python functions use the unprefixed names shown below.
| Phase | Tool | What it does |
|-------|------|-------------|
| 1a | `parse_midi_file` | Load a .mid file into a music21 stream |
| 1a | `analyze_key` | Detect key, mode, and confidence |
| 1a | `export_midi` | Write a stream to a .mid file |
| 1c | `transpose_midi` | Transpose by semitones or to a target key |
| 1c | `change_velocity` | Scale, set, or offset note velocities (clamped 1–127) |
| 1c | `modify_notes` | Remove/select notes by pitch range, shift octaves |
| 1c | `replace_chord_at` | Replace a chord at a specific bar/beat |
| 1c | `merge_midi` | Overlay two streams (flat or multi-part score) |
| 1c | `quantize_midi` | Snap note timings to quarter/eighth/sixteenth grid |
| 2 | `reharmonize` | Replace chords with diatonic or jazz substitutions |
| 2 | `harmonize_melody` | Generate block chord accompaniment from a melody |
| 3 | `analyze_chord_progression` | Identify chords + Roman numerals in a progression |
| 3 | `extract_melody` | Isolate the melody line (highest pitch per offset) |
| 3 | `detect_modulations` | Find key changes via sliding window analysis |
| 3 | `analyze_form` | Identify song sections (A, B, A') by register changes |
| 3 | `search_pattern` | Find melodic patterns by exact pitch or interval sequence |
## Getting started
### Prerequisites
- Python 3.11+
- A virtual environment (recommended)
### Install
```bash
cd music21-mcp
# Create and activate venv
python3 -m venv venv
source venv/bin/activate
# Install the package and test dependencies in editable mode
pip install -e ".[dev]"
```
### Run tests
```bash
# All 120 tests
pytest -v
# Just one tool's tests
pytest tests/test_transpose_midi.py -v
```
### Use as MCP server
The server runs over stdio and is intended for MCP clients that support local stdio servers.
```bash
# Start the server
python -m music21_mcp.server
```
To configure in an MCP client, add to your client's MCP config:
```json
{
"mcpServers": {
"music21-mcp": {
"command": "python",
"args": ["-m", "music21_mcp.server"],
"cwd": "/path/to/music21-mcp"
}
}
}
```
Or if using the project venv:
```json
{
"mcpServers": {
"music21-mcp": {
"command": "/path/to/music21-mcp/venv/bin/python",
"args": ["-m", "music21_mcp.server"]
}
}
}
```
### Use directly in Python
Every tool is a pure function you can call without the MCP layer:
```python
from music21_mcp.tools.parse_midi import parse_midi_file
from music21_mcp.tools.analyze_key import analyze_key
from music21_mcp.tools.transpose_midi import transpose_midi
from music21_mcp.tools.export_midi import export_midi
# Load a MIDI file
stream = parse_midi_file("song.mid")
# Detect the key
key_info = analyze_key(stream)
print(key_info)
# {'key': 'C major', 'mode': 'major', 'confidence': 0.797}
# Transpose to F major
transposed = transpose_midi(stream, target_key="F")
# Save the result
export_midi(transposed, "song_in_f.mid")
```
### Example: the full pipeline
```python
from music21_mcp.tools import (
parse_midi_file, analyze_key, transpose_midi,
change_velocity, quantize_midi, export_midi,
)
# Load
s = parse_midi_file("input.mid")
# Detect key
print(analyze_key(s))
# Transpose up 2 semitones, make 20% louder, quantize to 16th notes
s = transpose_midi(s, semitones=2)
s = change_velocity(s, scale=1.2)
s = quantize_midi(s, grid="sixteenth")
# Save
export_midi(s, "output.mid")
```
## Example prompts for testing
Single-tool prompts to verify each tool works in isolation:
1. **Parse only** — "Load `song.mid` with parse_midi_file and tell me how many parts and measures it has."
2. **Key detection** — "Use parse_midi_file to load `song.mid`, then analyze_key to tell me the key, mode, and confidence."
3. **Export** — "Load `song.mid` with parse_midi_file and export it to `copy.mid` with export_midi. Report the output path."
4. **Transpose** — "Parse `song.mid` and transpose it down 3 semitones. Export to `song_down.mid`."
5. **Transpose to key** — "Load `song.mid`, detect its key, then transpose it to E minor. Export to `song_em.mid`."
6. **Velocity** — "Parse `song.mid`, set all velocities to a fixed value of 90. Export to `song_vel90.mid`."
7. **Velocity boost** — "Load `song.mid` and scale all velocities by 1.3 (clamped to 127). Export to `song_louder.mid`."
8. **Filter notes** — "Parse `song.mid` and remove all notes below C3. Export to `song_no_bass.mid`."
9. **Octave shift** — "Load `song.mid` and shift everything up 1 octave. Export to `song_oct_up.mid`."
10. **Replace chord** — "Parse `song.mid` and replace the chord at bar 2, beat 1 with a C major triad. Export to `song_newchord.mid`."
11. **Merge** — "Load `drums.mid` and `bass.mid`, merge them into a single file. Export to `drum_and_bass.mid`."
12. **Quantize** — "Parse `song.mid` and quantize all timings to a sixteenth-note grid. Export to `song_quantized.mid`."
13. **Reharmonize** — "Load `song.mid` and reharmonize the chord progression using jazz substitutions. Export to `song_jazz.mid`."
14. **Harmonize** — "Parse `melody.mid` and generate block chord accompaniment from the melody line. Export to `melody_with_chords.mid`."
15. **Chord analysis** — "Load `song.mid` and analyze the chord progression. Give me the chords and Roman numerals."
16. **Extract melody** — "Parse `song.mid` and extract just the melody line. Export to `melody_only.mid`."
17. **Detect modulations** — "Load `song.mid` and find all key changes. Tell me where each modulation happens."
18. **Analyze form** — "Parse `song.mid` and identify the song structure (A, B, A' sections)."
19. **Search pattern** — "Load `song.mid` and search for the pitch sequence C4-E4-G4. Tell me where it occurs."
Multi-tool chains to test tool composition:
20. **Full analysis** — "Load `song.mid`. Detect the key, analyze the chord progression, extract the melody, and analyze the song form. Give me a complete analysis report."
21. **Transpose and harmonize** — "Parse `song.mid`, transpose up 5 semitones, then reharmonize the result with jazz substitutions. Export to `song_jazz_up.mid`."
22. **Clean and quantize** — "Load `song.mid`, remove all notes below C2, quantize to an eighth-note grid, and scale velocities by 0.8. Export to `song_cleaned.mid`."
23. **Melody extraction pipeline** — "Parse `song.mid`, extract the melody, harmonize it with block chords, and export to `melody_harmonized.mid`."
24. **Key-aware reharm** — "Load `song.mid`, detect the key, then reharmonize using diatonic substitutions appropriate for that key. Export to `song_diatonic.mid`."
25. **Modulation-aware transpose** — "Parse `song.mid`, detect all modulations, then transpose the whole piece so the first key becomes A minor. Export to `song_am.mid`."
26. **Pattern search** — "Load `song.mid` and search for the interval sequence [2, 2] (two whole steps up). Report every matching offset."
27. **Form and melody analysis** — "Parse `song.mid`, analyze its form, then extract the full melody line and export it to `melody.mid`."
28. **Multi-file merge and clean** — "Merge `drums.mid` and `bass.mid`, then merge that result with `keys.mid`. Quantize the combined file to a sixteenth grid, set velocities to 100, and export to `full_band.mid`."
29. **End-to-end remix** — "Load `song.mid`. Detect key, transpose down 2 semitones, quantize to eighth notes, reharmonize with jazz substitutions, boost velocity by 1.4, and export to `song_remix.mid`."
## Architecture
```
src/music21_mcp/
__init__.py # Package entry
server.py # FastMCP server — 16 tool wrappers returning JSON
tools/
parse_midi.py # Phase 1a
analyze_key.py
export_midi.py
transpose_midi.py # Phase 1c
change_velocity.py
modify_notes.py
replace_chord_at.py
merge_midi.py
quantize_midi.py
reharmonize.py # Phase 2
harmonize_melody.py
analyze_chord_progression.py # Phase 3
extract_melody.py
detect_modulations.py
analyze_form.py
search_pattern.py
tests/
test_*.py # One test file per tool, plus server + e2e tests
```
Most editing and analysis functions operate on music21 streams. Parsing and export perform file I/O, while the MCP wrappers accept file paths and return JSON strings. This keeps the domain logic independently testable.
## Tech
- [music21](https://web.mit.edu/music21/) — MIT's music theory and analysis toolkit
- [MCP](https://modelcontextprotocol.io/) — Model Context Protocol for AI agent tool calling
- Python 3.11+, pytest, strict TDD
## License
MIT
This server cannot be deployed
Maintenance
ActivityInactive
ResponsivenessNo issues