Skip to main content
Glama
README.md
# flai-mcp

MCP server that connects Claude to FL Studio for AI-assisted music production.

> **Status:** Alpha — functional core, actively developed. Contributions welcome.

```
Claude Code / Claude Desktop / Cursor
        │  MCP (stdio)
        ▼
  flai-mcp server (Python)
        │
  Virtual MIDI (SysEx)
  (IAC Driver / loopMIDI)
        │
  device_flai.py
  (MIDI controller script
   running inside FL Studio)
```

## What it can do

| Category | Capabilities |
|----------|-------------|
| **Transport** | Play, stop, record, get/set tempo, seek to bar/beat |
| **Mixer** | Get/set volume, pan, mute, solo, name, color for any track |
| **Channel Rack** | Get/set volume, pan, pitch, name, mute, mixer routing |
| **Patterns** | List, rename, recolor, clone, navigate between patterns |
| **Notes** | Write notes into patterns with pitch, velocity, timing via step sequencer API |
| **Plugins** | List parameters, get/set values, cycle presets |
| **Arrangement** | Add/list timeline markers, get playhead position |
| **Playlist** | Name and color playlist tracks |

### Example prompts

> "Write a four-on-the-floor kick pattern in pattern 1"

> "Add a rolling bassline in A minor to pattern 5 on the FLEX Bass channel"

> "Turn down the kick on mixer track 2 by 3dB and hard-pan the hi-hats"

> "Set the cutoff on channel 4 to 60% and resonance to 25%"

> "Add arrangement markers for Intro, Buildup, Drop, Breakdown, and Outro"

## Known limitations

- **Playlist clip placement** — FL Studio's scripting API does not expose any function to place pattern clips on the arrangement timeline. This is an API gap from Image-Line, not a flai-mcp limitation. Patterns must be arranged manually. ([API audit](https://il-group.github.io/FL-Studio-API-Stubs/midi_controller_scripting/playlist/))
- **Note writing uses step sequencer** — Notes are written via `setGridBit` + `setStepParameterByIndex`. This works for drums and melodic patterns with 1/16th note quantization. Sub-step timing is supported via the shift parameter, but it's not as flexible as the Piano Roll.
- **Piano Roll scripts can't do file I/O on macOS** — FL Studio's embedded Python `open()` is broken on macOS, so the file-based piano roll bridge doesn't work. The step sequencer approach is the current workaround.
- **Tempo setting** — Requires FL Studio 21+. Use the FL Studio UI for older versions.

## Setup

### 1. Virtual MIDI ports

**macOS (IAC Driver — built-in, free)**
1. Open **Audio MIDI Setup** (Spotlight → "Audio MIDI Setup")
2. Window → Show MIDI Studio
3. Double-click **IAC Driver** → check **Device is online**
4. Add two ports: `FLAI In` and `FLAI Out`

