rubin
Allows controlling Logic Pro (Apple's digital audio workstation) to compose MIDI, load patches (including Alchemy), and drive transport.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@rubincompose a 4-bar loop in Am with drums and arp"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
rubin
A minimal, dependency-free MCP server that turns Logic Pro into an AI-playable instrument: compose MIDI, load any factory patch (Alchemy included), and drive the transport.

Everything in this screenshot was placed by rubin: the five tracks and their regions (composed as a Standard MIDI File), the Alchemy patches on each channel strip (loaded through the Library), tempo, and key.
Why it works
UI-automation-first tools (clicking Logic's interface for every note) fail silently and read garbage state. rubin flips the approach:
Composition is a file, not clicks. Notes, CC automation, pitch bends, tempo, and time signature are written into a real Standard MIDI File — deterministic, testable, no UI involved. Logic maps each track's GM program to a software instrument on import.
Patch discovery is a disk read, not a guess. Logic's ~6,000 factory patches live on disk with the synth engine recorded inside each bundle;
find_patchesfilters them by name, category, or engine (Alchemy,Retro Synth,ES2,Sculpture...).UI scripting is a last resort, and verified. Only patch loading, import, and transport touch the UI — anchored to stable accessibility landmarks (the Library's "Search Sounds" field, track-header fields), with
list_tracksreading real state back so nothing fails silently.
Related MCP server: garageband-llm-bridge
Tools
Tool | What it does |
| Write a .mid from notes / CC / bends / volume / pan per track |
| Open a .mid in Logic as a new project (no dialogs, most reliable) |
| File > Import > MIDI File into the open project at bar 1 |
| Both steps in one call |
| Audio → MIDI via basic-pitch, content-hash cached |
| Browse the transcription cache |
| Full analysis: key/swing/chord detection, density contour, warnings, per-track stats |
| The same, as one readable paragraph |
| Analysis → ready compose_midi args that fit a source file (registers, key, feel) |
| Cut/arrange WAV sample slices on a tempo grid into a rendered song (no DAW) |
| Bounce a .mid to WAV with the built-in synth (mix MIDI arrangements with sample cuts) |
| RMS energy contour of a WAV — 'see' a render's dynamics without hearing it |
| Report each sample's pitch, key, and kind (pitched/sub/noise) |
| Reveal a file/folder in Finder, ready to drag onto a track |
| Reveal + drag guidance (Logic audio import isn't scriptable) |
| Search the on-disk factory patch index (name / category / engine) |
| Discover installed Surge XT presets (load via Surge's browser) |
| Discover factory FX-chain settings (.cst) — names for the Setting menu; not Library-loadable |
| Select track N (1-based) |
| Load a Library patch onto the selected track; returns the loaded name |
| Read back |
| Save the project (Cmd+S); reports the sheet if the project is unnamed |
| play / stop / record / go_to_beginning |
| Click through a Logic sheet/dialog (e.g. tempo-import prompt) |
| Is Logic running + front window title |
Note format: {start, dur, pitch, vel} — start/dur in beats, pitch 0–127
(60 = middle C), velocity 1–127. Channel 9 is GM drums (36 kick, 38 snare,
39 clap, 42 closed hat, 46 open hat). Tracks also accept cc
({beat, controller, value}), bends ({beat, value} −8192…8191),
program, volume, pan. Compositions accept time_sig ([3, 4]),
key ("Am", "Eb", "F#m"), tempo_changes ([{beat, bpm}]), and
swing (50 = straight, ~62 = MPC feel; swing_unit 0.5/0.25 for
8th/16th swing; per-track override supported). Tracks can declare a
progression ({chords: ["Am", "F", "Cmaj7", "E7"]}) instead of raw
notes — voicings are generated (styles: pad / bass / arp / melody — the
latter writes a hook: chord tones on strong beats, one peak, resolves to
the root), with repeat
and start_bar for staged entrances; drums: {pattern: "half_time"}
generates a full groove. analyze_midi reads the same chord names back.
Example: a full backing track from declarations
compose_midi {tempo: 85, key: "Am", name: "sketch", tracks: [
{name: "Pad", channel: 1, progression: {chords: ["Am","F","C","E"], repeat: 2}},
{name: "Drums", channel: 9, drums: {pattern: "half_time", bars: 12, start_bar: 4}},
{name: "Bass", channel: 0, progression: {chords: ["Am","F","C","E"], style: "bass", start_bar: 4}},
{name: "Arp", channel: 2, progression: {chords: ["Am","F","C","E"], style: "arp", start_bar: 8}},
]}
describe_midi {path: "~/Desktop/sketch.mid"}
→ 4 track(s), 283 notes, ~16 bars at 85 BPM. key Am (82% confident).
progression Am-F-C-E... dynamic arrangement (density 0.4-6.7 notes/beat). ...Staged entrances (start_bar) give the arrangement a real build; the
analyzer verifies its own output — key, chords, contour, and warnings for
register clashes or robotic velocities.
Example: an Alchemy pad in three calls
find_patches {category: "Synthesizer/Pad", plugin: "Alchemy"}
→ [{"name": "Drifting Away", ...}, ...]
select_track {index: 3}
load_patch {query: "Drifting Away"}
→ Loaded patch 'Drifting Away' on the selected trackGenre starting points (stock Logic, index-verified)
Role | Patches (exact |
Future-bass chord stabs | Massive Stack, Chicago Stack, Sparkle Chord (category |
Vocal-chop feel | Breathy Vox, Starlight Vox, Rhythmic Vox |
Sub bass | Deep Sub Bass, Full Sub, Super Sub 808 Bass |
Wobble bass (CC1 = wobble) | Mega Wobble Bass, FM Wobble Bass, Sharp Wobble Bass |
Dark pads | Drifting Away (Alchemy) |
Trap/808 kits | Modern 808; dub: Dub Machine |
Punk/rock | SoCal+ kit, Hard Rock guitar, Punchy Bottom bass |
rubin's CC automation maps onto these: cc 1 drives the wobble patches'
filter, cc 11 fakes sidechain pump on stabs, bends do scoops and slides.
Ears: audio in, MIDI out
transcribe_audio turns any recording — a hummed melody, a guitar take, a
sample — into MIDI with Spotify's basic-pitch, cached by content hash under
~/.cache/rubin/midi so repeat calls are free. analyze_midi then reads the
result back (rubin has its own SMF parser) and reports what the instrument
plays: pitch range, note density, polyphony. That loop — hear it, read it,
compose against it — is how rubin learns what source material sounds like.
Cut samples into a song
rubin edits audio the way it composes MIDI — as a deterministic file
operation, never through a DAW's region UI. cut_samples loads WAV files
(16/24/32-bit), slices/pitches/reverses/fades them, and arranges the chops
on a tempo grid into a rendered mix:
catalog_samples {folder: "~/Music/Samples/dubstep"}
→ Evil_1: sub, key E · Down_Growl: noise · ...
cut_samples {tempo: 140, out_path: "~/Desktop/drop.wav", events: [
{file: ".../Evil_1.wav", at_beat: 0, repeat: {times: 8, every: 4}}, # E sub every bar
{file: ".../Down_Growl.wav", at_beat: 0, end: 0.2, pitch: 3,
repeat: {times: 32, every: 0.5}}, # growl chops
]}catalog_samples first tells you each sample's pitch and whether it's tonal
or texture, so you can tune and place them. Output is a standard WAV any DAW
imports (or drag it in via reveal_in_finder). limit: true soft-clips
dense stacks so one loud hit doesn't thin the mix.
Install
# from a clone (development)
claude mcp add --scope user rubin -- /usr/bin/python3 ~/dev/rubin/server.py
# or installed as a package
pip install git+https://github.com/mrcolo/rubin
claude mcp add --scope user rubin -- rubin-mcp
python3 server.py --check # environment health: Logic, indexes, AUs, transcription
python3 server.py --verify song.mid # pre-flight: analysis + warnings, exit 1 if dirty
# optional, for transcribe_audio:
cd ~/dev/rubin && python3 -m venv .venv-bp && .venv-bp/bin/pip install basic-pitchRequires macOS Accessibility + Automation permissions for the host app
(Claude / terminal) — only for the UI-touching tools. compose_midi,
find_patches, and open_midi_as_project need no permissions at all.
Test & demo
python3 -m unittest discover -s tests # 76 tests, no Logic needed for most
python3 server.py --demo # compose + open a demo beat in Logic
python3 server.py --demo --write-only # just write the .mid
python3 server.py --cut-demo demo.wav # render a from-scratch sample cut (no external files)Files
server.py— MCP stdio server (hand-rolled JSON-RPC, no SDK)midi.py— Standard MIDI File writermidi_read.py— SMF parser + per-track analyzertranscribe.py— basic-pitch wrapper + content-addressed cachewave_edit.py— zero-dependency WAV slicer/arranger (the audio counterpart to midi.py)patches.py— factory patch index readerlogic_ctl.py— the minimal AppleScript/AX layerdemo_beat.py— 8-bar dark R&B demo (85 BPM, Am–F–C–E)tests/— unit + protocol tests
See CHANGELOG.md for the full arc.
Known limits
import_audiois best-effort and often aborts: Logic imports audio through a Browser pane, not a file dialog. It is hardened to NEVER type a path into the arrange window (a path's letters fire as key commands —rstarts a recording — which once damaged a live session). Drag audio from Finder for reliability.import_midiandimport_audioboth confirm a file panel is frontmost before typing a path, and abort with Escape otherwise — they never leak a path into the arrange window.import_midi's happy path is live-verified;import_audiousually aborts (audio import is a Browser pane).Patch loading, track selection, and import drive Logic's UI; they're anchored to stable AX landmarks (bounded subtree scans, never the whole window — real projects have thousands of AX elements) but a future Logic redesign could move them.
list_tracksexists so failures are visible, not silent.Logic auto-renames a track to its patch name after
load_patchunless the track was named manually first.Track-header patch labels can sit in an off-screen column and read stale — header text is NOT a reliable patch readback (this once produced a false "loading is broken" diagnosis). The selected track's channel-strip name in the inspector is ground truth;
load_patchverifies against it and returns VERIFIED or FAILED accordingly.Tested on Logic Pro X 10.x/11 ("Logic Pro X.app" and "Logic Pro.app" are both handled), macOS 14+.
This server cannot be deployed
Maintenance
Related MCP Connectors
MCP server for Producer/Riffusion AI music generation
Generate AI music via the Lacuna Music API from MCP clients like Claude Desktop & Code.
MCP server for progressive tool usage at any scale (see https://klavis.ai)
AI image, video, voice and music generation over MCP, routed to Veo 3.1, Seedance 2.5 and more.
Related MCP Servers
- AlicenseAqualityCmaintenanceMCP server that bridges Ableton Live with AI models, enabling real-time project inspection and control such as track overview, device parameters, and audio analysis.12MIT
- AlicenseBqualityDmaintenanceA local CLI and MCP server enabling an LLM to control GarageBand on macOS via AppleScript, accessibility automation, and MIDI workflows.69MIT
- FlicenseNot gradedqualityFmaintenanceAI-powered control for Apple Logic Pro via MCP, enabling transport, tracks, plugins, MIDI, project, and mixer control through natural language.5-
- AlicenseBqualityDmaintenanceA local MCP server that bridges Logic Pro MIDI data via an AUv3 plugin, enabling reading, creating, and manipulating MIDI regions and tracks through tools like read_logic_track and create_midi_region.8MIT