Skip to main content
Glama
KindaMAD-hav

fl-studio-mcp

by KindaMAD-hav

fl-studio-mcp-KindaMAD

Started as a fork of karl-andres/fl-studio-mcp. Karl's project is the base of this one: the MCP server, the MIDI + JSON bridge, the controller script that runs inside FL Studio, and the transport, mixer, channel, plugin and piano roll tools. His project in turn credits calvinw/fl-studio-mcp for the piano roll approach.

This fork adds what an agent needs to build a full arrangement in FL Studio on Windows without anyone at the keyboard: a tool that runs Python inside FL, screenshot and click tools, a Win32 layer that drives FL's UI without moving the cursor, and a pipeline that turns a song spec into patterns and playlist clips.

What this fork adds

Run code inside FL Studio

Tool

Description

fl_exec

Run Python in FL Studio's interpreter with every API module in scope. Assign to _result to return a value. Stdout and tracebacks come back too.

fl_introspect_api

List what the running FL build actually exposes, module by module. FL ships no type stubs, and the reference is wrong in places.

Every other tool wraps one API call, so a new capability used to mean a new controller handler, a reinstall and a reload. fl_exec skips that, and one call with a loop in it replaces dozens of tool calls.

See and click (Windows)

Tool

Description

fl_screenshot

Capture FL's window to a PNG with PrintWindow. Works when FL is covered and does not take focus. Optional crop and downscale.

fl_click

Click at a window-relative position.

fl_press_key

Send a real keystroke. Needed where the API has no equivalent: ui.enter() does nothing to a browser node, a real Enter loads it.

Multi-channel piano roll writes

Tool

Description

fl_compose_arrangement

Write notes to several channels in one call. Selects each channel, focuses its piano roll, writes the notes and triggers the script.

The piano roll trigger (Ctrl+Alt+Y) used to land in whichever window had focus, usually the terminal running the server, so FL never ran the script. It now finds FL's window, focuses it, sends the key and gives focus back. It also waits on a completion check instead of a fixed delay.

Win32 automation layer: utils/fl_window.py

  • Finds FL's main window by its process (FL64.exe), not its title, so an Explorer window or browser tab that mentions FL Studio never matches. It also reports the executable path, because FL 2025 and 2026 install side by side and both run as FL64.exe.

  • Per-monitor DPI aware, so coordinates hold on scaled and mixed-DPI displays.

  • Clicks, drags, scrolls and keys are posted straight to FL's message queue. The cursor does not move and your foreground window stays put.

  • Detects FL's modal dialogs, which block its script thread and stall the control link. Dismissing them is the one path that uses the real cursor, and it puts the cursor back afterwards.

Song pipeline: pipeline.py

FLPipeline().build(song) takes a Song (tempo, named patterns holding notes per channel, and an arrangement of (pattern, playlist_track, start_bar)) and builds it in FL:

Part

How

Tempo, patterns, channel selection

Scripting API

Notes

Streamed over MIDI and captured with general.dumpScoreLog

Playlist clips

Posted clicks on the playlist grid

Instruments

FL's browser and ADD menu, plus a real Enter keystroke

Loading an instrument is the only step that needs focus. scripts/verify_hands_free.py samples the cursor during a build to check that nothing else moves it. scripts/demo_pipeline.py builds a two-section drum arrangement and is the place to start.

The pipeline reads the scripting API version from general.getVersion() and gates the newer calls on it (patterns.setPatternLength, playlist.selectTool, patterns.clearPattern, patterns.duplicatePatternData).

What FL's scripting API can't do

Measured on FL Studio 2025 (API 38) and 2026 (API 45). Full notes are in docs/PIPELINE.md.

  • No function places a playlist clip, creates a channel or inserts a mixer FX slot. The pipeline does the first two through FL's UI. FX insertion is not built. scripts/check_api_gain.py re-tests all three after an FL update.

  • Pattern length is in steps, 16 per bar, not beats as the reference says.

  • selectTool is in playlist, not ui.

  • patterns.clearPattern opens a modal dialog on every call, which blocks the script thread until it is answered. Ticking "Remember my choice" once stops it.

  • PyFLP is not a way around this on FL 2025. Its writer produces files FL refuses to open, and its reader misparses FL 2025's 80-byte playlist clip records. flp_splice.py is kept as the record of that investigation.

