Research

fLMCP turns FL Studio into a programmable MCP environment.

fLMCP is a local control plane that lets an MCP client inspect and operate FL Studio through typed tools, live resources, a TCP bridge, piano-roll scripting, audio analysis, and voice-to-MIDI workflows.

MCP Music systems Desktop automation Audio analysis
Abstract technical visualization of the fLMCP local control plane connecting an MCP host to a DAW, mixer, piano roll, waveform analysis, and automation layers.
System map fLMCP in one frame: MCP calls on the left, FL Studio state on the right, and a local bridge keeping the two sides typed and observable. Architecture

fLMCP started from a practical problem: FL Studio is powerful, but it was never designed to be driven by a language-model client. If we wanted reliable control, we needed more than hotkeys and screen scraping. We needed a bridge that understands the DAW's state model, timing model, threading constraints, and API boundaries.

The result is a local MCP server for FL Studio with 159 MCP tools and 7 live resources. It covers the parts producers actually touch: transport, patterns, channels, mixer, plugins, piano roll, playlist, arrangement, automation, project operations, high-level generators, microphone transcription, and audio-file analysis.

Public repository geezoria/FLStudioMCP The repo is public. This write-up is the engineering tour: how the bridge is split, where FL Studio's API forces odd choices, and what the tool surface is built for. github.com/geezoria/FLStudioMCP
159static MCP tool registrations
7readable FL state resources
15tool modules across DAW domains
16 MiBbounded local JSON frame size

The hard problem is not "send a command to FL Studio."

Desktop music production software is not shaped like a normal web API. FL Studio has public Python modules, but those modules are loaded in different script contexts, not every operation is exposed, and the host application remains an interactive real-time program with a UI thread. A bridge that writes notes, moves mixer faders, queries plugin parameters, and records automation has to respect those constraints.

That makes fLMCP interesting for reasons beyond music. It is an example of turning a stateful GUI application into a structured agent environment without pretending the GUI has become a server. The system succeeds because it separates concerns that are often collapsed in automation projects:

  • Observation is handled through resources such as `fl://project`, `fl://transport`, `fl://channels`, and `fl://mixer`.
  • Mutation is handled through typed tools with explicit parameters and structured errors.
  • Host safety is handled by running FL API calls on FL Studio's main thread, not in the socket worker.
  • Piano-roll edits are routed through a dedicated piano-roll script because note insertion is only available there.
  • Heavy audio dependencies are imported lazily so the core control plane remains lightweight.

The architecture is a bridge, not a bot.

fLMCP has three primary runtime pieces. The MCP server runs outside FL Studio and speaks stdio to the host. The FL-side controller script runs inside FL Studio as a MIDI controller script and opens a local TCP listener. The companion piano-roll script runs inside the piano-roll scripting environment, where FL exposes note-level editing APIs.

01 Tool call The MCP host calls a typed function such as `transport_set_tempo` or `mixer_set_eq_band`.
02 Frame encode The server wraps action, id, and params into length-prefixed JSON.
03 TCP handoff The bridge receives the frame on localhost and pushes it into a thread-safe inbox.
04 Main-thread execute `OnIdle()` drains bounded work and calls the FL API from the correct thread.
05 Structured result The response comes back as JSON, while push events can report refreshes and transport ticks.
# conceptual request frame
request = {
    "id": 42,
    "action": "transport.setTempo",
    "params": {"bpm": 174.0}
}

# encoded as:
# uint32_be(len(json_payload)) + utf8_json_payload
header Four-byte big-endian payload length. The receiver knows exactly how many bytes to read next. uint32_be
body UTF-8 JSON envelope with request id, action name, and parameter object. {id, action}
result Matching response id with `ok`, `result`, or structured error. Push events omit the id. {ok, result}

This is a small design choice with large consequences. Length-prefixed JSON avoids delimiter ambiguity, supports binary-safe reads, and lets both sides reject oversized frames. Request ids let the client ignore asynchronous notifications until the matching response arrives. Push events make it possible to observe FL activity, such as transport ticks or project refreshes, without constant polling.

Why it works: fLMCP respects the host application's real constraints.

Main-thread correctness

The socket thread never owns the FL API.

The controller script accepts connections in background threads, but actual DAW operations are executed from `OnIdle()`. This avoids calling FL's Python API from a foreign thread and keeps request handling predictable.

Bounded scheduling

Automation does not sleep inside the UI loop.

Automation points are scheduled against monotonic deadlines and applied when due. The tool can return immediately while FL Studio remains responsive instead of freezing for the duration of an automation clip.

Context split

Piano-roll editing goes through the piano-roll runtime.

The general controller script can open the right channel and pattern, but note insertion belongs to the piano-roll scripting context. fLMCP stages JSON actions, triggers the script, and reads back state.

Graceful degradation

