Skip to main content
Glama

flstudio-mcp

Control FL Studio with Claude: AI mixing, composition, and mix diagnosis through natural language.

PyPI status license python platform FL Studio

Claude diagnosing and fixing a mix in FL Studio

Claude diagnosing and fixing a mix in FL Studio through natural language.

Overview

flstudio-mcp is a Model Context Protocol (MCP) server that lets Claude (Claude Code or Claude Desktop) drive FL Studio 2025 directly — the mixer, plugins, piano roll, routing, and project — from plain-language requests. Ask for a mix diagnosis, a vocal chain, a chord progression in a particular scale, or a full arrangement, and Claude carries it out through FL's scripting API and a set of calibrated, safety-checked tools.

It is genre- and producer-agnostic: nothing about it assumes a particular style of music.

Related MCP server: FL Studio MCP Server

Quickstart

For a new FL Studio setup, clone the repository so the controller and installer scripts are available:

git clone https://github.com/rosasynthesiz/flstudio-mcp.git
cd flstudio-mcp

Then run the installer for your OS. It installs the server into its environment, copies the FL controller, and seeds the note bridge:

:: first: in loopMIDI, create two ports named exactly "FLStudioMCP RX" and "FLStudioMCP TX"
scripts\install_windows.bat              :: controller + server (.venv) + note bridge
scripts\start_daemon.bat                 :: start the bridge in its own window, keep it open
./scripts/install_macos.sh         # macOS: controller + server + note bridge
fl-studio-mcp-daemon               # start the bridge, keep it running

Wire the two virtual MIDI ports in FL (loopMIDI on Windows, IAC Driver on macOS), arm MCP_Apply once in the piano roll, then ask Claude in plain language:

"Scan my mix and tell me what's wrong." — "Set up a vocal chain from my plugins." — "Export this arrangement to MIDI."

Full setup is below.

For an environment whose FL controller and MIDI bridge are already configured, the server package is also available from PyPI:

python -m pip install fl-studio-mcp

The PyPI package does not replace the controller/port setup above. The current main branch may contain changes that have not yet been released to PyPI.

Capabilities

Mixing & diagnosis

  • Mix Doctor — scans the whole mix and reports concrete problems (clipping, low headroom, level imbalance, missing high-pass, ungrouped related tracks, overlapping EQ boosts), each with the exact evidence and a proposed fix. Fixes are applied one at a time, only on approval, through a snapshot → write → readback → rollback safety layer. Master clipping is resolved by trimming the contributing source tracks rather than pulling the master.

  • Full-song peak watch — holds a running peak per track across playback, so level decisions are based on the loudest moment of the actual song, not a single instant.

  • Calibrated processing intents — musical EQ, compression, reverb, and delay moves mapped to real plugin parameters (native and third-party), each applied as one reversible change.

  • Level-aware compression — sets thresholds relative to a track's measured level during playback.

  • Gain staging — proposes per-track trims toward a healthy level with proper master headroom.

  • Reference match — compares your mix's level and tonal balance against a reference track.

  • Bulk track control — solo or mute a whole group (drums, vocals, …) in one step, with a one-call reset.

  • Track & channel coloring — color a track, a channel, or a whole group (drums, vocals, …) by color name or hex, reversible like every other change.

Plugin & preset control

  • Read and set plugin parameters by name, on native and third-party plugins (the parameter list is resolved live).

  • Verified writes — every parameter write is re-read on a fresh tick and retried (0.4 s apart) if FL did not take it; the answer carries verified / attempts and a hint, so a swallowed write is reported instead of echoed back as if it worked.

  • Batch parameter changes — fl_plugin_set_params sets several knobs of one plugin in a single paced burst and one undo step; fl_rollback_last_change puts them all back together.

  • Chain suggestions and preset recommendations drawn from your actual installed library — read directly from FL's plugin database and preset folders on disk, so recommendations are limited to what you own.

