Skip to main content
Glama

FL Codex

Tests License: MIT

Type a request in Codex, such as "a little more reverb on the guitar", and let Codex inspect the actual FL Studio project and adjust exposed plugin knobs.

This is an FL Studio MIDI controller extension + local MCP server for Windows. The extension runs inside FL, selected in MIDI settings > Controller type. It is not a VST DLL to put in a mixer effect slot. Codex supplies the language reasoning; no additional AI API account or API key is needed.

Current status

Experimental. Live connection and discovery have been verified on FL Studio 25.2.5. A real plugin knob write/readback/undo acceptance test is still pending; automated tests use a simulated host. Universal plugin compatibility is not claimed.

Implemented: live track/plugin discovery, paginated parameter inspection, normalized parameter writes with readback, and undo of bridge changes. Live connection verified with FL Studio 25.2.5: version, selection, tracks and loaded-plugin discovery. Automated tests cover guarded edits and undo, MIDI framing, and local TCP/MCP transports. Plugin knob acceptance is recorded in docs/ARCHITECTURE.md.

Scope: loaded effects and instruments that expose parameters through FL's scripting API. Not every visual knob is exposed. Patcher internals need exposed controls. This version does not insert plugins, listen to audio, create notes, or save projects. An existing distortion plugin can be adjusted; adding a new distortion effect is not implemented.

Related MCP server: FL Studio MCP Server

Windows setup

Prerequisites: Windows, FL Studio 2025 (development target: 25.2.5), Python 3.11+, uv, Codex with its CLI, and loopMIDI. The MIDI transport currently uses Windows WinMM; macOS and Linux are unsupported.

Clone the repository and open PowerShell in it:

git clone https://github.com/Radishoux/fl-codex.git
cd fl-codex
  1. Install Python dependencies from this directory:

    uv sync --locked
  2. Install our extension in FL's user-data folder:

    uv run --locked python install.py

    Custom location: uv run --locked python install.py --user-data 'D:\Music\FL Studio'. The installer detects Windows' Documents folder, including OneDrive redirection. It copies only our controller and pairing configuration.

  3. In loopMIDI, create a dedicated virtual port named exactly FL Codex. The relay looks up this name. Keep loopMIDI running: the virtual port exists only while it runs. No MIDI notes are sent by this bridge.

  4. In FL Studio, press F10 > MIDI, refresh the device list if needed, select the FL Codex input, enable it, and choose FL Codex Bridge under Controller type. Set its input Port to 0. Select FL Codex in the Output list and set its Port to the same 0; leave Send master sync off. Use another matching number if 0 belongs to another device. Check View > Script output for FL Codex Bridge ready via MIDI SysEx; output assigned: True. If the new controller type is absent, refresh/reopen MIDI settings or restart FL after saving your own work. The installer never closes FL.

  5. Verify the live connection:

    uv run --locked python bridge_client.py status

    The client starts the local MIDI relay automatically when needed. Keep loopMIDI running. Startup errors go to .local/relay.log. To run the relay visibly for diagnosis: uv run --locked python relay.py (only one relay can own port 32123).

  6. Register the MCP server with Codex (one-time, from this directory):

    $flCodexRoot = (Get-Location).Path
    codex mcp add fl-studio -- "$flCodexRoot\.venv\Scripts\python.exe" "$flCodexRoot\server.py"

    Reload Codex's MCP connections or open a new chat if the new tools are not available in the current chat. The CLI remains usable immediately.

Use

Name mixer tracks clearly, for example Guitar, Lead vocal, and Drums. Select the target track or include its name in the instruction:

  • "List the effects on Guitar and their wet/mix parameters."

  • "Increase the guitar reverb wet amount slightly."

  • "Add a little drive using the distortion effect already on Guitar."

  • "Undo your last knob change."

Codex first reads the actual plugin and parameter names. Writes use a fresh handle and refuse to overwrite a knob that changed after inspection. Small requests default to a maximum normalized movement of 0.1; this is not a dB or percentage-of-perceived-loudness scale. Changes are refused while recording.

No manual MIDI CC assignment is needed for exposed plugin parameters. MIDI SysEx carries commands and replies; the FL script calls FL's parameter API. The virtual input is reserved for this bridge and consumes musical MIDI messages.

Verify / develop

uv run --locked python -m unittest discover -s tests -v
uv run --locked python scripts/check_mcp.py
uv run --locked python scripts/list_midi.py

check_mcp.py regenerates tool_manifest.json from the real server. Tests bind localhost sockets; a sandbox that prohibits loopback needs host permission.

The live acceptance procedure and implementation details are in docs/ARCHITECTURE.md.

See CONTRIBUTING.md for development and compatibility reports.

License

MIT. FL Studio, loopMIDI and other dependencies remain under their respective licenses and are not included in this repository. This is an independent project, not an official Image-Line or OpenAI product.

Available Tools

6 tools
get_fl_parametersB
Read-only

Read parameter names, normalized values, display units and short-lived edit handles. Follow next_start.

NameRequiredDescriptionDefault
kindYes
slotNoEffect slot 0-9, instrument -1
indexYesZero-based mixer or global channel index
limitNoMaximum parameters per page
startNoFirst parameter index

TDQS

B3.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly/non-destructive/closed-world, and the description adds genuinely new context: the payload includes normalized values and display units, and the edit handles are 'short-lived' — a real constraint an agent must act on. It also signals pagination via next_start. It stops short of saying what the handles are for or what happens when they expire.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short sentences with no filler, and the return-payload summary is front-loaded. 'Follow next_start' is terse to the point of ambiguity, but nothing is wasted.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description carries the burden of explaining returns and does list the four payload elements, plus paging. However, it never explains how kind/slot/index combine to select a target, nor what an edit handle is used for downstream — meaningful gaps for a 5-parameter tool with required addressing fields.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 80% — slot, index, limit and start are all documented in-schema, and kind is a self-explanatory two-value enum. The description adds nothing about parameter meaning; 'Follow next_start' refers to a pagination token that is not even a request parameter, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

A specific verb ('Read') plus the resource ('parameters') and an enumeration of what comes back: names, normalized values, display units, edit handles. It is clearly the read counterpart to set_fl_parameter, though it never names that sibling or otherwise differentiates itself explicitly.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no statement of when to use this instead of set_fl_parameter or the list_* tools, and no prerequisites (e.g., needing a track/slot selected first). 'Follow next_start' hints at pagination handling but is the only usage-shaped guidance offered.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_fl_statusA
Read-only

Check the live FL bridge, version, current selection, recording state and capabilities.

NameRequiredDescriptionDefault

No parameters

TDQS

A3.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, destructiveHint=false, and openWorldHint=false, so the safety profile is covered structurally. The description contributes beyond that by enumerating what live state is surfaced (bridge, version, selection, recording state, capabilities), which tells the agent this is a cheap non-mutating probe. It does not say what happens when the bridge is down, so it is not a 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single front-loaded sentence with no filler, and the most important noun ("live FL bridge") leads. Nothing is wasted.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema and no parameters, the description carries the burden of describing returns and it does so by listing the state facets. The only real gap is error/disconnected behavior, which matters for a tool whose whole purpose is checking a live bridge.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes zero parameters and the schema is empty, so there is nothing for the description to disambiguate. Baseline 4 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb ("Check") and names the resource plus the exact facets returned: bridge liveness, version, current selection, recording state, and capabilities. That is far more informative than the name alone. It stops short of naming a sibling it displaces, which keeps it out of the top band.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No sentence tells the agent when to call this versus list_fl_tracks, get_fl_parameters, or the mutation tools. A reader can infer it is a diagnostic/liveness probe, but the description never states prerequisites (e.g. call before other FL tools) or exclusions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_fl_pluginsA
Read-only

Discover loaded effects on a mixer track, or the instrument at a global channel index.

NameRequiredDescriptionDefault
kindYes
indexYesZero-based mixer or global channel index

TDQS

A3.9/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The annotations already declare readOnlyHint=true, destructiveHint=false, and openWorldHint=false, so the safety profile is covered structurally. The description confirms discovery/read behavior and clarifies the index domain, but it does not add much beyond that about errors, empty results, or other runtime behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single front-loaded sentence that states the two operating modes without waste. Every clause contributes to selecting the right kind and index context.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple read-only list tool with safety annotations and a mostly self-explanatory schema, the description is sufficiently complete to support correct invocation. It could still say more about the returned shape or whether missing/out-of-range indexes produce errors, but those are minor gaps rather than blockers.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With only 50% schema description coverage, the description usefully clarifies that "kind=effect" applies to a mixer track index while "kind=instrument" applies to a global channel index. That mapping is important because the schema's index description alone is ambiguous across the two kinds.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb ("Discover") and resource ("loaded effects" / "instrument") and distinguishes the two modes by mixer track versus global channel index. It is clear, but it does not explicitly differentiate itself from siblings such as get_fl_parameters or list_fl_tracks.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear context for when to use the tool: to discover effects on a mixer track or an instrument at a global channel index. It does not state when not to use it or name alternatives, so it falls short of full usage guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_fl_tracksA
Read-only

List track names and indices; channel results also show mixer routing. Follow next_start.

NameRequiredDescriptionDefault
kindNomixer
limitNoMaximum tracks to read
startNoFirst index in this page

TDQS

A3.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, destructiveHint=false and openWorldHint=false, so safety is covered. The description adds genuinely new behavioral context beyond the schema: that results are paginated via a next_start cursor (a return value not present in the input schema) and that output shape varies by kind.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short sentences with the primary behavior front-loaded and no wasted words. "Follow next_start" is terse to the point of being slightly cryptic, since nothing explains that next_start is a returned cursor, but the density is appropriate.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description must carry return-value semantics, and it only partially does: names/indices, routing for channels, and a next_start cursor. It omits what the mixer kind returns, how the two kinds differ, and what happens when next_start is absent (last page).

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 67% — limit and start are already documented in the schema. The description adds partial meaning for the undescribed 'kind' enum by explaining what channel results contain, but never contrasts mixer vs channel or states what the default mixer mode returns. Baseline 3 fits.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ("List track names and indices") and adds a conditional output distinction (channel results include mixer routing). It is clearly the only track-listing tool among siblings like list_fl_plugins and get_fl_parameters, though it never names the sibling it differs from.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is only implied: "channel results also show mixer routing" hints that kind=channel is the choice when routing matters, but there is no explicit when-to-use/when-not statement or named alternative. An agent must infer which of mixer vs channel it wants.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

set_fl_parameterA

Change one freshly inspected knob and return actual readback. Refuses stale values and recording; stores bridge undo.

NameRequiredDescriptionDefault
valueYesRequested normalized value, not a physical unit
handleYesFresh handle from get_fl_parameters
max_deltaNoLargest intentional normalized move from the inspected value

TDQS

A3.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations cover safety (not read-only, not destructive), and the description adds real value beyond them: the call returns actual hardware readback, it rejects stale handles and refuses while recording, and it pushes an undo entry so the change is reversible. It does not say how failures surface (error vs. silent no-op).

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short sentences, mutation verb front-loaded, no filler. The telegraphic style ("stores bridge undo") trades a little clarity for density.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a mutating tool with no output schema, the description leaves the return value ("actual readback") undefined and does not say what happens on a max_delta violation or an out-of-band value. The preconditions it does cover are the ones that matter most, so it is adequate rather than complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and each parameter already carries a description, so the schema does the heavy lifting. The description reinforces that handle must come from a live get_fl_parameters call but says nothing about value normalization or max_delta beyond what the schema states.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

"Change one ... knob and return actual readback" gives a specific verb plus a single-resource scope, which distinguishes it from get_fl_parameters (read) and undo_fl_change (revert). The jargon "knob" and "bridge undo" slightly obscure the object being changed, keeping it out of 5 territory.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

"Freshly inspected" makes the prerequisite explicit: you must call get_fl_parameters first, and the "Refuses ... recording" clause tells the agent a context where it will not work. It never names an alternative sibling or says when to prefer undo_fl_change, so it stops short of explicit routing.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

undo_fl_changeA

Restore the latest bridge knob change, provided the plugin and value still match. Does not invoke FL's global undo.

NameRequiredDescriptionDefault

No parameters

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare this as non-read-only, non-destructive, and closed-world, and the description adds meaningful behavior: it restores only the latest matching bridge knob change and does not trigger global undo. It omits what happens when the plugin/value precondition is not met, leaving one behavioral gap.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two sentences, front-loaded with the action and its precondition, and contains no redundant restatement of annotations or schema. Every sentence contributes useful selection or invocation context.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a zero-parameter undo operation with annotations and no output schema, the description supplies enough scope, precondition, and exclusion context to call it correctly. The main remaining gap is failure behavior when the plugin/value precondition does not hold.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool defines zero parameters, so the schema carries no parameter-documentation burden. The description's mention of plugin and value matching refers to internal state conditions rather than inputs, which is a useful distinction.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific action, 'Restore', and a specific resource, 'latest bridge knob change', while distinguishing it from FL's global undo. It does not explicitly differentiate from sibling tools such as set_fl_parameter, so sibling routing is only partially supported.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives a clear usage condition: the plugin and value must still match. It also includes an exclusion by saying it does not invoke FL's global undo, but it does not name the alternative tool to use when the precondition fails or a broader undo is needed.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

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

  1. 6 tool updatesv0.1.0
    • First observedget_fl_parameters
    • First observedget_fl_status
    • First observedlist_fl_plugins
    • First observedlist_fl_tracks
    • First observedset_fl_parameter
    • First observedundo_fl_change

TDQS

A4/5.0

Scored across 6 tools

Disambiguation5/5

Each tool targets a distinct resource and action: status inspection, track listing, plugin listing, parameter reading, parameter writing, and undo. The boundary between inspecting a plugin and reading its parameters is clear from the descriptions.

Naming Consistency5/5

All tool names follow a consistent snake_case verb_fl_noun pattern. The verbs are used predictably: get for reads, list for collections, set for mutation, and undo for reversal.

Tool Count5/5

Six tools are well-scoped for an FL Studio bridge focused on safely inspecting and editing parameters. Each tool has a clear role and no obvious redundancy.

Completeness4/5

The parameter-editing lifecycle is covered: check status, discover tracks and plugins, read parameters, set a parameter, and undo a change. Minor gaps exist around broader FL Studio control such as transport actions, plugin loading, or redo.

Maintenance

ActivityMaintained
ResponsivenessSyncing

Related MCP Connectors

Related MCP Servers