Unsupported FL API surfaces become structured errors.

Some playlist, arrangement, rendering, and preset operations are not exposed by the public FL API. fLMCP keeps the tools visible but returns explicit limitations and fallback hints instead of silently pretending success.

The important research move is that fLMCP does not model FL Studio as a text editor with hotkeys. It models it as a live, partially exposed system: some state is readable, some state is mutable, some APIs are context-gated, and some operations require user-visible UI interaction.

The piano-roll bridge is the key technical pivot.

The most fragile part of many DAW automation attempts is note-level writing. Step sequencers and transport controls are useful, but music composition requires adding notes, chords, arpeggios, humanization, quantization, and transposition. In FL Studio, the piano-roll note API is only available in piano-roll scripts.

fLMCP handles this by treating the piano-roll script as a specialized execution environment. The MCP side writes a request queue, opens the relevant channel's piano roll when possible, sends the configured hotkey, then waits for a state file written by the piano-roll script. The method is intentionally simple: file-based staging gives both sides an inspectable handoff and keeps the FL-only note API inside the place where it is valid.

# conceptual piano-roll operation
piano_roll_add_notes(
    channel=4,
    pattern=2,
    clear_first=True,
    notes=[
        {"midi": 48, "time_bars": 0.0, "duration_bars": 1.0, "velocity": 0.78},
        {"midi": 55, "time_bars": 0.0, "duration_bars": 1.0, "velocity": 0.78},
        {"midi": 60, "time_bars": 0.0, "duration_bars": 1.0, "velocity": 0.78},
    ],
)

# internally:
# 1. select channel and pattern
# 2. stage note edits as JSON
# 3. trigger the active piano-roll script
# 4. return exported note state

The tool surface is broad, but it is organized by musical intent.

A large tool catalogue is only useful if the model can reason about it. fLMCP groups tools by the same boundaries a producer already understands: transport, patterns, channel rack, mixer, plugins, piano roll, playlist, arrangement, automation, project state, generators, voice, and audio.

Area Tools What it enables
Transport, patterns, project 38 Play/stop/record, tempo, time signature, pattern creation, undo, save, and project metadata.
Channels, mixer, plugins 51 Channel rack inspection, step sequencer writes, routing, EQ, send levels, plugin parameters, presets, and editors.
Piano roll, playlist, arrangement 30 Note writing, reading, quantizing, transposing, humanizing, markers, playlist tracks, and arrangement navigation.
Automation, UI, meta 16 Tempo/channel/mixer/plugin automation, window focus, hints, reconnects, raw bridge calls, and health checks.
Generators, voice, audio 24 Scales, chords, progressions, arpeggios, basslines, drum grooves, voice-to-MIDI, audio analysis, slicing, and DnB flips.
Tool coverage by functional layer Grouped from the 159 static MCP tool registrations found in the repository.
Channels, mixer, plugins
51
Transport, patterns, project
38
Piano roll, playlist, arrangement
30
Generators, voice, audio
24
Automation, UI, meta
16

The companion resource layer gives the model a read path that does not mutate anything. That matters for agent reliability: before editing a session, an MCP client can inspect what is currently loaded and choose tool calls with more context.

fl://statusBridge and transport snapshot.
fl://projectProject-level metadata.
fl://transportPlayback and position state.
fl://channelsFull channel rack state.
fl://mixerMixer track state.
fl://patternsPattern list and metadata.
fl://playlistPlaylist tracks and markers.

Examples: from DAW operations to musical workflows.

The most useful fLMCP calls are not isolated button presses. They combine low-level state control with high-level musical primitives. A model can create structure, write notes, inspect the mixer, adjust routing, and iterate on the result while staying inside typed tool calls.

Create a pattern with drums, bass, and harmony.

pattern_create(name="Verse - 174 DnB sketch")
transport_set_tempo(bpm=174)

gen_emit_drum_pattern_step_seq(
    channel_map={"kick": 0, "snare": 1, "clhat": 2, "ophat": 3},
    style="drum_and_bass",
    repeats=2,
)

gen_emit_bassline(
    channel=4,
    root="C2",
    scale="minor",
    progression="i-VII-VI-V",
    pattern_style="octaves",
)

gen_emit_chord_progression(
    channel=5,
    root="C4",
    scale="minor",
    progression="i-VII-VI-V",
    chord_length_bars=1.0,
)

Use state resources before editing.

# conceptual agent loop
project = read_resource("fl://project")
mixer = read_resource("fl://mixer")
channels = read_resource("fl://channels")

target = find_channel(channels, name_contains="Sub")
if target is not None:
    channel_route_to_mixer(index=target.index, mixer_track=12)
    mixer_set_eq_band(track=12, band=1, gain=-0.2, frequency=180)

Turn a hummed idea into piano-roll data.