Composition

  • Multi-track MIDI export — generate a complete arrangement as a standard MIDI file to import.

  • Multi-pattern arrangement — create, name, clone, and mark sections.

  • Drum patterns in the step sequencer: read or set a channel's steps in the current pattern, e.g. x...x...x...x..., reversible like every other change.

  • Note and chord writing into the piano roll, with quantize to a grid (for new notes and existing ones).

  • Composition in any scale or mode — Western modes, pentatonic, ragas, maqam, and beyond — through the scale composer, where Claude supplies the notes for the requested scale.

Audio analysis

  • Tempo and key estimation from an audio file.

  • Melody-to-MIDI transcription (CREPE pitch tracking, with a lighter fallback).

  • Chords-to-MIDI transcription of polyphonic audio (keys, piano, guitar) with Spotify's Basic Pitch, as notes for the piano roll or a .mid file.

  • Drums to MIDI: a drum loop or stem to kick, snare, clap, closed and open hi-hat, aligned to the beat, as a .mid or straight into the step sequencer of the channels you choose (one undo step).

The server exposes 72 tools across 14 categories, plus 6 live resources (project, mixer, transport, channels, patterns, status) that Claude can read directly.

What sets it apart

flstudio-mcp is built as a mixing and production assistant, not only a note sender. It diagnoses and repairs a whole mix, makes decisions from real measured levels rather than guesswork, and is aware of your actual plugin and preset library when it makes suggestions. Every change that touches the project is shown before it is applied, logged, and reversible.

Limitations

