Skip to main content
Glama
README.md
# logic-pro-mcp

An MCP server that lets an AI assistant operate **Apple Logic Pro** — transport,
mixing, a full Mackie Control surface, playhead positioning, and MIDI region
read/write.

## Why it exists

Logic is the least scriptable major DAW: no AppleScript API and no plugin SDK
that reaches project data. This server stitches together the macOS channels that
*do* work — and deliberately favours the ones that **don't force Logic to the
foreground**:

- **Mackie Control (MCU) over MIDI** for transport, the mixer, and the control
  surface — channels addressed by number, like real hardware.
- **Accessibility (AX) value reads/sets** for playhead position (focus-independent).
- **SMF round-trip + IAC streaming** for reading and writing region note data.

## Architecture

```
Claude ⇄ MCP server (TypeScript) ⇄ JSON-RPC over stdio ⇄ Python worker
        src/index.ts  src/bridge.ts                       python/worker.py
                                                            ├── logic/mcu.py          Mackie Control surface (persistent)
                                                            ├── logic/mcu_protocol.py MCU byte map + codecs
                                                            ├── logic/midiport.py     MMC + IAC streaming (rtmidi)
                                                            ├── logic/write_region.py playhead + record-to-track
                                                            ├── logic/export_region.py region export (AX)
                                                            ├── logic/smf.py          SMF read/write (mido)
                                                            ├── logic/axui.py         Accessibility helpers
                                                            └── logic/keys.py         CGEvent keys (fallback)
```

TypeScript owns only the MCP protocol. **Python owns all MIDI and macOS-native
work**, and is testable standalone via `python/cli.py` and `python/mcudev.py`.

## Supported operations

- **Transport** — play / stop / record over the MCU surface (background, no
  foreground; falls back to MMC then key commands).
- **Tracks** — list all channels (numbered, scanned across banks) with live
  state: arm, mute, solo, select, fader, pan, meter.
- **Track control** — arm / mute / solo / select any channel by number.
- **Mixing** — set volume (precise), pan, or center-pan, per channel or master.
- **Surface** — read full control-surface state (faders, V-pots, meters,
  timecode, lit buttons) and press any Mackie button with modifiers.
- **Playhead** — read position and go-to-bar via AX (focus-independent).
- **Cycle** — read or set the loop region (start/end bar) and toggle cycle
  on/off via AX (focus-independent).
- **MIDI content** — read the selected region or whole timeline as note data;
  record notes onto a track at a bar (IAC streaming); write notes to a `.mid`.

## Installation

```bash
npm install
python3 -m venv .venv && .venv/bin/pip install -r python/requirements.txt
npm run build
```

**macOS setup:**

1. Grant **Accessibility** permission to the worker's host process
   (System Settings ▸ Privacy & Security ▸ Accessibility).
2. Create two **IAC Driver** buses in Audio MIDI Setup: `IAC Driver MCU Cmd`
   and `IAC Driver MCU Fb`, plus `IAC Driver Bus 1` for note streaming.
3. In Logic ▸ Settings ▸ MIDI: enable **MMC input** ("Listen to MMC Input"),
   add a **Mackie Control** surface using `MCU Cmd` as Input and `MCU Fb` as
   Output, and filter both MCU buses out of track inputs.
4. For cycle locator control: show the locators in the Control Bar LCD
   (right-click the Control Bar ▸ Customize Control Bar and Display ▸ LCD ▸
   **Custom** ▸ check **Locators (Bar/Beat)**).

## Configure your AI harness

The server is a stdio MCP server: run `dist/index.js` with `node`, and set
`LOGIC_MCP_PYTHON` to the venv's Python so the worker uses the right interpreter.
Use **absolute paths** everywhere — most harnesses don't run from this directory.
(`dist/` is gitignored, so run `npm run build` first.)

The base config block, reused by every harness below:

```json
{
  "command": "/ABSOLUTE/PATH/TO/node",
  "args": ["/ABSOLUTE/PATH/logic-pro-mcp/dist/index.js"],
  "env": { "LOGIC_MCP_PYTHON": "/ABSOLUTE/PATH/logic-pro-mcp/.venv/bin/python" }
}
```

Find your absolute paths with `which node` and `pwd`.

**Claude Code** — register from the repo root (writes to `~/.claude.json`):

```bash
npm run build
claude mcp add logic-pro "$(which node)" "$(pwd)/dist/index.js" \
  --env LOGIC_MCP_PYTHON="$(pwd)/.venv/bin/python"
```

Or drop a `.mcp.json` in a project root to share it with that project
(`claude mcp add` with `--scope project` does the same):

```json
{ "mcpServers": { "logic-pro": { <base config block> } } }
```

**Claude Desktop** — edit
`~/Library/Application Support/Claude/claude_desktop_config.json`, add the server
under `mcpServers`, then restart the app:

```json
{ "mcpServers": { "logic-pro": { <base config block> } } }
```

**Other harnesses** (Cursor, Cline, custom SDK clients) take the same shape:
a stdio server with `command`, `args`, and `env`. Consult the host's MCP docs
for where its config file lives.

After registering, confirm the tools load (in Claude Code: `/mcp` should list
`logic-pro`). If they don't, check the worker can start standalone:
`.venv/bin/python python/worker.py` and send `{"id":1,"method":"ping"}`.