**Windows (loopMIDI — free)**
1. Install [loopMIDI](https://www.tobias-erichsen.de/software/loopmidi.html)
2. Create two ports: `FLAI In` and `FLAI Out`

### 2. Install flai-mcp

```bash
# Clone
git clone https://github.com/kaupau/flai-mcp.git
cd flai-mcp

# Create venv and install (requires Python 3.11+)
uv venv --python 3.11 .venv
uv pip install -e .

# Or with pip
python -m venv .venv
source .venv/bin/activate
pip install -e .
```

### 3. Install FL Studio bridge script

```bash
python scripts/install_fl_bridge.py
```

Or manually copy `fl_bridge/device_flai.py` to:
- **macOS:** `~/Documents/Image-Line/FL Studio/Settings/Hardware/FLAI/device_flai.py`
- **Windows:** `%USERPROFILE%\Documents\Image-Line\FL Studio\Settings\Hardware\FLAI\device_flai.py`

### 4. Configure FL Studio

1. Open FL Studio
2. **Options → MIDI Settings**
3. **Input section:**
   - Select `IAC Driver FLAI In` (or `FLAI In` on Windows)
   - Set **Controller type** to **FLAI**
   - Set **Port** to `1`
   - Click **Enable**
4. **Output section:**
   - Select `IAC Driver FLAI Out` (or `FLAI Out` on Windows)
   - Set **Port** to `1`
   - Click **Enable**

Verify it works: open **View → Script output** — you should see:
```
[FLAI] MCP Bridge initialized. Ready.
[FLAI] Input port: IAC Driver FLAI In
```

### 5. Configure your AI client

**Claude Code** — add to `~/.claude/settings.json`:
```json
{
  "mcpServers": {
    "flai": {
      "command": "/path/to/flai-mcp/.venv/bin/flai-mcp",
      "args": ["--midi-in", "IAC Driver FLAI In", "--midi-out", "IAC Driver FLAI Out"]
    }
  }
}
```

**Cursor** — add to `~/.cursor/mcp.json` (same format).

**Claude Desktop** — add to `claude_desktop_config.json`:
```json
{
  "mcpServers": {
    "flai": {
      "command": "/path/to/flai-mcp/.venv/bin/flai-mcp",
      "args": ["--midi-in", "IAC Driver FLAI In", "--midi-out", "IAC Driver FLAI Out"]
    }
  }
}
```

### 6. Verify

```bash
# List available MIDI ports
flai-mcp --list-ports

# Run with debug logging
flai-mcp --log-level DEBUG
```

## Architecture

```
src/flai_mcp/
├── server.py               — MCP server assembly
├── __main__.py             — CLI entry point (flai-mcp)
├── bridges/
│   └── midi_bridge.py      — async SysEx ↔ asyncio bridge via mido
├── protocol/
│   ├── commands.py         — command/status enums
│   └── encoding.py         — SysEx ↔ JSON serialization
└── tools/
    ├── transport.py        — play/stop/tempo/position
    ├── mixer.py            — mixer track controls
    ├── channels.py         — channel rack controls
    ├── patterns.py         — pattern management
    ├── piano_roll.py       — note writing (step sequencer API)
    ├── plugins.py          — plugin parameters & presets
    └── arrangement.py      — timeline markers

fl_bridge/
└── device_flai.py          — FL Studio MIDI Controller Script
```

### Protocol

Commands are SysEx messages with JSON payloads:

```
Request:  [0xF0, 0x7D, CMD_ID, REQ_ID, <ascii-json>, 0xF7]
Response: [0xF0, 0x7D, 0x70,   REQ_ID, STATUS, <ascii-json>, 0xF7]
```

- `0x7D` — SysEx manufacturer ID reserved for non-commercial/educational use
- JSON uses `ensure_ascii=True` so all payload bytes are 0x00–0x7F (SysEx-safe)
- Responses are matched by `REQ_ID` (0–127, rotating counter)

### How note writing works

FL Studio's MIDI Controller Scripting API doesn't expose piano roll note editing. The `flpianoroll` module only works in Piano Roll Scripts, which run in a separate Python context with broken file I/O on macOS.

flai-mcp writes notes via the **step sequencer API**:
- `channels.setGridBit(channel, step, on/off)` — enable/disable steps
- `channels.setStepParameterByIndex(channel, pattern, step, param, value)` — set pitch, velocity, pan, timing per step

This gives per-note control over pitch (param 0), velocity (param 1), pan (param 4), and micro-timing (param 7).

## Development

```bash
git clone https://github.com/kaupau/flai-mcp.git
cd flai-mcp
uv venv --python 3.11 .venv
uv pip install -e ".[dev]"

# Run protocol tests (no FL Studio needed)
pytest

# Check ports
flai-mcp --list-ports
```

### Adding new tools

1. Add command ID to `src/flai_mcp/protocol/commands.py`
2. Add handler in `fl_bridge/device_flai.py` → `_HANDLERS` dispatch table
3. Add MCP tool in `src/flai_mcp/tools/*.py`
4. Reinstall the FL Studio script: `python scripts/install_fl_bridge.py`

## Contributing

Contributions welcome! Some areas that need work:

- [ ] **Piano Roll note writing** — find a way to use `flpianoroll.score.addNote()` programmatically (the subprocess IPC approach from [music-copilot](https://github.com/TommyX12/music-copilot) is promising)
- [ ] **Playlist clip placement** — lobby Image-Line for `playlist.addClip()` API, or explore `.flp` file manipulation via [PyFLP](https://github.com/demberto/PyFLP)
- [ ] **Windows testing** — loopMIDI setup, path handling
- [ ] **Automation clips** — create and manipulate automation
- [ ] **Better tempo control** — `mixer.setCurrentTempo()` doesn't exist in all versions
- [ ] **Audio rendering** — export/bounce support if API allows

## License

MIT

Maintenance

ActivityInactive
ResponsivenessNo issues