These are properties of FL Studio's scripting API, stated plainly:

  • Plugins, audio files, and rendering are UI-only. FL's API cannot load a plugin, load an audio file, or render audio. The plugin and preset tools therefore suggest — you load the chosen plugin or preset, and Claude then configures it. Audio export is done manually (File > Export); Claude can analyze the rendered file afterward.

  • Only some plugin parameters accept arbitrary values. Levels and gains do; stepped parameters (filter types, orders, selectors) snap to their own grid steps, so an off-grid request cannot land; some parameters (Fruity Parametric EQ 2's band widths) ignore writes entirely. The parameter tools re-read and retry, then report verified: false with a hint and the value FL actually holds, instead of echoing the request as if it had landed.

  • Note writing is armed once per session. A generated pyscript writes notes into the piano roll; FL exposes no API to run a pyscript, so you run "MCP_Apply" once from the piano roll's scripting menu at the start of a session.

  • Micro-tonal and gamaka-heavy music is approximated. Scales with intervals smaller than a semitone (e.g. Arabic maqam) are rounded to the nearest semitone, and traditions built on gamaka/ornamentation (e.g. Carnatic) get the scale framework — the correct swaras and intervals — not gamaka or micro-tonal rendering. That's a limit of 12-tone MIDI, not of the tools.

Requirements

  • Windows 10/11 (tested on Windows 11) or macOS

  • FL Studio 2025 or newer

  • Claude Code or Claude Desktop (or any MCP client)

  • Python 3.10+

  • Virtual MIDI ports:

    • Windows: loopMIDI (download)

    • macOS: the built-in IAC Driver

  • Optional: ffmpeg on PATH (for MP3 analysis)

Linux is not yet supported — contributions welcome.

Setup

  1. Create two virtual MIDI ports, named exactly FLStudioMCP RX and FLStudioMCP TX. These are the "cables" between the MCP server and FL Studio: one carries commands into FL (RX), the other carries answers back (TX). Do this before running the installer, because it checks for them.

    Windows (loopMIDI):

    • Install and open loopMIDI.

    • If the list already holds ports with default names (loopMIDI Port, loopMIDI Port 1, …), select them and click − to remove them. The default names will not be detected.

    • In the New port-name box at the bottom, type FLStudioMCP RX and click +.

    • Type FLStudioMCP TX and click + again.

    • Keep loopMIDI running (it can start with Windows from its tray icon); the ports exist only while it runs.

    macOS:

    • Open Audio MIDI Setup.

    • Choose Window > Show MIDI Studio.

    • Double-click IAC Driver.

    • Enable Device is online.

    • Create or rename two ports exactly:

      • FLStudioMCP RX

      • FLStudioMCP TX

  2. Install the controller script and server:

    Windows:

    git clone https://github.com/rosasynthesiz/flstudio-mcp
    cd flstudio-mcp
    scripts\install_windows.bat

    macOS:

    git clone https://github.com/rosasynthesiz/flstudio-mcp
    cd flstudio-mcp
    chmod +x scripts/install_macos.sh
    ./scripts/install_macos.sh

    This copies the controller script, seeds the note-bridge pyscript (MCP_Apply), installs the server, and checks that your virtual MIDI ports exist.

    On Windows the server is installed into a .venv folder inside the repo, using Python 3.12/3.11/3.10 when available (the MIDI library has no working build for newer Pythons on Windows). The installer prints the full paths of the commands to use in the next steps. It finds your Documents folder even when it is redirected (OneDrive, non-English names). All FL Studio versions (2024, 2025, 2026, …) share one user-data folder, so one install covers them all. It also follows FL's own "User data folder" setting; if it still can't find the folder, run setx FL_SETTINGS "<folder>\FL Studio\Settings" once and open a new terminal (the installer and the daemon both use it).

    Both installers ask two optional questions (re-run the installer any time to add them):

    1. Audio analysis (about 100 MB, no AI models): tempo and key detection, drums to MIDI, light melody to MIDI, reference match.

    2. AI audio to MIDI (about 650 MB, downloads AI models): accurate melody to MIDI with CREPE, full chords with Spotify's Basic Pitch.

    To answer without the prompts, set FLMCP_EXTRAS first: all, none, or any of audio accurate chords.

    Manual install or picking parts (Windows: .venv\Scripts\pip):

    pip install -e ".[audio]"                    # tempo/key + light melody
    pip install -e ".[audio,audio-accurate]"     # + CREPE (accurate melody)
    pip install -e ".[audio-chords]"             # chords: then also run
    pip install --no-deps basic-pitch==0.4.0     #   (skips its TensorFlow requirement)
  3. Configure FL Studio — Options > MIDI Settings:

    • Enable FLStudioMCP RX as an input, set its controller type to FLStudioMCP, and give it a port number.

    • Select FLStudioMCP TX in the output list and give it the same port number. Outputs have no Enable button; setting the port is what activates it. Leave Send master sync off.

    • View > Script output should show [FLStudioMCP] Ready.

  4. Start the bridge daemon (recommended) so the MIDI port is held by a stable process:

    scripts\start_daemon.bat                 :: Windows: double-click, keep the window open
    fl-studio-mcp-daemon                     # macOS
  5. Register the server with Claude Code or Claude Desktop. On Windows, use the full ...\.venv\Scripts\fl-studio-mcp.exe path the installer printed instead of fl-studio-mcp.

    Claude Code: just ask Claude, for example:

    Add the fl-studio MCP server for all my projects: <path to fl-studio-mcp> with env FLSTUDIO_MCP_TRANSPORT=tcp

    Claude Desktop, add it to the config file:

    Windows: %APPDATA%\Claude\claude_desktop_config.json

    macOS: ~/Library/Application Support/Claude/claude_desktop_config.json

    {
      "mcpServers": {
        "fl-studio": {
          "command": "fl-studio-mcp",
          "env": { "FLSTUDIO_MCP_TRANSPORT": "tcp" }
        }
      }
    }

    tcp routes through the daemon, which works regardless of how Claude launches the server. Omit the env var to let the server open the MIDI ports directly instead.

  6. Arm the note bridge (per session) — open the piano roll and choose Tools > Scripting > MCP > MCP Apply from its menu once, so note-writing works.

    On macOS, the note bridge re-triggers the armed script with Cmd+Opt+Y. Grant Accessibility permission to the app running the MCP server or daemon, for example Terminal, iTerm, Claude Desktop, or Cursor: System Settings > Privacy & Security > Accessibility.

Verify the connection by asking Claude to call fl_ping.

After updating an existing installation, restart the bridge daemon and reconnect your MCP client so both processes load the new source. Dry-run is scoped to one MCP server process and resets on reconnect. See bridge correctness regressions for numeric JSON compatibility, dry-run behavior, and localized parameter names.

Troubleshooting

Symptom

Fix

Virtual MIDI ports not found / not detected

The two ports must be named exactly FLStudioMCP RX and FLStudioMCP TX. loopMIDI's default loopMIDI Port names won't work. Recreate them in loopMIDI (Windows) or IAC Driver (macOS), make sure loopMIDI is running, then re-run the installer.

FL Studio Settings\Hardware folder not found

Open FL Studio once so it creates its user-data folder. If you moved that folder (Options > File settings > User data folder), setx FL_SETTINGS "<that folder>\FL Studio\Settings", open a new terminal and re-run.

fl-studio-mcp-daemon is not recognized

The commands live in the repo's .venv\Scripts\ folder. Run them by full path (the installer prints it).

Python crashes on start / MIDI library fails to load (Windows)

Install Python 3.12 from python.org, delete the .venv folder, and re-run the installer.

No [FLStudioMCP] Ready in FL's Script output

The controller isn't registered: set the FLStudioMCP RX input's Controller type to FLStudioMCP in MIDI Settings, confirm device_FLStudioMCP.py is in Settings\Hardware\FLStudioMCP\, then fully restart FL Studio.

Claude can't reach FL / fl_ping fails

Make sure the daemon is running (fl-studio-mcp-daemon); check the transport matches (FLSTUDIO_MCP_TRANSPORT=tcp uses the daemon, unset uses direct MIDI); restart Claude Desktop after editing its config, or run /mcp in Claude Code to reconnect.

fl_ping says the heartbeat is stale (Ready is shown, but FL stops answering)

Usually happens after changing MIDI Settings while the script is running. Open View > Script output, select the FLStudioMCP tab and click Reload script (or restart FL Studio). Also check that the Output port number is on FLStudioMCP TX, not FLStudioMCP RX.

Note-writing does nothing

Run MCP_Apply once from the piano roll's scripting menu this session — it arms the note bridge.

macOS note-trigger fails

Grant Accessibility permission to the app running the MCP server or daemon, then click the FL Piano roll and try Cmd+Opt+Y.

Audio tools error or are unavailable

Re-run the installer and answer Y to "Install audio to MIDI?" (or install the extras manually, see Setup step 2).

The installer stops because the MCP server is running

Claude Desktop or Claude Code is running fl-studio-mcp.exe from the .venv, which locks its files. Quit Claude Desktop or Claude Code, then re-run.

Usage examples

Plain-language prompts:

  • "Scan my mix and tell me what's wrong."

  • "Set up a vocal chain on the lead vocal using my plugins."

  • "Suggest a vintage bass preset from my Serum library."

  • "Compose an 8-bar melody in D Dorian and write it to the selected channel."

  • "Export this arrangement to a MIDI file."

  • "What tempo and key is this track?" (on an audio file)

Architecture

A thin controller script runs inside FL Studio and returns only cheap, raw data; all judgement — diagnosis, calibration, planning — happens server-side. A standalone daemon owns the MIDI port so the server works regardless of how the MCP client is launched. Note authoring uses a generated pyscript bridge: the daemon re-triggers the armed MCP_Apply script with the platform run-last-script shortcut after a brief window force-focus. Every project-modifying tool routes through a snapshot → write → readback → rollback safety layer backed by a persisted change log.

Design notes and findings are in docs/.

License

MIT — see LICENSE.

Status & contributing

Beta — the public 1.0 release. Windows and macOS are supported; Linux contributions are welcome. Issues and pull requests: github.com/rosasynthesiz/flstudio-mcp.

Available Tools

67 tools
fl_analyze_audioAnalyze audio (tempo/key)A
Read-onlyIdempotent

Estimate tempo + key (+ duration, beats, onsets) of an audio file. Pure offline analysis -- does NOT touch FL. Key is ESTIMATED.

Inputs: path (required). Returns: object

fl_apply_compression_intentApply a 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.

Inputs: track (required), slot (required), intent (required), intensity, +1 more. Returns: object

fl_apply_delay_intentApply a 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.

Inputs: track (required), slot (required), intent (required), intensity. Returns: object

fl_apply_eq_intentApply an EQ mixing 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.

Inputs: track (required), slot (required), intent (required), intensity. Returns: object

fl_apply_mix_fixApply a Mix Doctor fix (gated)A

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.

Inputs: kind (required), track, target_db. Returns: object

fl_apply_reverb_intentApply a 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.

Inputs: track (required), slot (required), intent (required), intensity. Returns: object

fl_arrange_add_markerAdd a section marker at a barA

Add a named timeline marker at a bar (intro/verse/chorus/drop).

Inputs: bar (required), name (required). Returns: object

fl_arrange_clone_patternClone a pattern (copies notes)A

Clone a pattern (copies its notes) and rename the clone -- e.g. for verse -> verse2 variations.

Inputs: src (required), new_name (required). Returns: object

fl_arrange_new_patternNew named pattern (selects it)A

Create + select + name the next empty pattern. After this, the note bridge (fl_write_piano_roll_notes) writes INTO this pattern.

Inputs: name (required). Returns: object

fl_arrange_select_channelSelect channel (note-bridge target)A

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, ...).

