Skip to main content
Glama

fcp-midi

MCP server for semantic MIDI composition.

What It Does

fcp-midi lets LLMs compose music by describing musical intent -- notes, chords, dynamics, tempo changes -- and renders it into standard MIDI files. Instead of manipulating raw bytes or MIDI events, the LLM works with operations like note Bass E2 at:1.1 dur:quarter vel:90 and crescendo @track:Lead vel:45-75 @range:3.1-6.4. Built on the FCP framework; a mido.MidiFile is the source of truth throughout, so there's no separate serialization step.

Related MCP server: Vibe Composer MIDI MCP

Quick Example

midi_session('new "Voltage Drop" tempo:140 key:E-minor')

midi([
  'note Drums kick at:1.1 dur:eighth vel:100',
  'note Bass E2 at:1.1 dur:quarter vel:90',
  'chord Pad Em at:1.1 dur:whole vel:70',
  'crescendo @track:Lead vel:45-75 @range:3.1-6.4',
  'tempo 174 at:11.1',
])

midi_session('save as:./voltage_drop.mid')

Available MCP Tools

Tool

Purpose

midi(ops)

Batch mutations -- notes, chords, tracks, tempo, dynamics, copy/transpose

midi_query(q)

Inspect the composition -- map, tracks, events, piano-roll, instruments, find

midi_session(action)

Lifecycle -- new, open, save, checkpoint, undo, redo

midi_help()

Full reference card

Hero Examples

Plumber's Journey -- Classic game theme faithfully recreated: 4 tracks, 288 notes, 16 seconds, 180 BPM.

Voltage Drop -- A drum-and-bass track with tempo acceleration (140 -> 155 -> 174 BPM), 5 tracks, breakbeats, sub-bass, arpeggios, and a signature DROP section. Also used in the FCP vs raw Python agent battle -- FCP produced 1,674 notes across 12 tracks in 87 seconds, compared to 694 notes from ~689 lines of hand-written Python.

See docs/examples/ for MIDI files and the full writeup.

Installation

Requires Python >= 3.11.

pip install fcp-midi

MCP Client Configuration

{
  "mcpServers": {
    "midi": {
      "command": "uv",
      "args": ["run", "python", "-m", "fcp_midi"]
    }
  }
}

Architecture

Mido-native — no parallel semantic model between the op handlers and the file format:

MCP Server (fcp-core create_fcp_server + MidiAdapter)
  Parses op strings, dispatches to verb handlers, session lifecycle
        |
MidiModel (mido.MidiFile is the source of truth)
  Op handlers read/write mido messages directly on the tracks;
  a NoteIndex gives fast selector lookups. Undo/redo and batch
  atomicity are byte snapshots of the file, not event replay.

Key features:

  • Instrument library -- GM instruments by name (acoustic-grand-piano, synth-bass-1, standard-kit)

  • Soundfont support -- Load custom instrument banks

  • Beat addressing -- at:1.1 (bar 1, beat 1), at:3.2.240 (bar 3, beat 2, tick 240)

  • Duration vocabulary -- whole, half, quarter, eighth, sixteenth, triplet

  • Dynamics -- crescendo, diminuendo across ranges

  • Copy/transpose -- Duplicate and shift musical phrases

Development

uv sync
uv run pytest       # 620 tests
uv run pytest -m "not slow"  # skip stress tests (604 tests, ~0.25s)
uv run ruff check   # linting
uv run pyright      # type checking

License

MIT

Available Tools

4 tools
midiA

Execute midi operations. Each op string follows: VERB TARGET [key:value ...] Call midi_help for the full reference card.

MUSIC: note TRACK PITCH at:POS dur:DUR [vel:V] [ch:N] chord TRACK SYMBOL at:POS dur:DUR [vel:V] [ch:N] track add|remove NAME [instrument:INST] [program:N] [ch:N] [bank:MSB[.LSB]] cc TRACK CC_NAME VALUE at:POS [ch:N] bend TRACK VALUE at:POS [ch:N] tracker TRACK import at:POS [res:RES] ... tracker end