voice_to_piano_roll(
    duration_sec=8,
    bpm=120,
    scale_root="C",
    scale="minor",
    quantize_grid_sec=0.125,
    min_confidence=0.35,
    clear_first=True,
)

Analyze an audio file and generate a sketch from it.

analysis = audio_analyze(
    path="C:/samples/source_loop.wav",
    extract_melody=True,
    polyphonic=False,
)

song_to_dnb_flip(
    audio_path="C:/samples/source_loop.wav",
    target_bpm=174,
    dnb_style="amen",
    dnb_bars=4,
    include_melody=True,
    include_bass=True,
)

Voice and audio analysis make it more than a DAW remote.

The audio layer is intentionally optional. The core MCP server can start without `numpy`, `librosa`, `sounddevice`, `soundfile`, GUI libraries, or polyphonic transcription packages installed. Those dependencies are loaded only when a voice or audio tool is invoked. That keeps the base bridge usable for control and project automation, while still enabling richer workflows when the audio stack is present.

The monophonic voice path uses pitch tracking for humming and single-line melodies, then applies post-processing: confidence filtering, optional scale snapping, transposition, quantization, and conversion from seconds into bars at the selected BPM. Polyphonic mode uses a heavier transcription path for chords and overlapping notes when the extra runtime is available.

01 Capture Record microphone audio or load an existing file.
02 Track pitch Use monophonic F0 tracking for humming or a polyphonic engine for chords.
03 Segment notes Merge gaps, suppress unstable frames, and compute MIDI pitches.
04 Post-process Snap to scale, transpose, quantize, and filter by confidence.
05 Emit to FL Stage piano-roll notes and read back the resulting note state.

Useful applications beyond "AI makes a beat."

The obvious demo is generative composition, but the broader value is a programmable interface to a professional creative environment. fLMCP can support practical workflows where deterministic control matters.

01

Producer acceleration

Create first-pass drum, bass, chord, and arpeggio material without manually entering every note.

02

Mix and routing automation

Apply repeatable mixer setup, sends, EQ moves, naming, coloring, arming, and channel-to-track routing.

03

Plugin exploration

Search parameters, read values, set values, show editors, and script controlled sweeps for sound design.

04

Audio research prototyping

Estimate tempo, key, loudness, onsets, and melody, then transform those findings into editable MIDI.

05

Accessibility workflows

Use voice-to-MIDI and conversational control to lower the input cost of working in dense production UIs.

06

Agent benchmarking

Evaluate whether an agent can inspect state, plan a musical edit, execute tools, and verify the result.

07

Education

Teach scales, chord progressions, arrangement structure, signal flow, automation, and MIDI timing by example.

08

Session hygiene

Normalize names, colors, routing, tempos, markers, mixer states, and project metadata across sessions.

09

Creative iteration logs

Make changes through typed actions that can be summarized, replayed conceptually, and reasoned about.

Boundaries are part of the engineering.

fLMCP does not erase the limits of FL Studio's public Python API. It documents them and turns them into predictable behavior. That is why unsupported playlist clip placement, direct project rendering, some arrangement operations, and some plugin preset operations return explicit structured limitations instead of false success.

Local-only transport The bridge binds to localhost. It is designed as a local desktop control path, not a remote network service.
Single predictable bridge Calls serialize through one client connection so the DAW main-thread execution model remains understandable.
API honesty Where FL's public API does not expose an operation, the tool reports the limitation and suggests a workaround.
User-visible focus Piano-roll hotkey routing still depends on FL accepting the scripted action in the right UI context.

Quality model: test the bridge without requiring the DAW.

The repository is structured so much of the system can be validated offline. The protocol and bridge client can round-trip against a fake TCP bridge. Server construction can assert that expected tools and resources are registered. Pure helpers for audio key estimation, polyphonic note conversion, generators, and bridge helpers can be exercised without launching FL Studio.

This matters because desktop automation projects are often difficult to test. fLMCP keeps the FL-dependent boundary narrow enough that the surrounding protocol, schemas, conversion logic, optional dependency behavior, and musical helper functions can be validated in ordinary Python tests.

Future outlook.

The current architecture makes FL Studio addressable through MCP. The next work is less about adding one more button and more about trust: better state caching around push events, stronger verification after edits, safer multi-step composition plans, explicit undo checkpoints, and cleaner handling for DAW operations that still require UI interaction.

Longer term, fLMCP points at a broader pattern: professional desktop applications can become useful model-operated environments when we respect their runtime model. The lesson is not specific to music. Typed tools, read-only resources, local protocols, context-aware execution, and honest error surfaces are what make this feel like engineering instead of a screen-scraping trick.

Back to Journal Research notes, systems writeups, and technical implementation essays.

Have a technical system to build?

Tell us what you are solving. We will come back with a concrete next step.

Contact Gloryck