Inputs: channel (required). Returns: object

fl_clear_mute_soloClear all mutes + solosA

Unmute and unsolo every mixer track (reset). The universal undo for the bulk solo/mute tools.

Inputs: no named parameters. Returns: object

fl_detect_cleanup_candidatesDetect cleanup candidates (read-only)A
Read-onlyIdempotent

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.

Inputs: no named parameters. Returns: object

fl_diagnose_mixDiagnose the mix (Mix Doctor)A
Read-onlyIdempotent

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.

Inputs: no named parameters. Returns: object

fl_export_midiExport arrangement to .midA

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.

Inputs: tracks (required), bpm, output_path, beats_per_bar. Returns: object

fl_extract_melodyExtract melody from audio (pyin/CREPE)A
Read-onlyIdempotent

Transcribe a monophonic melody to quantized notes; engine-selectable (CREPE = accurate/heavy, pyin = light). Returns ALL notes with confidence

  • a kept flag; bridge_notes holds only the confident notes, ready for fl_write_piano_roll_notes. Does NOT write to FL -- review first.

Inputs: path (required), bpm, engine, min_conf. Returns: object

fl_gain_stageGain staging assistant (Mix Doctor)A
Read-onlyIdempotent

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.

Inputs: no named parameters. Returns: object

fl_get_channel_routingGet channel->mixer routingA
Read-onlyIdempotent