Status

Working end to end from a Song: tempo, patterns, notes, instruments through the ADD menu, and clip placement.

Not done yet:

  • Composition helpers (scales, voicings, groove templates). Every note in the demo scripts is written out by hand.

  • Mix pass. build() does not set mixer levels or plugin parameters yet, although the tools for both work.

  • Revision loop. build(reuse_slots=True) rebuilds in place, but spec diffing is not written.

  • Playlist and browser coordinates in Layout were measured at 2560x1380. Re-measure them from a screenshot if your layout differs, or clips land on the wrong bar without any error.

Related MCP server: FL Studio MCP Server

Requirements

  • FL Studio 20.7+ (MIDI Controller Scripting API). The pipeline was built on FL Studio 2025 (25.2.3) and 2026 (26.1.4).

  • Python 3.10+

  • Windows for everything this fork adds. The original tools also run on macOS.

    • Windows: loopMIDI

    • macOS: IAC Driver (built in, needs to be enabled)

Quick Installation

The setup script is written for macOS. On Windows it cannot set up MIDI or the controller script, so it prints those steps instead. They are covered under Manual Installation.

# Clone the repository
git clone https://github.com/KindaMAD-hav/fl-studio-mcp-KindaMAD.git
cd fl-studio-mcp-KindaMAD

# Run the one-command installer
./install.sh

This will:

  1. Install uv if not present

  2. Install Python dependencies

  3. Guide you through enabling virtual MIDI ports (IAC Driver on Mac)

  4. Install the FL Studio MIDI controller script

  5. Install the Piano Roll script (ComposeWithLLM)

  6. Configure Claude Desktop or Claude Code automatically

Manual Installation

1. Install Python Dependencies

# Using uv (recommended)
uv sync

# Or using pip
pip install -e .

2. Enable Virtual MIDI Ports

macOS (IAC Driver)

  1. Open Audio MIDI Setup (search in Spotlight)

  2. Press Cmd+2 or go to Window > Show MIDI Studio

  3. Double-click on IAC Driver

  4. Check "Device is online"

  5. Click Apply

Windows (loopMIDI)

  1. Download and install loopMIDI

  2. Create a virtual port (any name works)

  3. Optional, for the pipeline: create a second port with FLStudioNotes in its name. Notes stream over it so a long burst does not wake the controller script for every note. Without it the pipeline uses the control port.

  4. Keep loopMIDI running while using FL Studio

3. Install FL Studio Scripts

On Windows, with FL Studio closed:

python scripts/install_controller.py          # show what would change
python scripts/install_controller.py --apply  # install, keeping a backup

FL runs a copy of the controller script from its settings folder, and nothing keeps that copy in step with the repo. Re-run this after any change to fl_controller/device_FLStudioMCP.py and after every FL Studio update.

Or copy the controller script to FL Studio's Hardware folder by hand:

# macOS
mkdir -p ~/Documents/Image-Line/FL\ Studio/Settings/Hardware/FLStudioMCP
cp fl_controller/device_FLStudioMCP.py ~/Documents/Image-Line/FL\ Studio/Settings/Hardware/FLStudioMCP/

# Windows
mkdir "%USERPROFILE%\Documents\Image-Line\FL Studio\Settings\Hardware\FLStudioMCP"
copy fl_controller\device_FLStudioMCP.py "%USERPROFILE%\Documents\Image-Line\FL Studio\Settings\Hardware\FLStudioMCP\"

Copy the Piano Roll script:

# macOS
cp scripts/ComposeWithLLM.pyscript ~/Documents/Image-Line/FL\ Studio/Settings/Piano\ roll\ scripts/

# Windows
copy scripts\ComposeWithLLM.pyscript "%USERPROFILE%\Documents\Image-Line\FL Studio\Settings\Piano roll scripts\"

