FL Studio MCP
by LunarTrout
README.md
# flstudio-mcp
**English** · [Русский](README.ru.md)
An MCP server that lets an AI agent drive **FL Studio 2025** end to end: read the project,
measure the mix, move faders and plugin parameters, insert effects, write notes, diagnose a
mix and verify the result — through natural language, without screenshots and without
clicking.
It is the bridge between three worlds:
```
FL Studio ── MIDI-script controller ──▶ TCP bridge (127.0.0.1:9787)
│
▼
MCP server (stdio, this repo)
│
▼
Claude / Hermes / any MCP client
```
The controller runs inside FL as a MIDI scripting device. The bridge is a small daemon that
multiplexes requests. The MCP server exposes the tool surface and speaks MCP over stdio.
---
## Contents
- [What it can do](#what-it-can-do)
- [Requirements](#requirements)
- [Install](#install)
- [Configure the MCP client](#configure-the-mcp-client)
- [Tool surface](#tool-surface)
- [Typical workflows](#typical-workflows)
- [Safety model](#safety-model)
- [How it relates to flctrl](#how-it-relates-to-flctrl)
- [Troubleshooting](#troubleshooting)
- [Repository layout](#repository-layout)
- [License](#license)
---
## What it can do
| Area | Examples |
|---|---|
| Project overview | tempo, transport state, track and channel counts, routing |
| Mixer | volume, pan, mute/solo per track, routing, grouping into buses, naming, colours |
| Metering | per-track level sampling, peak-hold watching, mix diagnosis |
| Plugins | list filled slots, read every named parameter, set parameters, suggest presets |
| Processing | apply EQ / compression / delay / reverb intents, genre chains |
| Composition | write notes into the piano roll, chord progressions, melodies, clone patterns |
| Arrangement | markers, pattern selection, MIDI export |
| Analysis | tempo/key estimation from audio, melody extraction, reference matching |
| Safety | snapshots, rollback of the last change, dry-run preview, gain staging |
Everything is done through FL's own state — no screen scraping, no synthetic clicks.
## Requirements
- Windows 10/11 (FL Studio is Windows-first; the controller and bridge assume Windows paths)
- FL Studio 2025 or newer
- Python 3.10+ for the MCP server
- An MCP client (Claude Desktop, Hermes, or anything that speaks MCP over stdio)
## Install
```bash
git clone https://github.com/rosasynthesiz/flstudio-mcp
cd flstudio-mcp
# server environment
uv venv
uv pip install --python .venv/Scripts/python.exe -e .
# bridge daemon (same environment is fine)
./.venv/Scripts/python.exe -m fl_studio_mcp.bridge # or start-daemon.bat
```
Then, inside FL Studio:
1. Options → MIDI settings → enable the **FLStudioMCP** input and output ports (loopMIDI
ports with those names).
2. Set the controller script for that device to `fl_controller/device_FLStudioMCP.py`.
3. Confirm the bridge is listening: `netstat -ano | findstr 9787`.
The exact MIDI device registration can also be written directly to
`HKCU\Software\Image-Line\FL Studio 25\Devices\MIDI input\<port>` (`Port`, `Enabled`,
`ScriptFolder`), which is what the setup scripts in `fl_controller/` do.
## Configure the MCP client
```json
{
"mcpServers": {
"fl-studio": {
"command": "C:/path/to/flstudio-mcp/.venv/Scripts/python.exe",
"args": ["-m", "fl_studio_mcp.server"]
}
}
}
```
For Hermes, add the same block to the MCP servers section of its configuration and restart
the session. The tools then appear as `mcp__fl_studio__*`.
## Tool surface
The server exposes the FL Studio tool set grouped by intent. Names below are the MCP tool
names without the `mcp__fl_studio__` prefix.
**Read**
`fl_ping`, `fl_get_project_state`, `fl_get_tempo`, `fl_get_play_state`,
`fl_get_song_position`, `fl_get_mixer_state`, `fl_get_channel_state`,
`fl_get_channel_routing`, `fl_get_routing`, `fl_get_routing_all`,
`fl_plugin_list`, `fl_plugin_get_params`, `fl_list_presets`,
`fl_list_installed_plugins`, `fl_list_chains`
**Mix moves**
`fl_set_mixer_volume`, `fl_set_mixer_pan`, `fl_set_mixer_mute`, `fl_set_mixer_solo`,
`fl_set_channel_volume`, `fl_set_channel_pan`, `fl_set_channel_mute`,
`fl_set_channel_solo`, `fl_set_mixer_name`, `fl_set_track_color`,
`fl_set_channel_color`, `fl_set_route`, `fl_group_tracks`, `fl_solo_tracks`,
`fl_mute_tracks`, `fl_clear_mute_solo`, `fl_gain_stage`
**Measure**
`fl_get_track_level`, `fl_mix_watch_start`, `fl_mix_watch_status`, `fl_mix_watch_stop`,
`fl_diagnose_mix`, `fl_reference_match`, `fl_detect_cleanup_candidates`
**Processing**
`fl_plugin_set_param`, `fl_apply_eq_intent`, `fl_apply_compression_intent`,
`fl_apply_delay_intent`, `fl_apply_reverb_intent`, `fl_setup_chain`,
`fl_apply_mix_fix`, `fl_suggest_preset`
**Composition**
`fl_arrange_new_pattern`, `fl_arrange_clone_pattern`, `fl_arrange_select_channel`,
`fl_arrange_add_marker`, `fl_write_piano_roll_notes`, `fl_write_raga_melody`,
`fl_write_raga_chords`, `fl_quantize_pattern`, `fl_extract_melody`,
`fl_export_midi`
**Transport and safety**
`fl_play`, `fl_stop`, `fl_toggle_play`, `fl_record`, `fl_set_song_position`,
`fl_take_snapshot`, `fl_rollback_last_change`, `fl_set_dry_run`,
`fl_analyze_audio`
The companion library `flctrl` (see [How it relates to flctrl](#how-it-relates-to-flctrl))
adds the measurement layer: per-track live capture, the tape, events, masking, provenance.
## Typical workflows
**Diagnose and fix a mix**
```
fl_ping → bridge alive?
fl_get_mixer_state → what tracks exist
fl_diagnose_mix → problems + proposed fixes
fl_apply_mix_fix(fix_id) → snapshot → apply → verify
fl_rollback_last_change → if the numbers got worse
```
**Balance by numbers**
```
fl_gain_stage → propose per-track trims so peaks sit in a target window
fl_get_track_level → verify each track
fl_reference_match → compare level and tonal balance with a reference file
```
**Write a part**
```
fl_arrange_select_channel
fl_write_raga_melody / fl_write_piano_roll_notes
fl_quantize_pattern
```
## Safety model
- **Dry run.** `fl_set_dry_run(true)` makes write tools return a plan instead of touching FL.
- **Snapshots and rollback.** `fl_take_snapshot` records state; `fl_rollback_last_change`
replays the pre-change values.
- **One change at a time.** Parameter writes are queued with pauses — bursts crash FL's
engine (see the library's `docs/RULES.md`, rule 1).
- **No synthetic clicks in dialogs.** FL's DirectUI export dialogs crash under synthetic
input; automation stays on the API and the CLI.
## How it relates to flctrl
Two repositories, two layers:
| Repository | Layer | Responsibility |
|---|---|---|
| `flstudio-mcp` (this one) | control | tools, bridge, FL controller, mix moves |
| `flctrl` | measurement | live per-track capture, the tape, events, frames, reference work |
`flctrl` exposes its own compact ten-tool MCP surface (`fl_help`, `fl_list`, `fl_get`,
`fl_set`, `fl_call`, `fl_measure`, `fl_compare`, `fl_undo`, `fl_dry_run`, `fl_project`) for
agents that prefer a small, generic interface over a large, specific one. Both talk to the
same bridge on port 9787 and can be used together: `flstudio-mcp` to act, `flctrl` to hear.
## Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| `fl_ping` times out | bridge not running, or FL's controller not loaded | start the daemon; check MIDI settings |
| Tools work but FL does not move | controller script not attached to the device | set the script for the FLStudioMCP input |
| FL freezes during a batch of writes | too many parameter writes in a row | use batch helpers with pauses |
| Export/render dialogs hang | synthetic input into DirectUI | do export manually or via CLI |
| Mixer changes disappear | project reloaded from disk | save points, see `flctrl` |
## Repository layout
```
fl_controller/ FL MIDI-script device (runs inside FL)
fl_pyscripts/ helper scripts executed through the controller
src/fl_studio_mcp/ server, bridge, tools
docs/ reports, calibration notes, this documentation
scripts/ setup helpers (MIDI registration, environment)
start-daemon.bat convenience launcher for the bridge
server.json MCP registry metadata
```
## License
MIT — see [LICENSE](LICENSE).