Which mixer track each channel-rack channel is linked to: {total, channels:[{channel, name, target_mixer_track, target_name}]}.

Inputs: no named parameters. Returns: object

fl_get_channel_stateGet channel stateA
Read-onlyIdempotent

All channel-rack channels (index, name, volume, pan, mute, solo).

Inputs: no named parameters. Returns: object

fl_get_mixer_stateGet mixer stateA
Read-onlyIdempotent

All mixer tracks (index, name, volume, pan, mute, solo). Names in this overview are truncated; use a single-track read for the full name.

Inputs: no named parameters. Returns: object

fl_get_play_stateGet play stateA
Read-onlyIdempotent

Return whether FL is currently playing and / or recording.

Inputs: no named parameters. Returns: object

fl_get_project_stateGet project stateB
Read-onlyIdempotent

Tempo, transport state, pattern/channel/mixer counts.

Inputs: no named parameters. Returns: object

fl_get_routingGet mixer track routingA
Read-onlyIdempotent

Which destination tracks this mixer track sends to: {track, name, routes_to:[{dst, dst_name, level?}]}.

Inputs: track (required). Returns: object

fl_get_routing_allGet full routing matrixA
Read-onlyIdempotent

Routing for every mixer track (paginated under the hood, returned whole): {total, routing:[{i, name, routes_to:[...]}]}.

Inputs: no named parameters. Returns: object

fl_get_song_positionGet song position (beats)A
Read-onlyIdempotent

Return the current playhead position in beats from the song start.

Inputs: no named parameters. Returns: object

fl_get_tempoGet tempo (BPM)A
Read-onlyIdempotent

Return the current FL Studio project tempo in beats per minute.

Inputs: no named parameters. Returns: object

fl_get_track_levelGet track level (dB)A
Read-onlyIdempotent

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}.

Inputs: track (required), samples. Returns: object

fl_group_tracksGroup tracks into a busA
Idempotent

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.

Inputs: sources (required), bus (required), name. Returns: object

fl_list_chainsList genre chainsA
Read-onlyIdempotent

List the built-in genre processing-chain recipes (vocal, drum_bus, bass, master) and their ordered steps.

Inputs: no named parameters. Returns: object

fl_list_installed_pluginsList installed plugins (FL DB on disk)A
Read-onlyIdempotent

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).

Inputs: kind. Returns: object

fl_list_presetsList presets (from disk)A
Read-onlyIdempotent

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).

Inputs: plugin_filter. Returns: object

fl_mix_watch_startStart full-song peak watch (Mix Doctor)A
Read-onlyIdempotent

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.

Inputs: interval_ms. Returns: object

fl_mix_watch_statusPeak watch status (Mix Doctor)A
Read-onlyIdempotent

Is a peak watch running, and for how long / how many polls so far?

Inputs: no named parameters. Returns: object

fl_mix_watch_stopStop peak watch + diagnose (Mix Doctor)A
Read-onlyIdempotent

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.

Inputs: no named parameters. Returns: object

fl_mute_tracksMute a group of 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.

Inputs: category, tracks. Returns: object

fl_pingPing FL StudioA
Read-onlyIdempotent

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.

Inputs: no named parameters. Returns: object

fl_playPlayA
Idempotent

Start playback. Idempotent — calling while already playing is a no-op.

Inputs: no named parameters. Returns: object

fl_plugin_get_paramsGet plugin parametersA
Read-onlyIdempotent

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"}, ...]}.

Inputs: track (required), slot (required). Returns: object

fl_plugin_listList plugins on a mixer trackA
Read-onlyIdempotent

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.

Inputs: track (required). Returns: object

fl_plugin_set_paramSet plugin parameterA
Idempotent

Set one plugin parameter (normalised 0..1). param may be an index or a name; names are resolved from the live param list. The change is logged and undo-able via fl_rollback_last_change. Returns before/after plus the resolved {index, name}.

Inputs: track (required), slot (required), param (required), value (required). Returns: object

fl_quantize_patternQuantize piano-roll notesA

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).

Inputs: grid_bars, snap_ends. Returns: object

fl_recordToggle recordA
Destructive

Toggle FL Studio's record-arm state.

Inputs: no named parameters. Returns: object

fl_reference_matchReference match (level/balance)A
Read-onlyIdempotent

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.

Inputs: reference_audio_path (required). Returns: object

fl_rollback_last_changeRollback last changeA
Destructive

Undo the most recent write by replaying its pre-change snapshot.

Inputs: no named parameters. Returns: object

fl_set_channel_colorColor channelsA

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.

Inputs: color (required), channels. Returns: object

fl_set_channel_muteSet channel muteA
Idempotent

Mute or unmute a channel-rack channel (state=True mutes).

Inputs: channel (required), state (required). Returns: object

fl_set_channel_panSet channel panA
Idempotent

Set a channel-rack channel's pan position (-1 left .. +1 right).

Inputs: channel (required), value (required). Returns: object

fl_set_channel_soloSet channel soloA
Idempotent

Solo or unsolo a channel-rack channel (state=True solos).

Inputs: channel (required), state (required). Returns: object

fl_set_channel_volumeSet channel volumeA
Idempotent

Set a channel-rack channel's volume. unit='db' uses 0.8=unity (0 dB).

Inputs: channel (required), value (required), unit. Returns: object

fl_set_dry_runSet dry-run modeA
Idempotent

When on, write tools return a 'planned' preview without changing FL.

Inputs: enabled (required). Returns: object

fl_set_mixer_muteSet mixer track muteB
Idempotent

Mute or unmute a mixer track (state=True mutes).

Inputs: track (required), state (required). Returns: object

fl_set_mixer_nameSet mixer track nameA
Idempotent

Rename a mixer track.

Inputs: track (required), name (required). Returns: object

fl_set_mixer_panSet mixer track panA
Idempotent

Set a mixer track's pan position (-1 left .. +1 right).

Inputs: track (required), value (required). Returns: object

fl_set_mixer_soloSet mixer track soloB
Idempotent

Solo or unsolo a mixer track (state=True solos).