4. Configure FL Studio

  1. Restart FL Studio (if it's running)

  2. Go to Options > MIDI Settings

  3. Under Input, find your virtual MIDI port (e.g., "IAC Driver Bus 1" or your loopMIDI port)

  4. Set the Controller type to FLStudioMCP

  5. Enable the port (click to highlight it)

5. Configure Claude

Add to your Claude Desktop config (~/Library/Application Support/Claude/claude_desktop_config.json on macOS, %APPDATA%\Claude\claude_desktop_config.json on Windows):

{
  "mcpServers": {
    "fl-studio": {
      "command": "uv",
      "args": ["run", "--directory", "/path/to/fl-studio-mcp-KindaMAD", "fl-studio-mcp"]
    }
  }
}

Or for Claude Code, add the same server to your MCP settings.

Usage

Running the Server Manually

# Using uv
uv run fl-studio-mcp

# Or after installation
fl-studio-mcp

Piano Roll Workflow

  1. Open FL Studio and select a channel

  2. Open the Piano Roll (F7 or double-click the channel)

  3. The first time, manually run the script: Tools > Scripting > ComposeWithLLM

  4. After that, the MCP tools will auto-trigger the script

Building a Song with the Pipeline (Windows)

  1. Open FL Studio with the playlist visible

  2. Check the playlist and browser coordinates in Layout (src/fl_studio_mcp/pipeline.py) against a screenshot of your layout

  3. Run the demo, optionally passing the bar to start at:

uv run python scripts/demo_pipeline.py 1

It prints the project state before the build, then each pattern and clip it created.

Available Tools

The transport, mixer, channel, plugin and piano roll tools below are from the original project. fl_compose_arrangement and the scripting and vision tools are described above.

Connection

Tool

Description

fl_connect

Connect/reconnect to FL Studio

fl_connection_status

Get connection status

Transport

Tool

Description

fl_play

Start/pause playback

fl_stop

Stop playback

fl_record

Toggle recording

fl_get_transport_status

Get playback/recording state

fl_set_song_position

Set playback position

fl_get_song_length

Get song duration

fl_set_loop_mode

Switch between pattern/song mode

fl_set_playback_speed

Adjust playback speed (0.25x-4x)

Mixer

Tool

Description

fl_get_mixer_track_count

Get number of mixer tracks

fl_get_mixer_track_info

Get track details

fl_get_all_mixer_tracks

List all tracks

fl_set_track_volume

Set track volume

fl_set_track_pan

Set track pan

fl_mute_track

Mute/unmute track

fl_solo_track

Solo/unsolo track

fl_arm_track

Arm track for recording

fl_set_track_name

Rename track

fl_set_track_color

Set track color

fl_set_stereo_separation

Adjust stereo width

Channels

Tool

Description

fl_get_channel_count

Get number of channels

fl_get_channel_info

Get channel details

fl_get_all_channels

List all channels

fl_get_selected_channel

Get selected channel

fl_select_channel

Select/deselect channel

fl_select_one_channel

Select channel exclusively

fl_trigger_note

Trigger MIDI note (real-time)

fl_set_channel_volume

Set channel volume

fl_set_channel_pan

Set channel pan

fl_mute_channel

Mute/unmute channel

fl_solo_channel

Solo/unsolo channel

fl_set_channel_name

Rename channel

fl_set_channel_color

Set channel color

fl_route_channel_to_mixer

Route to mixer track

fl_get_grid_bit

Get step sequencer step

fl_set_grid_bit

Set step sequencer step

fl_get_step_sequence

Get full pattern

fl_set_step_sequence

Set full pattern

Plugins

Tool

Description

fl_is_plugin_valid

Check if plugin exists

fl_get_plugin_name

Get plugin name

fl_get_plugin_param_count

Get parameter count

fl_get_plugin_params

List all parameters

fl_get_plugin_param_value

Get parameter value

fl_set_plugin_param_value

Set parameter value

fl_get_preset_count

Get preset count

fl_next_preset

Next preset

fl_prev_preset

Previous preset

fl_get_plugin_color

Get plugin color

Piano Roll

Tool

Description

fl_send_notes

Add notes to the piano roll

fl_send_chord

Add a chord (multiple notes at same time)

fl_delete_notes

Delete specific notes

fl_clear_piano_roll

Clear all notes

fl_get_piano_roll_state

Read current piano roll notes

fl_trigger_script

Manually trigger the FL Studio script

fl_get_piano_roll_info

Get piano roll system info

fl_clear_request_queue

Cancel pending queued changes

Limitations

  • The dedicated tools only control what is already in the project. The scripting API cannot load plugins, add channels, place playlist clips or insert mixer FX slots. On Windows the pipeline adds channels and places clips through FL's UI (see above).

  • fl_trigger_note is real time only. Notes don't persist unless FL Studio is recording. Use the piano roll tools or the step sequencer for notes that stay.

Example Workflows

Adjusting a Mix

"Set the volume of mixer track 1 to 80% and pan it slightly left"

Creating a Drum Pattern

"Create a basic kick pattern on channel 0 with kicks on steps 0, 4, 8, and 12"

Adding a Melody to Piano Roll

"Add a C major arpeggio starting at beat 0: C4, E4, G4, C5 - each note quarter duration"

Adding Chords

"Add a C major chord at beat 0, then F major at beat 2, then G major at beat 4"

Automating Plugin Parameters

"List the parameters of the plugin on channel 0 and set the filter cutoff to 50%"

Querying Anything the Tools Don't Cover

"Use fl_exec to list every pattern with its name and length in bars"

Troubleshooting

"Not connected to FL Studio"

  1. Ensure FL Studio is running

  2. Check that the FLStudioMCP controller is enabled in MIDI Settings

  3. On Mac, verify IAC Driver is enabled in Audio MIDI Setup

  4. On Windows, verify loopMIDI is running

  5. Restart FL Studio after enabling the controller

"Timeout waiting for FL Studio response"

  1. Make sure FL Studio is in focus

  2. Check the Script output window in FL Studio (View > Script output)

  3. Verify the controller is receiving MIDI (look for activity in MIDI Settings)

  4. Look for a modal dialog in FL. One blocks the script thread and every command times out until it is answered.

FL behaves like the controller code is out of date

It probably is. Run python scripts/install_controller.py to see the difference between the repo and the copy FL loads, then --apply with FL closed.

Pipeline clips land on the wrong bar or lane

The Layout coordinates no longer match your screen. Take an fl_screenshot, find bar 1 and bar 2 on the ruler and the first two track labels, and update Layout.

Piano Roll script not triggering

  1. First time: manually run Tools > Scripting > ComposeWithLLM in FL Studio

  2. On macOS: grant Accessibility permissions when prompted

  3. Ensure FL Studio is in focus when triggering

  4. Try pressing Cmd+Opt+Y (macOS) or Ctrl+Alt+Y (Windows) manually

No MIDI ports available

  • macOS: Enable IAC Driver in Audio MIDI Setup

  • Windows: Install and run loopMIDI

Architecture

The original project uses a hybrid approach:

┌─────────────────┐     ┌─────────────────────────────────────────┐
│   MCP Client    │────▶│           FastMCP Server                │
│  (Claude, etc)  │     │                                         │
└─────────────────┘     │  ┌─────────────────┐  ┌──────────────┐  │
                        │  │ MIDI + JSON     │  │ Piano Roll   │  │
                        │  │ Tools           │  │ Tools (JSON) │  │
                        │  └────────┬────────┘  └──────┬───────┘  │
                        └───────────┼──────────────────┼──────────┘
                                    │                  │
                               MIDI + JSON        JSON Files +
                                    │              Keystroke
                                    ▼                  ▼
                        ┌─────────────────────────────────────────┐
                        │              FL Studio                   │
                        │  ┌──────────────┐  ┌──────────────────┐ │
                        │  │FLStudioMCP   │  │ Piano Roll Script│ │
                        │  │(MIDI Ctrl)   │  │ (ComposeWithLLM) │ │
                        │  └──────────────┘  └──────────────────┘ │
                        └─────────────────────────────────────────┘

How It Works

  1. Transport/Mixer/Channels/Plugins:

    • MCP server writes command to JSON file

    • Sends MIDI trigger note to FL Studio

    • FL Studio controller script reads JSON, executes API, writes response

    • MCP server reads response

  2. Piano Roll:

    • MCP server writes note requests to JSON file

    • Sends keystroke (Cmd+Opt+Y / Ctrl+Alt+Y) to trigger FL Studio script

    • Piano Roll script reads JSON and modifies notes

  3. Added in this fork:

    • fl_exec and fl_introspect_api use the same MIDI + JSON link, with two new handlers in the controller script

    • The vision tools and the pipeline also post Win32 messages directly to FL's window

    • The pipeline streams notes over MIDI (a second port if there is one) and reads them back with general.dumpScoreLog

Development

Prerequisites

  • Python 3.10+

  • uv (recommended)

Setup

# Install all dependencies including dev extras
uv sync --dev

# Or with pip
pip install -e ".[dev]"

Available Commands

Command

Description

uv run fl-studio-mcp

Run the MCP server

uv run ruff check .

Lint the codebase

uv run ruff check --fix .

Lint and auto-fix

uv run pytest

Run tests

Project Structure

fl-studio-mcp-KindaMAD/
├── fl_controller/
│   └── device_FLStudioMCP.py    # FL Studio MIDI controller script (runs inside FL Studio)
├── docs/
│   └── PIPELINE.md              # Pipeline design and the measured API capability map
├── scripts/
│   ├── setup.sh                 # FL Studio script installer
│   ├── install_mcp_for_claude.sh # Claude config installer
│   ├── install_controller.py    # Sync the controller script into FL (Windows)
│   ├── ComposeWithLLM.pyscript  # Piano Roll script (runs inside FL Studio)
│   ├── demo_pipeline.py         # Build a two-section arrangement from a Song
│   ├── check_api_gain.py        # Re-test the API walls after an FL update
│   ├── verify_hands_free.py     # Check a build never moves the cursor
│   ├── flp_validate.py          # Walk and compare .flp event streams
│   └── probe_*, diag_*, test_*  # Probes and diagnostics used to map the API
├── src/fl_studio_mcp/
│   ├── server.py                # FastMCP server entry point
│   ├── pipeline.py              # Song spec to FL project
│   ├── flp_splice.py            # Byte-level .flp clip editing (investigation record)
│   ├── tools/                   # MCP tool implementations
│   │   ├── channels.py
│   │   ├── mixer.py
│   │   ├── piano_roll.py
│   │   ├── plugins.py
│   │   ├── scripting.py         # fl_exec, fl_introspect_api
│   │   ├── transport.py
│   │   └── vision.py            # fl_screenshot, fl_click, fl_press_key
│   └── utils/
│       ├── connection.py        # FL Studio connection wrapper
│       ├── fl_trigger.py        # Piano roll keystroke trigger
│       ├── fl_window.py         # Win32 window lookup, focus and posted input
│       ├── midi_connection.py   # MIDI + JSON communication layer
│       └── screenshot.py        # PrintWindow capture
├── fl_api_report.json           # Live API surface from probe_fl_api.py, the baseline for check_api_gain.py
└── install.sh                   # One-command installer

Credits

License

MIT. See LICENSE.

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    C
    maintenance
    An MCP server that enables remote control and automation of FL Studio via the flapi Python client. It provides tools for managing transport, mixer tracks, pattern sequencing, and plugin parameters, allowing users to execute Python code directly within the FL Studio environment.
    2
    -
  • A
    license
    Not graded
    quality
    D
    maintenance
    An MCP server that connects AI assistants to FL Studio for music production via Virtual MIDI. It enables users to control transport, manage the mixer, write notes, and manipulate plugin parameters through natural language.
    1
    MIT