flstudio-mcp
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| FLSTUDIO_MCP_TRANSPORT | No | Transport method: 'tcp' to route through the daemon (recommended for Claude Desktop), omit for direct MIDI. | tcp |
Capabilities
Features and capabilities supported by this server
| Capability | Details |
|---|---|
| tools | {
"listChanged": true
} |
| logging | {} |
| prompts | {
"listChanged": false
} |
| resources | {
"subscribe": false,
"listChanged": false
} |
| extensions | {
"io.modelcontextprotocol/ui": {}
} |
| experimental | {} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| fl_pingA | Check that FL Studio is running and the controller script is loaded. Returns the controller's reported FL Studio version, the age of the last heartbeat in seconds, and the MIDI port names in use. Call this first when something seems wrong. |
| fl_get_tempoA | Return the current FL Studio project tempo in beats per minute. |
| fl_set_tempoA | Set the FL Studio project tempo. Range is 10-999 BPM (FL's own limits). |
| fl_playA | Start playback. Idempotent — calling while already playing is a no-op. |
| fl_stopA | Stop playback. Idempotent. |
| fl_toggle_playA | Toggle between play and stop, mirroring the spacebar in FL. |
| fl_recordA | Toggle FL Studio's record-arm state. |
| fl_get_play_stateA | Return whether FL is currently playing and / or recording. |
| fl_get_song_positionA | Return the current playhead position in beats from the song start. |
| fl_set_song_positionA | Move the playhead to the given beat position. |
| fl_get_project_stateB | Tempo, transport state, pattern/channel/mixer counts. |
| fl_get_mixer_stateA | All mixer tracks (index, name, volume, pan, mute, solo). Names in this overview are truncated; use a single-track read for the full name. |
| fl_get_channel_stateA | All channel-rack channels (index, name, volume, pan, mute, solo). |
| fl_set_mixer_volumeA | Set a mixer track volume. unit='db' uses 0.8=unity (0 dB). |
| fl_set_mixer_panA | Set a mixer track's pan position (-1 left .. +1 right). |
| fl_set_mixer_muteB | Mute or unmute a mixer track (state=True mutes). |
| fl_set_mixer_soloB | Solo or unsolo a mixer track (state=True solos). |
| fl_set_mixer_nameA | Rename a mixer track. |
| fl_set_channel_volumeA | Set a channel-rack channel's volume. unit='db' uses 0.8=unity (0 dB). |
| fl_set_channel_panA | Set a channel-rack channel's pan position (-1 left .. +1 right). |
| fl_set_channel_muteA | Mute or unmute a channel-rack channel (state=True mutes). |
| fl_set_channel_soloA | Solo or unsolo a channel-rack channel (state=True solos). |
| fl_take_snapshotA | Read current state for a scope (for your own before/after diffing). |
| fl_rollback_last_changeA | Undo the most recent write by replaying its pre-change snapshot. |
| fl_set_dry_runA | When on, write tools return a 'planned' preview without changing FL. |
| fl_write_piano_roll_notesA | Write notes into the currently-open FL Piano roll. Each note: {pitch (MIDI), time_bars, length_bars, velocity 0-1}. Set quantize (grid in bars) to snap note starts to a grid before writing. Setup: open the Piano roll and run 'MCP_Apply' once from its Scripting menu (so Ctrl+Alt+Y targets it). mode='replace' clears first. |
| fl_quantize_patternA | Quantize the notes ALREADY in the open Piano roll: reads the score, snaps note starts (and optionally lengths) to the grid, rewrites -- via the pyscript bridge, no dialog. Needs the Piano roll open + MCP_Apply armed once this session (same setup as note writing). |
| fl_plugin_listA | List the filled effect slots (0-9) on a mixer track, with plugin names. We cannot load NEW plugins (FL API limit) -- this only reports plugins already present in the project. |
| fl_plugin_get_paramsA | Every named parameter of the plugin in this slot: index, name, normalised value (0..1) and FL's display string (e.g. '3.6dB', '500Hz'). Returns {"total", "params":[{"i","name","v","s"}, ...]}. |
| fl_plugin_set_paramA | Set one plugin parameter (normalised 0..1). |
| fl_apply_eq_intentA | Apply a musical EQ move on a Fruity Parametric EQ 2 using a free band. Sets type/freq/gain/width as one undo-able group; returns the band used and FL's readback strings. Revert with fl_rollback_last_change. |
| fl_apply_reverb_intentA | Musical reverb moves on a Fruity Reeverb 2 (decay/wet/high-cut), as one undo-able group. Returns readback strings. Revert: fl_rollback_last_change. |
| fl_apply_delay_intentA | Musical delay moves on a Fruity Delay (time division / feedback / wet / feedback-cut), as one undo-able group. Feedback is clamped <=100% unless intensity>0.9 (warns on self-oscillation risk). Returns readback strings. |
| fl_get_track_levelA | Measure a mixer track's level by sampling meter peaks over a short window. Requires PLAYBACK -- returns playing=False (avg/peak null) when stopped/silent. {track, playing, avg_db, peak_db}. |
| fl_apply_compression_intentA | Compress via Fruity Limiter (COMP section) or FabFilter Pro-C. ALWAYS sets ratio AND threshold together; ratio/attack/release/makeup (+ Pro-C Style) per intent, as ONE rollback unit. When level_aware and the track is playing, threshold is set relative to the MEASURED peak (a smart starting point, not exact gain-reduction); stopped -> preset fallback + a note. Returns readback + the measured level / chosen threshold. |
| fl_get_routingA | Which destination tracks this mixer track sends to: {track, name, routes_to:[{dst, dst_name, level?}]}. |
| fl_get_routing_allA | Routing for every mixer track (paginated under the hood, returned whole): {total, routing:[{i, name, routes_to:[...]}]}. |
| fl_get_channel_routingA | Which mixer track each channel-rack channel is linked to: {total, channels:[{channel, name, target_mixer_track, target_name}]}. |
| fl_detect_cleanup_candidatesA | Flag (do NOT touch) empty channels + unused mixer tracks, each with a reason. Judgement is computed server-side from cheap controller reads. Channel emptiness is a name heuristic; unused-track detection is reliable. |
| fl_set_routeA | Enable/disable a send from src -> dst (calls afterRoutingChanged on the FL side). Snapshot + readback; undo with fl_rollback_last_change. |
| fl_group_tracksA | Group sources into a bus, EXCLUSIVELY: each source -> bus ON and its direct -> Master OFF; bus -> Master ON; optional bus rename. Applied as ONE rollback unit -- fl_rollback_last_change undoes the whole grouping. |
| fl_solo_tracksA | Isolate a group so only it is audible -- mutes every OTHER (non-Master) track. Use category ('drums', etc.) or explicit tracks. Implemented as mute-the-rest (reliable; FL's multi-solo is inconsistent). Reverse with fl_clear_mute_solo. One rollback unit. |
| fl_mute_tracksA | Mute a group of tracks (leaves the others as they are). Use category or explicit tracks. One rollback unit; reverse with fl_clear_mute_solo. |
| fl_clear_mute_soloA | Unmute and unsolo every mixer track (reset). The universal undo for the bulk solo/mute tools. |
| fl_set_track_colorA | Set the color of mixer tracks. Pick targets by category ('drums', 'bass', ...) or an explicit tracks list; choose a color by name or hex. All writes are ONE rollback unit -- fl_rollback_last_change reverts them. (Master is never colored.) |
| fl_set_channel_colorA | Set the color of channel-rack channels (separate from mixer-track color). Target by index or name substring. ONE rollback unit -- fl_rollback_last_change reverts it. |
| fl_arrange_new_patternA | Create + select + name the next empty pattern. After this, the note bridge (fl_write_piano_roll_notes) writes INTO this pattern. |
| fl_arrange_select_channelA | Make a channel the active selection so the note bridge (fl_write_piano_roll_notes) writes INTO it. Use before writing each instrument's notes in a section (drums -> ch X, bass -> ch Y, ...). |
| fl_arrange_clone_patternA | Clone a pattern (copies its notes) and rename the clone -- e.g. for verse -> verse2 variations. |
| fl_arrange_add_markerA | Add a named timeline marker at a bar (intro/verse/chorus/drop). |
| fl_analyze_audioA | Estimate tempo + key (+ duration, beats, onsets) of an audio file. Pure offline analysis -- does NOT touch FL. Key is ESTIMATED. |
| fl_extract_melodyA | Transcribe a monophonic melody to quantized notes; engine-selectable (CREPE = accurate/heavy, pyin = light). Returns ALL notes with confidence
|
| fl_write_raga_melodyA | Write a MELODY (single-line, sequential notes) into the selected channel via the piano-roll bridge. YOU (Claude) generate the swaras for the named raga/root -> MIDI notes (use the proper aarohana/avarohana; respect the raga's allowed swaras); this tool only selects the channel + writes. SHOW the user the notes/swaras BEFORE calling. Needs the Piano roll open + MCP_Apply armed once this session (see the note-bridge setup). |
| fl_write_raga_chordsA | Write CHORDS / a progression (stacked notes sharing start times) into the selected channel via the bridge. YOU stack chord tones drawn from the raga/scale (give simultaneous notes the SAME time_bars). Tool selects the channel + writes. SHOW the user the chords BEFORE calling. |
| fl_list_chainsA | List the built-in genre processing-chain recipes (vocal, drum_bus, bass, master) and their ordered steps. |
| fl_list_installed_pluginsA | Read FL's installed-plugin DATABASE from disk (the .fst shortcuts FL writes for every scanned plugin) -> a de-duped, categorized list of what you OWN. Bypasses the FL API (which only sees LOADED plugins). FL still can't LOAD these -- it's for library-aware suggestions. effects_by_role is a rough keyword grouping (Claude should apply its own plugin knowledge). Read-only (directory listing only). |
| fl_setup_chainA | Plan a genre-appropriate processing chain over a track's EXISTING plugins. READ-ONLY plan: returns the ordered intent calls (each with the matched plugin + slot) and which steps are MISSING because the needed plugin isn't loaded (FL can't load plugins -- add those manually). After the user approves, apply each step by calling its 'apply' tool+args (fl_apply_eq_intent / fl_apply_compression_intent / fl_apply_reverb_intent -- each logged + rollback-able). e.g. vocal: HP -> comp -> presence -> air -> reverb. |
| fl_export_midiA | Write a type-1 multi-track .mid from an arrangement spec. YOU (Claude) generate the whole arrangement -- multiple named tracks, each with notes {pitch, start_bars, length_bars, velocity} across all sections -- and this writes ONE .mid. Bypasses the note-bridge's one-pattern + MCP_Apply limits. Does NOT touch FL: IMPORT the file yourself (FL: File > Import > MIDI file, or drag it into the playlist). FL won't auto-load instruments -- assign a channel to each imported track. Returns the saved file path. |
| fl_list_presetsA | Read preset NAMES from disk: FL Presets\ (per-plugin 'Plugin presets', plus Channel/Mixer presets) + Serum 2 Presets (.serumpreset). With NO filter -> a SUMMARY (which plugins have presets + counts). With plugin_filter -> that plugin's full preset list. Read-only. FL can't LOAD presets via the API -- this is for suggestions (you load the named preset, then Claude can tweak it). |
| fl_suggest_presetA | Suggest presets from YOUR library matching a description, for a given plugin. Reads the plugin's preset NAMES from disk + ranks by name match. Name-only (can't hear the sound) -- apply your own knowledge of preset naming. FL can't LOAD presets via the API: recommend which to load in the plugin manually; AFTER the user loads it you can tweak its params via fl_plugin_set_param / fl_apply_*_intent. |
| fl_diagnose_mixA | Scan the WHOLE mix and report problems + proposed fixes. READ-ONLY. Transparent threshold rules (clipping, headroom, level imbalance, missing high-pass, ungrouped tracks, EQ clashes) on a thin paginated snapshot; returns findings (severity + exact evidence) + concrete proposals. IMPORTANT: this samples peaks over only ~1.2s -- one MOMENT of the song, so it can MISS clipping in a drop/chorus that isn't playing right now. For full-song-accurate levels use WATCH mode: fl_mix_watch_start -> play the whole song -> fl_mix_watch_stop. If stopped, level rules are skipped (needs_playback). Applies nothing. |
| fl_apply_mix_fixA | Apply ONE Mix Doctor fix via the safety layer: snapshot -> write -> FRESH readback -> rollback-able with fl_rollback_last_change. Call this ONLY after the user approves the exact change in conversation (Mix Doctor never auto-applies). 'trim_volume' sets a mixer track's fader to target_db. For grouping use fl_group_tracks; for EQ use fl_apply_eq_intent. |
| fl_mix_watch_startA | Begin a peak-HOLD watch: continuously sample every mixer track's peak, keeping a RUNNING MAX per track, until fl_mix_watch_stop. Tell the user to PLAY the whole song (or at least the loudest section / the drop) while this runs -- then stop for full-song-accurate level diagnosis. Read-only. |
| fl_mix_watch_statusA | Is a peak watch running, and for how long / how many polls so far? |
| fl_mix_watch_stopA | Stop the peak watch and diagnose on the FULL-SONG running-max peaks captured across the whole watch (accurate clipping/headroom/imbalance vs the ~1.2s snapshot). Read-only -- proposes fixes, applies nothing. |
| fl_gain_stageA | Propose per-track fader trims so each track's peak sits in a healthy band (~-12..-6 dBFS, aim -9) and the Master keeps -3..-6 dB headroom. READ-ONLY proposals -- apply approved ones via fl_apply_mix_fix (rollback). Uses FULL-SONG peaks from a recent watch (fl_mix_watch_start -> play -> fl_mix_watch_stop) when available; else a ~1.2s snapshot (prefer watch). FL's fader is POST-chain, so this sets a track's OUTPUT level, not a true pre-plugin input trim. |
| fl_reference_matchA | Compare your mix's LEVEL + rough tonal BALANCE to a reference track. READ-ONLY. Analyzes the reference FILE (overall level + low/mid/high spectral-band shares) and your mix (Master peak for level + a ROUGH name-based band estimate). HONEST: a level/balance compare, NOT a spectral match -- FL doesn't expose its output audio, so the your-mix balance is estimated from track names + peaks. Suggests adjustments; applies nothing. |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
No prompts | |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
| status | Bridge alive + a cheap transport/tempo snapshot. |
| project | Tempo, transport, and channel/mixer/pattern counts. |
| transport | Live transport: playing/recording, song position, tempo. |
| channels | Channel-rack summary (name + vol/pan/mute/solo), capped. |
| mixer | Mixer-track summary (name + vol/pan/mute/solo), capped. |
| patterns | Pattern list (1-based index + name), capped. |
Latest Blog Posts
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/rosasynthesiz/flstudio-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server