Inputs: track (required), state (required). Returns: object

fl_set_mixer_volumeSet mixer track volumeA
Idempotent

Set a mixer track volume. unit='db' uses 0.8=unity (0 dB).

Inputs: track (required), value (required), unit. Returns: object

fl_set_routeSet mixer routing (src -> dst)A
Idempotent

Enable/disable a send from src -> dst (calls afterRoutingChanged on the FL side). Snapshot + readback; undo with fl_rollback_last_change.

Inputs: src (required), dst (required), enabled. Returns: object

fl_set_song_positionSet song position (beats)A
Idempotent

Move the playhead to the given beat position.

Inputs: beats (required). Returns: object

fl_set_tempoSet tempo (BPM)A
Idempotent

Set the FL Studio project tempo. Range is 10-999 BPM (FL's own limits).

Inputs: bpm (required). Returns: object

fl_set_track_colorColor mixer tracksA

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.)

Inputs: color (required), category, tracks. Returns: object

fl_setup_chainSet up a genre chain (plan)A
Read-onlyIdempotent

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.

Inputs: track (required), chain_type (required). Returns: object

fl_solo_tracksSolo a group of 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.

Inputs: category, tracks. Returns: object

fl_stopStopA
Idempotent

Stop playback. Idempotent.

Inputs: no named parameters. Returns: object

fl_suggest_presetSuggest a preset by descriptionA
Read-onlyIdempotent

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.

Inputs: description (required), plugin (required). Returns: object

fl_take_snapshotTake snapshotA
Read-onlyIdempotent

Read current state for a scope (for your own before/after diffing).

Inputs: scope (required). Returns: object

fl_toggle_playToggle playA

Toggle between play and stop, mirroring the spacebar in FL.

Inputs: no named parameters. Returns: object

fl_write_piano_roll_notesWrite piano-roll notesA
Destructive

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.

Inputs: notes (required), mode, quantize. Returns: object

fl_write_raga_chordsWrite raga/scale CHORDSA
Destructive

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.

Inputs: notes (required), raga, root, channel, +1 more. Returns: object

fl_write_raga_melodyWrite a raga/scale MELODYA
Destructive

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).

Inputs: notes (required), raga, root, channel, +1 more. Returns: object

Tool Schema Changelog

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

Loading tool schema changelog…

    TDQS

    A3.8/5.0

    Scored across 67 tools

    Disambiguation4/5

    Most tools have clearly distinct purposes, but the sheer number (67) creates some potential confusion, especially among similar-sounding tools like fl_get_channel_routing, fl_get_routing, fl_get_routing_all. However, descriptions help differentiate them.

    Naming Consistency5/5

    All tools follow a consistent fl_verb_noun pattern using snake_case, making it easy to predict tool names. Naming is highly uniform throughout the set.

    Tool Count2/5

    With 67 tools, the server is excessively large for a typical MCP server. While it covers many aspects of FL Studio, the scope is too broad, making it difficult for agents to navigate and select the right tool efficiently.

    Completeness3/5

    The toolset covers a wide range of FL Studio operations (project info, mixer, channel rack, piano roll, mixing effects, etc.), but notable gaps exist, such as no tool for loading plugins or handling automation, limiting full workflow coverage.

    Maintenance

    ActivityMaintained
    ResponsivenessUsually handled

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      Not graded
      maintenance
      Enables AI assistants to control FL Studio on Windows through a local MCP server without cloud dependencies. Bridges MCP clients to FL Studio's Python scripting environment via file-based IPC for project management, transport control, and UI workflow automation.
      -
    • A
      license
      C
      quality
      C
      maintenance
      Gives AI assistants full control of FL Studio through its scripting API, enabling project editing, mixing, piano roll composition, MIDI export, and plugin automation without touching the mouse or keyboard.
      57
      2
      MIT
    • A
      license
      Not graded
      quality
      C
      maintenance
      Enables Claude Desktop to drive FL Studio 2025 and 2026 through natural language, diagnosing and repairing mixes, configuring plugins, writing notes and chords in any scale, exporting arrangements to MIDI, and analyzing audio for tempo, key, and melody.
      MIT