STATE: mute TRACK solo TRACK program TRACK INSTRUMENT|program:N [at:POS] [bank:MSB[.LSB]]

META: tempo BPM [at:POS] time-sig N/D [at:POS] key-sig KEY-MODE [at:POS] marker TEXT at:POS title TEXT

EDITING: remove SELECTORS move SELECTORS to:POS copy SELECTORS to:POS transpose SELECTORS SEMITONES velocity SELECTORS DELTA quantize SELECTORS grid:DUR modify SELECTORS [pitch:P] [vel:V] [dur:D] [at:POS] [ch:N] repeat SELECTORS [to:POS] count:N crescendo SELECTORS from:VEL to:VEL decrescendo SELECTORS from:VEL to:VEL

SELECTORS: @track:NAME @channel:N @range:M.B-M.B @pitch:PITCH @velocity:N-M @all @recent @recent:N @not:TYPE:VALUE Combine to intersect: @track:Piano @range:1.1-4.4

POSITION: M.B (1.1 = start) M.B.T (tick offset) tick:N +DUR -DUR end

DURATION: whole, half, quarter, eighth, sixteenth, 32nd 1n, 2n, 4n, 8n, 16n, 32n dotted-quarter, triplet-eighth, ticks:N

PITCH: C4, D#5, Bb3 (note+accidental+octave) midi:60 (raw MIDI number)

CHORDS: Cmaj, Am, Dm7, G7, Bdim, Faug, Csus4, Asus2 Cmaj7, Am7, Dm7b5, G9, Cm6, Cadd9, Dm/F (slash)

VELOCITY: 0-127 (numeric) ppp, pp, p, mp, mf, f, ff, fff (dynamic names)

CC NAMES: volume, pan, modulation, expression, sustain, reverb, chorus, brightness, portamento, breath

GM INSTRUMENTS (EXAMPLES): acoustic-grand-piano, electric-piano-1, vibraphone acoustic-guitar-nylon, electric-bass-finger, violin trumpet, alto-sax, flute, string-ensemble-1 program:N (raw 0-127) bank:MSB[.LSB]

RESPONSE PREFIXES:

  • note/chord added ~ event modified

  • track modified - event removed ! meta event @ bulk operation

CONVENTIONS:

  • Positions are 1-based: measure 1, beat 1 = 1.1

    • Channels are 1-indexed user-facing (ch:1 through ch:16)

    • Channel 10 is drums (GM standard)

    • Track names are unique identifiers

    • Batch multiple ops in one call for efficiency

    • Call midi_help after context truncation for full reference

Inputs: ops (required).

midi_helpA

Returns the midi reference card with all syntax.

Inputs: no named parameters.

midi_queryD

Query midi state.

Inputs: q (required).

midi_sessionC

Session: 'new "Title"', 'open ./file', 'save', 'checkpoint v1', 'undo', 'redo'

Inputs: action (required).

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    B3.3/5.0

    Scored across 4 tools

    Disambiguation5/5

    Each tool has a clearly distinct role: midi for editing/creating music, midi_query for reading state, midi_session for session/file management, and midi_help for documentation. There is no overlap in their primary purposes.

    Naming Consistency5/5

    All tools follow a consistent 'midi[_suffix]' pattern using snake_case. The base 'midi' denotes the core operation, while suffixes like '_query', '_session', and '_help' clearly indicate auxiliary functions. This is a predictable and uniform convention.

    Tool Count5/5

    With exactly 4 tools, the set is well-scoped and right-sized. The main tool centralizes a rich DSL for MIDI operations, while the supporting tools handle query, session, and help functions. No redundancy or excessive splitting.

    Completeness5/5

    The tool set provides full lifecycle coverage for MIDI work: creating/editing via midi, reading state via midi_query, session control (new/open/save/undo/redo) via midi_session, and reference via midi_help. There are no obvious missing operations within the domain.

    Maintenance

    ActivityInactive
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers