Skip to main content
Glama

kuruitsugizaki

An MCP server that lets a model read and write FL Studio projects and drive a running FL Studio, so it can write music.

The model does not listen. A render comes back as numbers and pictures (spectrograms, loudness, stereo width), and the person listens and decides.

Factory Seance, two minutes of glitchy witch house and breakcore, was written start to finish by Claude Opus 5.5 through this harness, in about 35 minutes: every note, drum hit, sound choice, mixer route and automation clip, from FL's factory sounds only. Nobody edited it; the person who asked for it listened afterwards and kept it as it was. Listen: examples/seance.mp3, the clip with sound: examples/demo.mp4, how it was made: examples/seance.md.

https://github.com/user-attachments/assets/d5ddff3b-1f48-4249-9a7c-0230aac6e610

Splinter Engine, made with 0.4.0.

https://github.com/user-attachments/assets/2984c857-38cc-4384-b51d-e807018261eb

Seven Lamps, made with 0.4.4.

https://github.com/user-attachments/assets/355de51f-cf49-410f-94c3-5f754773bfa7

Windows only for now. To install it, follow INSTALL.md. Everything past setup and the tools (how to write a piece, the file format, traps, decisions) is under docs/, starting at docs/INDEX.md.

Requirements

  • Windows, FL Studio 2025. Built and measured on FL 25.1.6, scripting API 38.

  • loopMIDI with at least one port. FL loads the controller script only when its MIDI input port exists.

  • Python 3.12 or newer and uv.

  • ffmpeg and ffprobe on PATH, for the analysis scripts.

Related MCP server: FL Studio MCP Server

Setup

The short way: close FL and double-click setup.bat. It installs what is missing (uv, loopMIDI, optionally ffmpeg), builds the environment, installs FL's controller script, makes the MIDI port and FL's MIDI setting, adds the server to the Claude desktop app, and ends with a check that FL answers. INSTALL.md lists every step and where it lands.

By hand, the same in four moves (INSTALL.md, By hand, has the detail):

uv sync

Register the server with the MCP client, with the path to this folder:

"kuruitsugizaki": { "command": "<this folder>\\.venv\\Scripts\\kuruitsugizaki.exe" }

Then, in a chat with the model, FL closed:

  1. It calls config. On a standard install every path is found by itself (FL under Program Files\Image-Line, the rest under your Documents folder) and shows as detected; for anything not found it asks you where it is and sets it; it does not guess. The keys are in kuruitsugizaki.example.json; what you set is stored in kuruitsugizaki.json here, which git ignores.

  2. It calls fl_install, which writes the controller script into FL's Settings\Hardware folder with this folder's bridge path filled in, adds a loopMIDI port named kuruitsugizaki and assigns the script to it in FL's MIDI settings. Both of those live in the registry, and FL overwrites its own when it closes, which is why FL has to be closed.

  3. Only when fl_install answers that it could not make the MIDI setting: in FL, Options, MIDI settings, select a loopMIDI input port, controller type kuruitsugizaki, and restart FL once.

Script output in FL shows kuruitsugizaki {'api': 38, ...} on load. .venv\Scripts\python scripts\doctor.py prints one line per requirement, any time.

The server opens FL only for a project: project_write(open=true) and fl_render. Other live tools answer that FL is closed instead of starting it; fl_probe starts it to test the link and closes it again, and a first-time saved plugin state is made in FL and FL closed again (Plugins by name). An FL you started yourself is used when it is the only one open, and the result says so; the server closes only FLs it started, and with several FLs open and none of them its own it does nothing until you close the extra ones. Before acting on an FL you started, the server copies the project it has open to tmp/backups/<name>-<time>.flp, once per project per server run; the result says where the copy went and whether FL holds unsaved changes the copy lacks. FL gives no path, so the file is found by its name in the window title, and an untitled project is not copied. When FL crashes, the server reads the cause from Windows' Application log (faulting module, exception code) and returns it; an FL the harness started is closed with its crash handler and the Windows crash dialog, while a crashed FL of yours keeps its dialog. When FL shows a dialog and stops answering, the result names it and saves a picture of it to tmp/fl_dialogs/, and nothing more is sent to FL while it is up. A harness FL whose project FL reports changed is saved before it is closed, so closing never stops at "Save changes?".

Layout

file

what

scripts/server.py

the MCP server: tools, and the live link to FL

scripts/config.py

the machine paths, read from kuruitsugizaki.json

setup.bat, setup.ps1

the one-step install (INSTALL.md, The short way)

uninstall.bat, scripts/uninstall.py

undoes the setup: controller script, the MIDI port and FL's MIDI setting, the Claude entries, saved plugin states; settings move to tmp/uninstall; uv, loopMIDI, ffmpeg and .venv stay

Dockerfile

for MCP directories' automated checks: runs the server on Linux, where the file tools work and the live link to FL answers that it needs Windows

scripts/doctor.py

doctor.py [--install] [--claude [config]] [--live]: one line per requirement of this machine's setup, ok or MISSING with what to do; --install runs fl_install, --claude adds the server to the Claude desktop app's config, --live starts FL, asks it for its API version and closes it again

scripts/midisetup.py

the loopMIDI port and FL's MIDI input setting, both in the registry: reads them, and makes them when no input has the script

fl/device_kuruitsugizaki.py

FL controller script; fl_install puts it in place

scripts/flp.py

.flp event codec: parse, serialize (byte-exact), notes, diff

scripts/project.py

.flp -> full project JSON (round-trips byte-identical)

scripts/view.py

compact, summary and score views, compact -> full

scripts/style.py

style.py <folder> [out]: the project list behind profile

scripts/selftest.py

what CI runs, no FL needed: templates round-trip, a project from shipped parts builds and reads back, profile, the server's tool list; on Windows with FL also every example

scripts/writer.py

project JSON -> .flp, template based

scripts/automation.py

automation points (event 234) and targets (event 227)

scripts/levels.py

mixer fader and main volume records in event 225

scripts/mixerfx.py

mixer effect blocks: read one from any FL-saved project, place it in a track's slot

scripts/presets.py

puts a preset into a plugin channel's state: .vital (Vital), .h2p (Diva), .fxp (Sylenth1), .SerumPreset (Serum 2), <pack>/<preset> (FLEX)

scripts/serum2.py, sylenth1.py, diva.py, flex.py

each synth's preset format, and <script> catalog [out.tsv]: one TSV row per preset in that library

scripts/catalog.py

catalog.py <preset folder> <out.tsv>: Vital presets by style, oscillators, unison, effects on, macro names

scripts/render.py

render.py <flp> [--close] [--reopen]: FL's command-line render to wav and mp3 beside the project, then a short report and the spectrogram (spectro.py). FL must be closed first; --close asks it to (never forced); --detail puts the full analysis in the log

scripts/spectro.py

render -> PNG: semitone piano-roll spectrogram, chroma, 20 Hz-20 kHz spectrogram, RMS/peak, L/R correlation, ghost % over time with wash stretches (wash.py); --bpm adds bar lines. PNGs in tmp/spectro/. It prints a short report (length, key, flags only where something is there, peak and RMS) and writes the full analysis beside the picture as .txt; --detail prints that instead

scripts/wash.py

the wash check spectro.py runs on every render: ghost % per 4 s window, stretches weighted by length and edge rate, seconds where a hit rings out with nothing new under it before the next one counted half, head over trail, a score where over 18 is a wash (docs/COMPOSING.md §9)

scripts/loudness.py

integrated and momentary LUFS, LRA, true peak, RMS

scripts/scope.py

stereo density heatmaps per moment and band, --timeline for width over time

scripts/waveshape.py

A/B of several renders at several zooms around each file's loudest second

scripts/onsets.py

hit onsets of a WAV, for chopping loops

scripts/chop.py

cuts time ranges of a file into their own WAVs with short fades, optionally reversed

scripts/vox.py

vocal -> syllables with a median pitch each

scripts/sampleindex.py

the index behind samples: every audio file under a folder with size and modified time from listings, lengths from headers on demand

scripts/pick.py

how every long list is cut: one item from each equal slice, first to last, at a random place in it, so each call differs

scripts/cli.py

how setup, doctor and uninstall print: a rule per section, aligned rows with a coloured status

scripts/setup_paths.py

setup's path questions (setup.bat -Custom): each path set or found, Enter keeps it; --yes asks nothing

scripts/samples.py

samples.py <folder>: per file duration, BPM and key from the name, levels, width, onsets, centroid -> tmp/samples/<folder>.tsv

scripts/melstats.py

per-instrument note overview of a project

scripts/fxdump_fl.py

sent through fl_exec: every effect on every insert of the open project with its parameters

scripts/nudgemap.py, profiles/serum2/

Serum 2 host-parameter mapping (parked)

profiles/sylenth1/params.json

Sylenth1's 244 parameter names in blob order

projects/init/init.flp

the template new projects are built from

projects/init/fx.flp

the block effects by name are built on (config effect_template)

examples/

seven small documents, one per part of the format (instruments, effects, routing and sidechain, global, mixer and instrument automation), and a full two-minute piece with its script, notes and render; examples/build.py builds them all. Start at examples/README.md

docs/params/

parameter maps, one TSV per plugin: 27 of FL's own and 22 VST3s, listed in docs/params/INDEX.md; the params tool reads them

Tools

tool

does

config(key=None, value=None)

no arguments: every path key, its value or the path detected for it, and whether it exists; with key and value: sets it

fl_install()

installs the controller script into FL's Hardware folder with the bridge path written in and, with FL closed and unless an input in FL already has the script, adds a loopMIDI port named kuruitsugizaki and assigns the script to it in FL's MIDI settings (midisetup.py); the answer's midi entry says what was done or what is left to do by hand

project_read(path, view="compact", patterns=None, arrangements=None, unused=False, bars=None)

.flp -> JSON. compact: rows with pointers, the form project_write takes. summary: per-pattern stats and a per-track timeline. score: bars [first, last] (at most 16) of the first arrangement as text, one row per step and one column per part. full: exact round-trip form

project_write(doc, path, open=False, play=None)

JSON (compact or full) -> .flp; open loads it in FL (launching FL if needed), play = song or pattern

profile(folder=None)

a table of the .flp projects under a folder (read only): tempo, key, arrangement length; which to open with project_read. Also written to tmp/profile/<folder>/. Without folder it reads config projects_folder; the first folder given is saved there, and none records that the user has none

samples(folder=None, query=None, min_seconds=None, max_seconds=None, limit=100, max_folders=200, measure=False)

the user's sample folders from config sample_folders, asked once (none when they have none, and then FL's factory packs are the source), each with its folders at every level and their file counts. query searches every level by words in the path; min_seconds/max_seconds by length; results {folder: [[name, seconds]]}, an even spread across folders above limit. Indexed in tmp/samples/index/ from folder listings, relisted where a folder changed. measure writes tmp/samples/<folder>.tsv

fl_render(path, reopen=True, key=None)

saves and closes an FL the harness started, then runs render.py <path> --close [--reopen] [--key K] detached; with an FL you started open it renders nothing and asks you to close it, because FL hands a command-line render to the FL already running. Read the result with render_report

render_report(path)

a finished render: the short report and the spectrogram picture together; says so while the render is still running

fl_transport(action, mode=None, pattern=None)

play / stop, song / pattern mode; needs a project open in FL

plugins(query=None, native=False)

the VST3 and CLAP plugins FL has installed, and every instance in the optional library project (see Plugins by name); native=True adds FL's own: name, instrument or effect, vendor, format, source, how many presets load by name, whether it has a parameter map

presets(plugin, query=None, limit=200, harvest=False, kind=None)

a plugin's preset ids, filtered by words; the id goes into project_write as preset. When more than limit match, the list is an even spread across the preset folders, each folder an equal share, drawn anew on each call. harvest=True first reads the presets built into the plugin from FL (it opens the plugin there once, about a second per preset). kind picks instrument or effect for a name that is both, such as Serum2; without it the instrument is taken

params(plugin, query=None, kind=None)

a library plugin's parameters from docs/params/: index (for automation targets), name, saved value and display, and FL's display at 0, .25, .5, .75 and 1 where swept. kind picks instrument or effect for a name that is both, such as Serum2; without it the instrument is taken

fl_exec(code, out=None, timeout=10), fl_call(fn, args), fl_probe()

raw access to FL's Python API inside the running FL; fl_exec returns what the code assigns to result, or writes it as JSON to out (also when result is {'__out__': path, 'data': value}); they need FL open, and fl_probe starts it and closes it again

project_read, project_write, profile, plugins, presets and params reload the codec modules on every call; a change to server.py, flex.py or diva.py needs an MCP restart, and a new tool reaches a client only in a session started after it.

The template

projects/init/init.flp, saved by FL: a Sampler, FLEX, one audio channel and one automation clip; a mixer of inserts 1-125, no effects; a project routing past 125 is refused. Every plugin but FLEX loads by name; Serum 2, Vital, Diva and Sylenth1 take a preset ({"kind": "plugin", "plugin": "Vital", "preset": "<id>"}) into a state FL saved for them (Plugins by name). A template of your own holding them still works, matched by name: Serum2, FLEX, Vital, Sylenth1, Diva(x64).

Effects

An effect goes in by name: any effect FL has installed (Plugins by name). The first effect in projects/init/fx.flp is the block by-name effects are built on (config effect_template).

Plugins by name

Every plugin FL has installed can go into a project by name, with nothing to prepare: FL's plugin manager keeps one entry per plugin in its Plugin database (Documents\Image-Line\FL Studio\Presets\Plugin database, config key plugin_db, found by itself), and the writer builds the plugin from it on the template's blocks, fresh, as dragging it in from FL's browser does. plugins lists them; project_write takes an instrument as {"kind": "plugin", "plugin": "<name>", "preset": "<id>"} and an effect as mixer.effects: [{"track": t, "slot": s, "plugin": "<name>", "preset": "<id>"}]. A plugin installed in several formats is one name; add "format": "vst3" (or native, clap, vst) to pick one. A plugin FL has not scanned is not listed: run FL's plugin manager first. plugins leaves out what config hide_plugins names: by default FL's controllers, visualizers and notebooks, the VFX and FL Studio Mobile entries, Fruity Delay 2 and the first Parametric EQ, and every VST2 build. An entry is a name or * pattern, <format>:<name> for one format only, or category:<folder> for a category of FL's Plugin database. Setting the key replaces the default list. A hidden plugin cannot be written by name either.

Optionally, one project FL saved can hold tuned instances you want reused as they are, each instrument on its own channel, each effect in a mixer slot; set its path as config key library. A library instance wins over a fresh one of the same name.

Presets, listed by presets:

  • .fst files, from FL's factory and user Plugin presets folders (config keys fl_presets, fl_user_presets, found by themselves). FL writes one for any plugin from its plugin menu, VSTs included (a wrapped VST's go into Fruity Wrapper - <name>), so saving a sound there makes it usable by name.

  • Vendor preset files, found by default for Krush (ProgramData\Tritik\Krush), Portal (ProgramData\Output\Portal\Presets), spiff (ProgramData\oeksound\spiff\Presets) and ShaperBox 3 (APPDATA\Cableguys\ShaperBox3, named by the preset name inside each file), and for any other plugin from the folders config key vst_presets names: {"<plugin>": {"ext": ".vpreset", "dirs": {"": "<factory folder>", "user": "<user folder>"}}}. An entry there replaces a plugin's default. JUCE XML presets whose plugin keeps more in its state than the preset holds, as Krush and spiff do, are merged into that state; the rest replace it.

  • Serum 2, Vital, Sylenth1, Diva and FLEX presets, from each plugin's own default folder plus any folders config serum2_presets, vital_presets, sylenth1_presets (limited to sylenth1_folders) and diva_presets add, and from flex_packs. When a key has more than one folder, ids start with the folder's name. These presets, and vendor files from vst_presets, load into a saved instance of the plugin. The first time one is needed, project_write opens the plugin in FL, saves it, and keeps that state in tmp/states/, which takes a few seconds once per plugin.

  • NKS .nksf presets for any VST3 plugin, matched to it by the plugin id inside the file, from Native Instruments' User Content, the libraries in Public Documents, and config nks_presets; they need no saved instance.

  • Presets built into a plugin, for a VST3 plugin with a parameter named Program, such as TDR Kotelnikov: the harvest steps that parameter in FL and keeps each preset's state in tmp/states/<plugin>.programs/, dropping exact duplicates such as empty user slots. A plugin with no preset files shows them after presets(plugin, harvest=True).

Parameter maps: open a copy of the library in FL (the sweep leaves every knob at 1) and send the text of scripts/params_fl.py through fl_exec once. Then _kz_dump('tmp/params/pass1_all.json'); for each v in 0, .25, .5, .75, 1, four separate fl_exec calls, _kz_sweep(v, 'set'), _kz_sweep(v, 'nudge'), _kz_sweep(v, 'back'), _kz_read('tmp/params/sweep_<v>.json') (a display read in the call that set it is stale); then python scripts/parammap.py writes docs/params/. Each function takes only and skip lists of plugin names as FL reports them (docs/params/INDEX.md, column as FL names it).

Project JSON, compact form

{
 "format": "compact",
 "base": "projects/init/init.flp",
 "project": {"bpm": 175, "ppq": 96},
 "instruments": [{"id": "lead", "kind": "plugin", "plugin": "serum2", "preset": "C:/presets/lead.SerumPreset", "mixer": 1},
                 {"id": "keys", "kind": "plugin", "plugin": "flex", "preset": "Hard 808s/808 Clean Fuzz", "mixer": 2},
                 {"id": "pad", "kind": "plugin", "state": {"from": "projects/my_song.flp", "channel": 3}, "mixer": 3}],
 "samples": [{"id": "snare", "kind": "audio", "path": "C:/samples/snare.wav", "mixer": 8}],
 "automation": [{"id": "fade", "kind": "automation", "target": {"mixer": 0, "param": "vol"}, "points": [[0, 0.8], [32, 0.0]]}],
 "mixer": {"volume": {"1": 0.729, "7": 0.434}, "main_volume": 0.6625},
 "note_cols": ["bar", "beat", "tick", "len", "key", "vel", "inst"],
 "patterns": [{"id": "lead_a", "notes": [[1, 1, 4, 66, "A#4", 96, 0], [1, 2, 3, 18, "G#4", 80, 0]]}],
 "clip_cols": ["track", "bar", "beat", "tick", "len", "src", "trim?"],
 "arrangements": [{"name": "Arrangement", "clips": [[5, 17, 1, 0, 1536, "lead_a"], [4, 17, 3, 0, 31, "s0"], [20, 1, 1, 0, 27648, "a0"]]}]
}
  • Time: [bar, beat, tick], 1-based bar and beat, 96 ticks per beat, 4/4. Lengths in ticks. Exact integers; no grid is imposed.

  • Keys: note names, MIDI 60 = C4 (FL's own UI calls MIDI 60 C5). Flats accepted.

  • Pointers: a note's inst is an index into instruments. A clip's src is a pattern id, s<N> (sample N) or a<N> (automation N), so no instrument or pattern id may look like s1 or a1.

  • Patterns hold notes for any number of instruments. A clip's len sets how much of a pattern plays.

  • Instruments: state: {from: file, channel: n} copies that channel whole, preset and routing included, from any FL-saved project, switched on even when it was muted there (muted: true keeps it off; project_read reports a muted channel with muted: true); or any plugin by name (Plugins by name). preset loads a sound into it: an id from presets, or a .SerumPreset, .vital, .h2p or .fxp path, or <pack>/<preset> for FLEX. mixer: n routes it. Serum 1 .fxp are not supported.

  • Sampler channels: "kind": "sampler" with a path loads that file into a sampler, so notes pitch it (C4 = original pitch). A sampler plays its sample to the end whatever the note length; cut chops to their own files first (chop.py).

  • Song mode: compact documents are saved in song mode so FL and its command-line render play the arrangement; project.song_mode: false saves pattern mode.

  • Samples: path, or state to copy one. An audio clip without trim plays the whole sample; trim is [start_ms, end_ms] into the sample. A path may start with %FLStudioFactoryData%, FL's own token for its install folder, so %FLStudioFactoryData%/Data/Patches/Packs/Drums/Kicks/808 Kick.wav finds FL's factory kick on any machine.

  • Project info: project takes title, author, genre and comment, written into FL's project info (FL shows the title in its window), and project_read returns them.

  • Automation: points are [beat, value, tension?] in beats from the clip start. Targets: {"global": "tempo" | "main_pitch"}, {"mixer": t, "param": "vol" | "pan" | "sep"} (insert 0 is the master: its fader is the overall level), {"mixer": t, "slot": s, "param": n} (effect parameter n), {"mixer": t, "slot": s, "rec": "0x1f00"} (the slot's mute) or "0x1f01" (its mix), {"channel": id, "param": n} (instrument parameter n) or {"channel": id, "param": "vol" | "pan" | "pitch" | "fcut" | "fres" | "mute"}. Values: tempo = (bpm - 60) / 120; main pitch 0.5 in tune, +-12 semitones; mixer volume 0.8 = 0 dB; pan 0 left, 0.5 centre, 1 right; sep 1 mono, 0 widest; channel pitch 0.5 in tune, +-48 semitones; channel volume 0.78 is FL's default. {"global": "main_vol"} is written but FL 2025 ignores it. examples/README.md lists the scales measured so far (fcut, fres and mute are written but their scales were not measured).

  • Mixer effects: mixer.effects: [{"track": 3, "slot": 0, "plugin": "<name>", "preset": "<id>"}] puts that effect in the given slot, replacing what was there; from: {file, track, slot} in place of plugin copies one with its settings from a saved project.

  • Mixer routes: mixer.routes: [{"from": 11, "to": 10, "level": 0.0}] routes insert 11 to insert 10; level 0 is a sidechain-only send, which is what a sidechained limiter or compressor listens to. "on": false removes a route.

  • Mixer volume: mixer.volume maps insert -> fader, 0.8 = 0 dB; main_volume is FL's global main volume.

  • base: the file whose globals, unmapped sections, arrangement track templates and mixer are kept. Building on one of your own projects keeps its mixer chains. Default: the template key.

The compact form leaves out bytes that are not mapped. For editing an existing project without losing anything, use view="full".

Not written yet

Mixer pans and sends as static settings; a plugin FL's plugin manager has not scanned; pattern names; time signature; vendor preset files for VSTs whose state is neither JUCE XML nor #zip# (an .fst saved from FL is their route). See docs/FLP.md, Open.

License

MIT, see LICENSE. It covers this code and these docs, not FL Studio, the plugins or their presets.

Available Tools

15 tools
configA
Idempotent

The paths on this machine the server needs (FL, loopMIDI, FL's Hardware folder, preset libraries), stored in kuruitsugizaki.json. Call it first in a new install, and whenever another tool answers that a key is not set. No arguments: every key with its value or the path detected for it, and whether that path exists. key alone: that key. key and value: set it. Never guess a path or search the disk for one: ask the user where it is, then set it.

NameRequiredDescriptionDefault
keyNoa key name, as the no-argument call lists them, e.g. 'fl_exe'
valueNothe path to set for key; omit to read the key

TDQS

A4.3/5.0
Behavior4/5

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

With destructiveHint=false, idempotentHint=true and readOnlyHint=false already declaring the safety profile, the description adds real context: the persistence target (kuruitsugizaki.json), the fact that a set mutates stored config, and the existence check returned for detected paths. It does not discuss permissions or failure behavior, but the core behavioral traits are disclosed.

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?

Purpose is front-loaded, followed by usage triggers, then the mode semantics and the prohibition. Every sentence is functional and none is padding, even though it is a single dense paragraph.

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

Completeness5/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 compensates by explaining the return shape of the no-argument call ('every key with its value or the path detected for it, and whether that path exists'). All three call modes, the storage file, and operational guidance are covered, so an agent has everything needed to invoke it correctly.

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 100% and each parameter is already documented, so the baseline is 3. The description's 'key alone / key and value' mapping reinforces the schema's semantics but adds little beyond what is already written in the property descriptions.

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 names the resource concretely — the machine-local paths the server needs (FL, loopMIDI, FL's Hardware folder, preset libraries) persisted in kuruitsugizaki.json — and then spells out the three operating modes (list-all, read-one, set-one). It is specific about what the tool does, though it never explicitly contrasts itself against siblings like fl_probe or fl_install; that differentiation is only implied.

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

Usage Guidelines5/5

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

It gives explicit triggers ('call it first in a new install', 'whenever another tool answers that a key is not set') and an explicit prohibition with an alternative action ('Never guess a path or search the disk... ask the user where it is, then set it'). An agent knows both when to reach for it and what not to do instead.

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

fl_callA
Destructive

Call one function of FL's scripting API inside the running FL and return what it returns: {ok, value} or {ok: false, error}. For a single read or change, e.g. a parameter name or a mixer level of the open project. Use fl_exec for several calls or logic; use project_read and project_write for anything the .flp file holds, which need no FL. A setter changes the open project as an edit by hand would; nothing is saved. Needs FL open; it is not started for this.

NameRequiredDescriptionDefault
fnYesmodule.function as FL's API names it, e.g. 'plugins.getParamName'
argsNoits positional arguments, e.g. [0, 5, -1]

TDQS

A4.5/5.0
Behavior4/5

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

Goes beyond the annotations by disclosing the return shape ({ok, value} vs {ok: false, error}), that a setter mutates the open project 'as an edit by hand would', that nothing is saved, and that FL must already be running. The destructiveHint=true annotation is consistent with the setter caveat. It stops short of stating whether partial failures or invalid fn names are recoverable, but the added context is substantial.

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?

Front-loads the core action and return contract, then layers usage routing and preconditions. Every sentence carries distinct information with no restatement of the name or schema.

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

Completeness5/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 supplies the return contract itself, plus precondition (FL open), mutation semantics (edit-like, unsaved), and routing to alternatives. Nothing an agent needs before invoking a generic API-dispatch tool is missing.

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%, so 'fn' (module.function) and 'args' (positional array) are already documented with examples in the schema. The description adds only an illustrative use case ('a parameter name or a mixer level') rather than deeper semantics, so baseline 3 applies.

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

Purpose5/5

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

States a specific verb ('call one function of FL's scripting API') plus the exact return envelope, and positions it against siblings: fl_exec for multiple calls/logic, project_read and project_write for .flp contents. An agent can distinguish this from any other tool in the list without opening a schema.

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

Usage Guidelines5/5

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

Gives explicit selection criteria: use this for 'a single read or change', fl_exec for several calls or logic, project_read/project_write for anything the .flp holds. It also names a precondition — FL must be open and is not started for this — so the agent knows when the call will fail.

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

fl_execA
Destructive

Run Python inside the running FL's embedded interpreter, where FL's modules (channels, mixer, plugins, transport, patterns, general ...) import. For live reads or changes that need several calls or logic; one call is simpler with fl_call. Returns {ok, value} with what the code assigns to result, or {ok: false, error} with the traceback. FL's sandbox refuses files, sockets and pipes. Changes act on the open project and are not saved. Needs FL open; it is not started for this.

NameRequiredDescriptionDefault
outNowrite the result as JSON to this path (relative to the repo) and return only its size, for large reads; also when `result` is {'__out__': path, 'data': value}
codeYesPython source; assign the answer to `result`
timeoutNoseconds to wait for FL's answer

TDQS

A4.4/5.0
Behavior4/5

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

Goes well beyond the annotations by disclosing the sandbox restrictions (no files, sockets, pipes), that changes act on the open project and are not saved, and the exact return shape for success and failure. The destructiveHint=true annotation is qualified rather than contradicted — mutations are real but discarded — which is valuable context. Minor gap: no mention of timeout behavior or long-running code.

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?

Front-loads the core purpose and keeps every sentence load-bearing, but the later clauses are packed with multiple semicolon-joined facts in a single sentence, making it slightly denser than necessary.

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

Completeness5/5

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

Despite no output schema, the description fully documents return values, the error/traceback form, sandbox limits, persistence semantics, and the FL-must-be-open prerequisite. Nothing an agent needs to invoke it correctly is missing.

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%, so code, out, and timeout are already documented. The description reinforces the `result` assignment convention but adds no syntax, format, or edge-case detail about `out` or `timeout` beyond what the schema states, so baseline 3 applies.

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

Purpose5/5

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

Starts with a specific verb+resource ('Run Python inside the running FL's embedded interpreter') and enumerates the importable modules. It also names the sibling it differs from ('one call is simpler with fl_call'), so an agent can pick it out of a crowded toolset without opening a schema.

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

Usage Guidelines5/5

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

Gives an explicit selection rule: use this when work needs several calls or logic, otherwise prefer fl_call. It also states the prerequisite ('Needs FL open; it is not started for this'), which is exactly the when-not guidance an agent needs.

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

fl_installA
DestructiveIdempotent

Set up the live link to FL. Needed once per install, and again after this folder moves. Close FL first. It does two things: 1) writes FL's controller script into FL's Settings\Hardware folder (config key fl_hardware), with this folder's bridge path in it, replacing an older copy; 2) unless a MIDI input in FL already has the script, makes a loopMIDI port named kuruitsugizaki and assigns the script to it in FL's MIDI settings. Both live in the registry, which FL rewrites when it closes; if FL was open, the answer's midi entry says so and what to do by hand. Returns {ok, installed, bridge, changed, midi, next}. Then start FL and call fl_probe to see the script answer.

NameRequiredDescriptionDefault

No parameters

TDQS

A4.9/5.0
Behavior5/5

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

The annotations already declare mutation, destructiveness, and idempotency, and the description adds meaningful operational detail: it replaces an older controller script, conditionally creates and assigns a loopMIDI port, and explains registry-rewrite behavior. The note about FL being open and the returned midi guidance further reduces ambiguity.

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 front-loaded with the main action and then uses a clear numbered structure for the two effects. Despite covering a complex install flow, every sentence carries useful operational information and there is no filler.

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

Completeness5/5

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

For a destructive, stateful setup tool with no output schema, the description is complete: it covers prerequisites, side effects, registry caveats, the returned fields, and the recommended next call. Nothing essential for correct invocation is omitted.

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 no parameters, so the baseline is 4. The description does not need to explain parameter semantics, and it correctly focuses on behavior and return value instead.

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

Purpose5/5

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

The description states a specific verb and resource: setting up the live link to FL. It immediately enumerates the two concrete setup actions, so the tool is distinguishable from fl_probe and other siblings.

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

Usage Guidelines5/5

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

It gives explicit usage conditions: needed once per install and again after the folder moves, with the prerequisite to close FL first. It also names the follow-up tool fl_probe, so the agent knows the next step in the workflow.

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

fl_probeA
Idempotent

Check the live link to FL: returns FL's scripting API version, its embedded Python version, FL's pid and the pipe handle it holds, or an error saying what is missing. Call it first when a live tool (fl_exec, fl_call, fl_transport, project_write with open) fails, and after fl_install. When FL is closed it starts it (and loopMIDI) to test the link and closes it again: launched_fl_seconds says how long FL took, closed_fl that it was closed. Reads nothing from the project.

NameRequiredDescriptionDefault

No parameters

TDQS

A4.8/5.0
Behavior5/5

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

Annotations say readOnlyHint=false but not why; the description fills that gap by disclosing the actual side effect — when FL is closed it launches FL (and loopMIDI) to test the link, then closes it again. It also clarifies scope ("Reads nothing from the project") and names the response fields launched_fl_seconds and closed_fl, so the agent knows a slow call is expected behavior rather than a hang.

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?

Front-loaded with the check-and-return contract, then the call conditions, then the side effect — a sensible order with no filler. The clause "launched_fl_seconds says how long FL took, closed_fl that it was closed" is elliptically compressed and takes a re-read, which keeps it just below a 5.

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

Completeness5/5

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

No output schema exists, so the description carries the full burden of describing return values — and it does, listing the version fields, pid, pipe handle, error shape, and the two launch/close indicators. Combined with the failure-recovery guidance, an agent has everything needed to call it and interpret the result.

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 no parameters and the schema is empty at 100% coverage, so there is nothing for the description to clarify. Baseline 4 applies; no parameter guidance is needed or missing.

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

Purpose5/5

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

States a specific verb and resource ("Check the live link to FL") and enumerates exactly what it returns: scripting API version, embedded Python version, pid, pipe handle, or a descriptive error. It also names the sibling live tools (fl_exec, fl_call, fl_transport, project_write) so an agent can place it in the tool set without opening any schema.

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

Usage Guidelines5/5

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

Gives explicit triggering conditions: call it first when a live tool fails, and after fl_install. This is a precise when-to-use rule tied to named siblings, not an implied one.

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

fl_renderA
DestructiveIdempotent

Render an .flp to audio: a .wav and .mp3 beside it (replacing earlier ones), then a spectrogram and a short report. Call it after project_write to check a piece. FL renders from the command line, so an FL the harness started is saved first and closed; an FL the user started is left alone and the render refused until they close it. Runs detached and returns at once; a 2-minute piece takes under a minute. Returns {ok, rendering, log, saved_open_project}. Then call render_report(path) until it stops saying the render is running, and make no live call (fl_exec, fl_call, fl_transport) before that: FL is closed while it renders.

NameRequiredDescriptionDefault
keyNothe key the piece is written in, e.g. 'F minor' or 'G#m'; the log then says how much pitch energy falls outside its scale
pathYesthe .flp to render
reopenNoopen the project in FL again when done

TDQS

A4.2/5.0
Behavior3/5

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

Annotations already declare destructiveHint=true and idempotentHint=true, and the description's 'replacing earlier ones' is consistent with that. It adds substantial useful context – detached execution, timing, harness-saved-and-closed behavior, refusal when user FL is open, and the return shape – which is meaningful beyond annotations. However, several of these (return shape, follow-up loop) are more procedural than behavioral-safety disclosure, so a 3 is appropriate rather than the top of the range.

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?

Dense and front-loaded: the core action and artifacts come first, prerequisites and caveats follow. A few sentences are lengthy (the FL closed-while-rendering note), but every sentence carries operational information. Slightly long, but no filler.

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

Completeness5/5

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

Although there is no output schema, the description spells out the return object {ok, rendering, log, saved_open_project} and the follow-up protocol (poll render_report until it stops saying rendering). For a detached, stateful render tool, an agent has everything needed to call it correctly and handle the async result.

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 all three parameters are fully described in the schema (key, path, reopen), so the schema does the heavy lifting. The description does not add syntax or meaning beyond the schema for these parameters. Baseline 3 applies.

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

Purpose5/5

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

Specific verb and resource (render an .flp to audio) plus the exact artifacts produced: .wav, .mp3 beside it, a spectrogram, and a short report. Clearly distinguishes itself from siblings by naming project_write, render_report, fl_exec, fl_call, and fl_transport with their relationship to this tool.

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

Usage Guidelines5/5

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

Explicitly says when to call it (after project_write to check a piece) and gives a negative constraint: make no live call (fl_exec, fl_call, fl_transport) before the render stops running. It also explains the refusal condition for a user-started FL instance, leaving no ambiguity about prerequisites.

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

fl_transportA
Idempotent

Play or stop whatever project is open in the running FL, to hear it; it changes nothing in any file. action 'play' plays from the start, also when called while playing. action 'stop' stops playback. mode 'song' plays the arrangement, 'pattern' loops one pattern (pattern: its number, selected first); without mode FL keeps the one it has. Needs FL open with a project; it is not started for this: open one with project_write(open=true), which can also start playback itself (play='song'). Returns {playing, mode}. To get audio out, use fl_render, which saves and closes FL instead.

NameRequiredDescriptionDefault
modeNo'song' or 'pattern'; omit to keep FL's
actionYes'play' or 'stop'
patternNoin pattern mode, the pattern number to select first

TDQS

A4.5/5.0
Behavior4/5

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

Adds real context beyond the annotations: nothing is written to any file, FL is not launched, playback restarts from the beginning even when already playing, and the return value is {playing, mode}. Minor tension with idempotentHint=true since a repeated 'play' restarts playback, but the description discloses this rather than hiding it, so it informs the agent.

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?

Front-loaded with the core action and its effect on files, and every sentence carries information. It is dense and semicolon-heavy, bordering on run-on, which slightly slows parsing but does not waste words.

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

Completeness5/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 supplies the return shape ({playing, mode}), the runtime prerequisite, the mode fallback behavior, and the handoff to fl_render for actual audio. Nothing an agent needs to call this correctly is missing.

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

Parameters5/5

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

Schema coverage is 100%, yet the description still adds semantics the schema lacks: 'song' means arrangement, 'pattern' loops a single pattern, the pattern number is selected first, omitting mode preserves FL's current mode, and play always starts from the beginning. This is meaningful enrichment over bare enum-like strings.

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

Purpose5/5

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

States a specific verb pair (play/stop) and resource (the open project's transport in the running FL), and explicitly scopes it as non-file-changing. It also distinguishes itself from fl_render, which saves and closes FL, so an agent can separate it from the nearest sibling.

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?

Gives clear preconditions (FL must already be open with a project; use project_write(open=true) otherwise) and names the alternative for audio capture (fl_render). It does not state when *not* to use it in favor of fl_probe or fl_call, but the routing guidance it does give is strong.

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

paramsA
Read-onlyIdempotent

A plugin's automatable parameters, for writing automation: each one's index (the param of an automation target {channel: id, param: index} or {mixer: t, slot: s, param: index}), its name, and what its normalised value means where measured (FL's display at 0, .25, .5, .75 and 1, so a value can be picked for a wanted Hz, dB or %). Call it before automating a plugin or effect knob. It answers only for plugins with a parameter map (plugins shows which); for any other, read names live with fl_call('plugins.getParamName', ...). Not for choosing a sound: plugins lists what is installed, presets a plugin's presets. Reads files only; FL need not run.

NameRequiredDescriptionDefault
kindNo'instrument' or 'effect', for a name that is both; without it the instrument is taken
queryNowords that must all appear in the parameter name, case-insensitive, e.g. 'filter cutoff'
pluginYesthe plugin's name as plugins lists it; a unique part of it works

TDQS

A4.6/5.0
Behavior5/5

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

Annotations already cover safety (readOnly, idempotent, non-destructive), and the description adds beyond them: it only answers for plugins with a parameter map (a real coverage limitation) and that it 'reads files only; FL need not run', telling the agent it works without a live session.

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?

Front-loaded with the core purpose and output meaning, then routing and caveats. Dense but every sentence carries information; the long nested automation-target parenthetical is the only heavy patch.

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

Completeness5/5

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

No output schema exists, so the description must explain returns — and it does: index usable as an automation target, name, and the normalised-value display at 0/.25/.5/.75/1 so a value can be chosen for a target Hz, dB or %. Nothing needed to call it correctly is missing.

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 the schema already documents 'kind' (instrument/effect disambiguation), 'query' (case-insensitive all-words match), and 'plugin' (name from plugins). The description adds little parameter-level detail beyond implying that names are matched against the plugin's list; baseline 3 is appropriate.

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

Purpose5/5

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

States a specific verb+resource: it returns a plugin's automatable parameters, each with its index, name, and what its normalised value means. It explicitly distinguishes itself from 'plugins' (lists what's installed), 'presets' (a plugin's presets), and fl_call('plugins.getParamName', ...) for plugins without a parameter map.

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

Usage Guidelines5/5

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

Gives an explicit trigger ('Call it before automating a plugin or effect knob') and explicit non-uses ('Not for choosing a sound: plugins lists what is installed, presets a plugin's presets'), plus the fallback route for plugins lacking a parameter map.

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

pluginsA
Read-onlyIdempotent

List the plugins this machine has: every plugin in FL's plugin database, and every tuned instance in the optional library project. Call it to choose instruments and effects before project_write; then presets for a plugin's presets, params for its automatable parameters. Each row: name, kind (instrument or effect), vendor, format (native, vst3, clap, vst), source (fl or library), how many presets load by name, whether it has a parameter map. Any of them goes into project_write by name: an instrument as {kind: plugin, plugin: , preset?, format?}, an effect as mixer.effects [{track, slot, plugin: , preset?, format?}]; without a preset it arrives as if dragged in fresh from FL's browser, a library instance as saved. A plugin installed in several formats is one name (native, then vst3, clap, vst unless format is given). By default it lists only VST3 and CLAP plugins; native=true adds FL's own. Reads files only; FL need not run.

NameRequiredDescriptionDefault
queryNokeep names containing this text, case-insensitive, e.g. 'serum'; omit for all
nativeNotrue also lists FL's own (native) plugins

TDQS

A4.7/5.0
Behavior5/5

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

Annotations already declare a safe read-only operation, but the description adds substantial behavior: file-only reads, no running FL instance needed, default filtering behavior, format deduplication rules, and the exact row fields returned.

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?

Despite its length, the description is front-loaded with the core purpose and every sentence carries useful information about return fields, filtering, deduplication, or project_write integration. There is no redundant filler.

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

Completeness5/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 compensates by documenting the returned row fields and how names map into project_write. Combined with annotations and full schema coverage, an agent has enough context to call it correctly.

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 100%, so the parameter meanings are fully documented in the schema. The description repeats the native behavior but adds no new semantics for query, making the baseline 3 appropriate.

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

Purpose5/5

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

States a specific verb and resource: list the plugins this machine has, covering both FL's plugin database and tuned library instances. It clearly distinguishes itself from siblings like presets and params while also explaining how results feed into project_write.

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

Usage Guidelines5/5

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

Explicitly says to call it before project_write to choose instruments and effects, and directs the agent to presets or params for plugin subresources. It also explains the default VST3/CLAP-only listing and the native=true override.

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

presetsA
Idempotent

List the presets that load by name for one plugin; an id goes into project_write as an instrument's or effect's preset. Call it after plugins, when choosing a sound. Returns {plugin, kind, total, presets}; total counts every match, and when there are more than limit the list is an even spread across the preset folders, each folder an equal share, not the first ones. A plugin name that matches nothing or several plugins returns {ok: false, error} naming the candidates. Reads files only and FL need not run, except with harvest, which opens the plugin in FL and adds its built-in presets to the catalog.

NameRequiredDescriptionDefault
kindNo'instrument' or 'effect', for a name that is both (Serum2); without it the instrument is taken
limitNoat most this many ids
queryNowords that must all appear in the id, case-insensitive, any order, e.g. 'bass reese'
pluginYesthe plugin's name as plugins lists it; a unique part of it works
harvestNofirst read the plugin's built-in presets from FL (opens it there once, about a second per preset); for a plugin whose presets live inside it, not in files

TDQS

A4.7/5.0
Behavior5/5

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

Goes well beyond the annotations: discloses the return shape, that total counts all matches, that limit produces an even spread per preset folder rather than a truncated prefix, the {ok:false, error} result for ambiguous/unknown plugin names, and that harvest opens the plugin in FL at ~1s per preset. This also explains why readOnlyHint=false despite the otherwise file-only read.

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?

Purpose and caller order come first, then return shape, then paging semantics, then failure mode, then the harvest caveat. Dense but every sentence carries information an agent would otherwise have to discover by error.

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

Completeness5/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 supplies both the success payload keys and the error payload, states the FL-runtime caveat for harvest, and covers the ambiguous-plugin failure. Nothing needed to call this correctly is missing.

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?

Schema coverage is 100%, so the baseline is 3; the description still adds value by explaining what the returned id is consumed by and how a plugin name that matches several plugins fails with named candidates. Parameter-level details (kind, query, limit) are left to the schema.

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

Purpose5/5

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

Specific verb + resource (list presets for one plugin) plus the downstream consumer ('an id goes into project_write as an instrument's or effect's preset'), which tells an agent exactly what the output is for. It also names the ordering dependency on the 'plugins' sibling, so it is clearly distinguishable from others in the set.

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?

'Call it after plugins, when choosing a sound' gives an explicit sequencing rule and trigger condition, and the harvest note says when the harvest variant applies (presets living inside the plugin, not on disk). No explicit when-not or comparison to the adjacent 'samples' sibling is given, which keeps it short of a 5.

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

profileA
Idempotent

List a person's projects from a folder of their .flp files: tempo, key and arrangement length in bars, so you know which to open and read in full with project_read. Reads every .flp under the folder, subfolders included, and changes none of them; FL need not run; about 2 s for 80 projects. Also written as profile.md and profile.json to tmp/profile//. Projects that fail to read are listed, not fatal; a folder with no .flp returns {ok: false, error}. Without folder it reads config projects_folder; when that is not set, ask the user where their own projects are and pass that folder, which is then saved there, so later sessions do not ask again. When they have none, set projects_folder to 'none' with config, and profile then answers that.

NameRequiredDescriptionDefault
folderNothe folder of .flp projects, absolute or relative to the repo; omit to use config projects_folder

TDQS

A4.6/5.0
Behavior4/5

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

Adds substantial context beyond annotations: reads subfolders recursively, FL need not be running, ~2s for 80 projects, writes profile.md/profile.json to tmp/profile, failed reads are listed not fatal, and the {ok: false, error} shape for an empty folder. The readOnlyHint=false annotation is consistent (the tool writes report files while changing no .flp), and the description clarifies this distinction.

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?

Front-loaded with what it does and returns before the fallback logic, and every clause carries information. It is a dense, semicolon-heavy run-on paragraph, costing a little readability, but little is wasted.

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

Completeness5/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 fully carries the return burden: it lists per-project fields, the error shape, the on-disk artifacts, and the config resolution behavior. Nothing an agent needs to call it correctly is missing.

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?

Schema coverage is 100% and the folder parameter is already documented, so the schema carries the base meaning. The description adds value beyond it by explaining the full default chain (config projects_folder, then ask-and-persist), which the schema only gestures at with 'omit to use config projects_folder'.

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

Purpose5/5

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

States a specific verb+resource ('List a person's projects from a folder of their .flp files') and enumerates the returned fields (tempo, key, arrangement length in bars). It explicitly distinguishes itself from the sibling project_read ('which to open and read in full with project_read').

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

Usage Guidelines5/5

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

Explicitly positions itself as the lightweight triage step before project_read, and gives detailed fallback guidance: omit folder to use config projects_folder, ask the user and save it when unset, and set projects_folder to 'none' when the user has none. When and when-not are both covered.

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

project_readA
Read-onlyIdempotent

Read one FL Studio .flp file into JSON; FL need not run and the file is not changed. Use it to see what a project holds, to take parts from it, or to check what project_write wrote. For the style across many projects use profile; for the project open in FL right now, fl_exec. Views: 'summary' (start here: instruments, per-pattern stats, a per-track arrangement timeline, the parts sounding in each bar, mixer effects); 'compact' (default: every note and clip as rows, the same shape project_write accepts; notes [bar, beat, tick, len_ticks, key, vel, instrument#], clips [track, bar, beat, tick, len_ticks, src, trim?] where src is a pattern id, s a sample, a an automation clip); 'full' (exact, round-trips byte for byte; large, so narrow it with patterns or arrangements); 'score' (a bar range of the first arrangement as text, one row per step and one column per part, so how the parts line up can be read; bars [first, last]). Fails with the parser's error on a file that is not an .flp.

NameRequiredDescriptionDefault
barsNoscore only: [first, last] bar, at most 16; default the first 4
pathYesthe .flp file, absolute or relative to the repo
viewNo'compact', 'summary', 'score' or 'full'compact
unusedNoalso list patterns not placed in the playlist and parked clips
patternsNoonly these pattern ids (compact, full and score)
arrangementsNoonly these arrangements, by name

TDQS

A4.8/5.0
Behavior5/5

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

Annotations already declare readOnly/idempotent/non-destructive, but the description goes well past them: it states the file is unchanged, warns that 'full' is large and should be narrowed with patterns or arrangements, and discloses the failure mode ('the parser's error on a file that is not an .flp').

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?

Front-loaded with the core action and the not-running/not-modified guarantees before any detail. It is long, and the view catalogue is dense, but nearly every clause carries decision-relevant information; only the inline tuple formats are slightly heavy for a description.

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

Completeness5/5

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

With six parameters, no output schema, and four view modes, the description supplies exactly what is missing: the return shape per view, the default, the sizing caveat for 'full', and the error behavior. An agent can pick a view and call it correctly without opening anything else.

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?

Schema coverage is 100% and already documents bars, patterns and arrangements, so the schema carries the basics. The description still adds real value by explaining what each view returns and in what shape (note and clip row formats, per-bar sounding parts, score layout) and by naming 'compact' as default and 'summary' as the starting point.

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

Purpose5/5

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

States a specific verb and resource ('Read one FL Studio .flp file into JSON') plus two crucial scope facts: FL need not be running and the file is not modified. It explicitly distinguishes itself from siblings profile and fl_exec by naming what those cover instead.

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

Usage Guidelines5/5

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

Gives three concrete use cases ('see what a project holds', 'take parts from it', 'check what project_write wrote') and names the alternatives with the condition that selects them: profile for style across many projects, fl_exec for the project open in FL right now. Nothing is left to inference.

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

project_writeA
DestructiveIdempotent

Write a project document to an .flp file, replacing any file at path. This is how a piece gets made.

The document: the compact form project_read returns, or its full form. The field reference is README.md, 'Project JSON, compact form'; examples/README.md has a working document per feature. Read one before a first write.

Sounds:

  • an instrument is a plugin by name (see plugins) with an optional preset, or a channel copied from a saved project, state {from: file, channel: n};

  • an effect is mixer.effects {track, slot, plugin} or one copied, {track, slot, from: {file, track, slot}}.

Units that are easy to get wrong: 96 ticks per beat, 4/4; keys like 'D#4' with MIDI 60 = C4; mixer volume 0.8 = 0 dB; a tempo automation value is (bpm - 60) / 120. Mixer inserts run 1-125.

Without open, FL need not run. With open or play, FL first saves the project it has open (so no dialog appears), then opens this one.

Returns the file read back (channels, notes per pattern, clips per arrangement) and the writer's warnings; read them.

NameRequiredDescriptionDefault
docYesthe project document, compact or full
openNoopen it in FL afterwards, launching FL if needed
pathYesthe .flp to write, absolute or relative to the repo; pieces go to projects/music/<piece>.flp
playNo'song' or 'pattern': open it and start playback

TDQS

A4.4/5.0
Behavior4/5

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

Annotations already declare destructiveHint=true and idempotentHint=true, but the description adds genuine operational detail beyond them: the file at path is replaced, FL need not be running unless open/play is used, and FL first saves its currently open project before opening this one. The side-effect chain (launch FL, save existing project) is disclosed, which annotations alone do not convey.

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?

Front-loaded with purpose and the destruction semantics, then organized into scannable sections (sounds, units, behavior, returns). Dense but each block is functional; the units section is arguably long but directly prevents common errors.

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

Completeness5/5

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

For a tool with no output schema and nested input, the description covers return values ('the file read back... and the writer's warnings; read them'), input format and reference material, unit conventions, and open/play side effects. An agent has what it needs to construct a document and predict consequences.

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?

Schema coverage is 100%, so baseline is 3, but the description meaningfully elaborates the complex nested doc parameter: compact vs full form, the 'sounds' shapes (instrument as plugin+preset, effect as mixer.effects or copied form). It also warns about easy-to-mistake units. This adds real value over the schema's terse 'compact or full' note.

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

Purpose5/5

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

States a specific verb and resource: 'Write a project document to an .flp file, replacing any file at path.' This makes clear it is the write counterpart to project_read, and the follow-up 'This is how a piece gets made' frames the outcome an agent produces.

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?

Given clear workflow context: 'Read one before a first write' points the agent to the README/example reference, and 'Without open, FL need not run' contrasts the open/play variants. It stops short of explicitly routing to sibling tools (e.g. project_read) by name, so 4 rather than 5.

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

render_reportA
Idempotent

Read what fl_render produced: the short report (length, peak, key, the number of parts sounding in each bar, and a flag only where something is found) and the spectrogram picture, as [text, image]. Call it after fl_render; it does not wait, and while the render is still going it says so: call again. With no render on record it answers to call fl_render first; a render that failed comes back as its log. Look at the picture before handing a piece over; the full analysis is in the .txt the report names. FL need not run. It writes into tmp/spectro/ only: a resized picture, and the spectrogram and its .txt again from the .wav when the log has no analysis.

NameRequiredDescriptionDefault
pathYesthe path given to fl_render, or the .wav beside it; only its file name is used to find the render, so two pieces with the same name in different folders share one report

TDQS

A4.5/5.0
Behavior5/5

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

Goes well beyond the annotations: it discloses non-blocking behavior ("it does not wait... while the render is still going it says so: call again"), the failure path (a failed render returns its log), and concrete side effects ("writes into tmp/spectro/ only" — a resized picture plus regenerated spectrogram and .txt). These are consistent with readOnlyHint=false, idempotentHint=true and destructiveHint=false, and add real operational context.

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

Conciseness3/5

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

Information-dense but written as a semicolon-chained run-on with oblique phrasing ("it answers to call fl_render first"), which forces re-reading. The most important fact — that it reads rather than renders — is front-loaded, but the middle clauses bury the polling instruction and side-effect notes.

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

Completeness5/5

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

Despite no output schema, the description covers the return shape ([text, image]), what the text contains, the in-progress case, the failure case, the no-prerequisite case, and the on-disk side effects. An agent has everything needed to call it correctly and interpret its result.

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 100% and the schema already explains that only the file name is used to locate the render, including the same-name collision caveat. The prose only echoes this indirectly ("the .wav beside it"), so it adds little meaning beyond the structured field — the baseline 3 applies.

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

Purpose5/5

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

States a specific verb and resource — read what fl_render produced — and enumerates the two return artifacts (short report text and spectrogram image) as [text, image]. It is explicitly positioned against the sibling fl_render that generates the output, so an agent can tell the producer from the reader without opening either schema.

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

Usage Guidelines5/5

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

Gives explicit ordering ("Call it after fl_render"), an alternative when the precondition is unmet ("With no render on record it answers to call fl_render first"), and downstream workflow guidance ("Look at the picture before handing a piece over"). It also states that FL need not be running, removing a common source of mis-invocation.

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

samplesA
Idempotent

List samples for drums, one-shots, loops and breaks; a sample's path (its folder plus its name) goes into project_write as a sampler's or audio clip's path. Call it before choosing any sample, and take samples only from folders the user gave.

No arguments: the user's sample folders, each with its subfolders and how many audio files each holds. With query, the samples whose path matches; with folder, that folder's subfolders and files, and a query stays inside it. Returns {total, results: {folder: [[name, seconds]]}}; past limit the list is an even spread across folders.

When config sample_folders is not set it returns {ok: false, error}: ask the user where their samples are and set it with config (a folder or a JSON list), or 'none' when they have none, which makes FL's factory packs the source; the answer is kept.

Changes no sample file; FL need not run. It caches folder listings in tmp/samples/index/; measure also writes tmp/samples/.tsv.

NameRequiredDescriptionDefault
limitNoat most this many samples
queryNowords that must all appear in the path below the sample folder, case-insensitive, any order, any depth, e.g. 'snare tight'
folderNoone folder to look into: absolute, below a sample folder, or %FLStudioFactoryData%/...; omit for all sample folders
measureNoalso write the folder's own audio files' levels, width, onsets and centroid to tmp/samples/<folder>.tsv
max_foldersNoat most this many folders in a folder listing, whole levels from the top
max_secondsNokeep samples at most this long, e.g. 1 for one-shots
min_secondsNokeep samples at least this long

TDQS

A4.6/5.0
Behavior4/5

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

Annotations declare readOnlyHint=false, and the description reconciles that by stating 'Changes no sample file' while disclosing the actual writes: folder-listing cache in tmp/samples/index/ and a TSV when measure is set. It also documents the failure shape {ok: false, error} and that FL need not be running — context the annotations cannot express. Return-record format and truncation behavior are covered too, leaving only minor gaps like cache invalidation timing.

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?

Core purpose and the project_write handoff are front-loaded, and the paragraph breaks map to distinct modes (default, filtered, error, side effects). It is denser than it needs to be in places — semicolon-chained clauses and the tmp/ path details could be tightened — but no sentence is pure filler.

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

Completeness5/5

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

For a 7-parameter, all-optional tool with no output schema, the description supplies the return shape ({total, results: {folder: [[name, seconds]]}}), the error shape, truncation policy, and side effects. An agent has everything needed to call it correctly on the first try.

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?

Schema coverage is 100%, so the schema baseline already carries per-parameter meaning. The description nonetheless adds non-obvious semantics the schema omits: that the no-argument form lists all sample folders with subfolder counts, that a query stays confined inside a supplied folder, and that past limit the results are an even spread across folders rather than a truncated head.

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

Purpose5/5

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

Opens with a specific verb and resource ('List samples for drums, one-shots, loops and breaks') and immediately connects its output to a sibling ('a sample's path ... goes into project_write'). An agent can distinguish it from presets, plugins, and project_read without opening any schema.

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

Usage Guidelines5/5

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

Explicit sequencing ('Call it before choosing any sample'), an explicit constraint ('take samples only from folders the user gave'), and a documented recovery path when config sample_folders is unset (ask the user, then set it with config, or 'none' for factory packs). It names the alternative tool and the condition that selects it.

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. 5 tool updatesv0.4.5
    • Changedparams1 field changed
      • changedInput schema / properties / query / anyOf
        Previous value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "type": "string"
        +  },
        +  {
        +    "type": "integer"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
    • Changedplugins1 field changed
      • changedInput schema / properties / query / anyOf
        Previous value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "type": "string"
        +  },
        +  {
        +    "type": "integer"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
    • Changedpresets1 field changed
      • changedInput schema / properties / query / anyOf
        Previous value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "type": "string"
        +  },
        +  {
        +    "type": "integer"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
    • Changedproject_read3 fields changed
      • addedInput schema / properties / bars
        Added value: +{
        +  "anyOf": [
        +    {
        +      "items": {
        +        "type": "integer"
        +      },
        +      "type": "array"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "description": "score only: [first, last] bar, at most 16; default the first 4",
        +  "title": "Bars"
        +}
      • changedInput schema / properties / patterns / description
        Previous value: -"only these pattern ids (compact and full)"New value: +"only these pattern ids (compact, full and score)"
      • changedInput schema / properties / view / description
        Previous value: -"'compact', 'summary' or 'full'"New value: +"'compact', 'summary', 'score' or 'full'"
    • Changedsamples2 fields changed
      • changedInput schema / properties / max_folders / description
        Previous value: -"at most this many folders in a folder listing: whole levels from the top, the last level shared across its parents"New value: +"at most this many folders in a folder listing, whole levels from the top"
      • changedInput schema / properties / query / anyOf
        Previous value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "type": "string"
        +  },
        +  {
        +    "type": "integer"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
  2. 2 tool updatesv0.4.2
    • Changedrender_report1 field changed
      • changedInput schema / properties / path / description
        Previous value: -"the .flp (or its .wav) that fl_render rendered"New value: +"the path given to fl_render, or the .wav beside it; only its file name is used to find the render, so two pieces with the same name in different folders share one report"
    • Changedsamples4 fields changed
      • changedInput schema / properties / folder / description
        Previous value: -"one folder to look into; omit for all sample folders"New value: +"one folder to look into: absolute, below a sample folder, or %FLStudioFactoryData%/...; omit for all sample folders"
      • changedInput schema / properties / max_folders / description
        Previous value: -"at most this many folders in a folder listing"New value: +"at most this many folders in a folder listing: whole levels from the top, the last level shared across its parents"
      • changedInput schema / properties / measure / description
        Previous value: -"also measure the folder's own audio files into tmp/samples/<folder>.tsv"New value: +"also write the folder's own audio files' levels, width, onsets and centroid to tmp/samples/<folder>.tsv"
      • changedInput schema / properties / query / description
        Previous value: -"words that must all appear in the path, case-insensitive, any order, e.g. 'snare tight'"New value: +"words that must all appear in the path below the sample folder, case-insensitive, any order, any depth, e.g. 'snare tight'"
  3. 6 tool updatesv0.4.0
    • Changedparams1 field changed
      • addedInput schema / properties / kind
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "description": "'instrument' or 'effect', for a name that is both; without it the instrument is taken",
        +  "title": "Kind"
        +}
    • Changedplugins1 field changed
      • addedInput schema / properties / native
        Added value: +{
        +  "default": false,
        +  "description": "true also lists FL's own (native) plugins",
        +  "title": "Native",
        +  "type": "boolean"
        +}
    • Changedpresets2 fields changed
      • addedInput schema / properties / harvest
        Added value: +{
        +  "default": false,
        +  "description": "first read the plugin's built-in presets from FL (opens it there once, about a second per preset); for a plugin whose presets live inside it, not in files",
        +  "title": "Harvest",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / kind
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "description": "'instrument' or 'effect', for a name that is both (Serum2); without it the instrument is taken",
        +  "title": "Kind"
        +}
    • Changedprofile5 fields changed
      • addedInput schema / properties / folder / anyOf
        Added value: +[
        +  {
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • addedInput schema / properties / folder / default
        Added value: +null
      • changedInput schema / properties / folder / description
        Previous value: -"the folder of .flp projects, absolute or relative to the repo"New value: +"the folder of .flp projects, absolute or relative to the repo; omit to use config projects_folder"
      • removedInput schema / properties / folder / type
        Removed value: -"string"
      • removedInput schema / required
        Removed value: -[
        -  "folder"
        -]
    • Addedrender_report
    • Addedsamples
  4. 1 tool updatev0.3.0
    • Changedfl_render1 field changed
      • addedInput schema / properties / key
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "description": "the key the piece is written in, e.g. 'F minor' or 'G#m'; the log then says how much pitch energy falls outside its scale",
        +  "title": "Key"
        +}
  5. 12 tool updatesv0.2.1
    • Changedconfig2 fields changed
      • addedInput schema / properties / key / description
        Added value: +"a key name, as the no-argument call lists them, e.g. 'fl_exe'"
      • addedInput schema / properties / value / description
        Added value: +"the path to set for key; omit to read the key"
    • Changedfl_call2 fields changed
      • addedInput schema / properties / args / description
        Added value: +"its positional arguments, e.g. [0, 5, -1]"
      • addedInput schema / properties / fn / description
        Added value: +"module.function as FL's API names it, e.g. 'plugins.getParamName'"
    • Changedfl_exec3 fields changed
      • addedInput schema / properties / code / description
        Added value: +"Python source; assign the answer to `result`"
      • addedInput schema / properties / out / description
        Added value: +"write the result as JSON to this path (relative to the repo) and return only its size, for large reads; also when `result` is {'__out__': path, 'data': value}"
      • addedInput schema / properties / timeout / description
        Added value: +"seconds to wait for FL's answer"
    • Changedfl_render2 fields changed
      • addedInput schema / properties / path / description
        Added value: +"the .flp to render"
      • addedInput schema / properties / reopen / description
        Added value: +"open the project in FL again when done"
    • Changedfl_transport3 fields changed
      • addedInput schema / properties / action / description
        Added value: +"'play' or 'stop'"
      • addedInput schema / properties / mode / description
        Added value: +"'song' or 'pattern'; omit to keep FL's"
      • addedInput schema / properties / pattern / description
        Added value: +"in pattern mode, the pattern number to select first"
    • Changedparams2 fields changed
      • addedInput schema / properties / plugin / description
        Added value: +"the plugin's name as plugins lists it; a unique part of it works"
      • addedInput schema / properties / query / description
        Added value: +"words that must all appear in the parameter name, case-insensitive, e.g. 'filter cutoff'"
    • Changedplugins1 field changed
      • addedInput schema / properties / query / description
        Added value: +"keep names containing this text, case-insensitive, e.g. 'serum'; omit for all"
    • Changedpresets3 fields changed
      • addedInput schema / properties / limit / description
        Added value: +"at most this many ids"
      • addedInput schema / properties / plugin / description
        Added value: +"the plugin's name as plugins lists it; a unique part of it works"
      • addedInput schema / properties / query / description
        Added value: +"words that must all appear in the id, case-insensitive, any order, e.g. 'bass reese'"
    • Changedprofile1 field changed
      • addedInput schema / properties / folder / description
        Added value: +"the folder of .flp projects, absolute or relative to the repo"
    • Changedproject_read5 fields changed
      • addedInput schema / properties / arrangements / description
        Added value: +"only these arrangements, by name"
      • addedInput schema / properties / path / description
        Added value: +"the .flp file, absolute or relative to the repo"
      • addedInput schema / properties / patterns / description
        Added value: +"only these pattern ids (compact and full)"
      • addedInput schema / properties / unused / description
        Added value: +"also list patterns not placed in the playlist and parked clips"
      • addedInput schema / properties / view / description
        Added value: +"'compact', 'summary' or 'full'"
    • Changedproject_write4 fields changed
      • addedInput schema / properties / doc / description
        Added value: +"the project document, compact or full"
      • addedInput schema / properties / open / description
        Added value: +"open it in FL afterwards, launching FL if needed"
      • addedInput schema / properties / path / description
        Added value: +"the .flp to write, absolute or relative to the repo; pieces go to projects/music/<piece>.flp"
      • addedInput schema / properties / play / description
        Added value: +"'song' or 'pattern': open it and start playback"
    • Removedtest
  6. 14 tool updatesv0.2.0
    • First observedconfig
    • First observedfl_call
    • First observedfl_exec
    • First observedfl_install
    • First observedfl_probe
    • First observedfl_render
    • First observedfl_transport
    • First observedparams
    • First observedplugins
    • First observedpresets
    • First observedprofile
    • First observedproject_read
    • First observedproject_write
    • First observedtest

TDQS

A4.4/5.0

Scored across 15 tools

Disambiguation5/5

Each tool targets a distinct stage of the FL Studio workflow: setup/diagnostics, project file read/write, live scripting, transport, rendering, and metadata discovery. The only close pair is fl_call vs fl_exec, but the descriptions clearly separate single API calls from multi-call Python logic. Resource-specific tools like plugins, presets, params, samples, and profile are all clearly differentiated.

Naming Consistency4/5

Names are consistently snake_case and use meaningful prefixes: fl_* for live/FL-facing operations and project_* for file operations, with bare nouns for catalog/config tools. There are minor deviations from a uniform verb_noun pattern, such as profile, samples, plugins, fl_probe, and fl_transport, but the grouping is still readable and predictable.

Tool Count5/5

Fifteen tools is at the upper end of the ideal range but appropriate for a complex domain spanning setup, project file generation, live control, rendering, and asset discovery. Each tool has a clear role and does not appear redundant within the set.

Completeness4/5

The surface covers setup, diagnostics, project reading/writing, live API/Python access, transport, rendering, and plugin/sample/preset/parameter discovery comprehensively. Minor gaps remain around explicitly saving live edits and file-level operations such as delete/rename, though these are partly workable through project_write or fl_exec.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers