Documentation menu
On this page

The extension is the authority for the live protocol. Protocol 3 accepts one UTF-8, whitespace-delimited command line, terminated by \n, and returns one JSON object followed by \n. Requests are not JSON. The Python MCP adapter adds JSON tool schemas, authorization and workflow state above this protocol.

Endpoint and request path

  • Host: 127.0.0.1; port: 8765; local machine only.
  • No network authentication: do not forward or expose the listener.
  • The deprecated OSC compatibility listener is not started by the MCP adapter.
  • The Python client bounds commands to 1 MiB and responses to 8 MiB and uses a 65-second socket timeout. Direct clients should also bound their input/output.

For a live operation, the adapter validates the arguments and any required confirm/cooperative authorization, then sends a command. The extension serializes dispatch and schedules host/UI work. Each received request has one 30-second deadline spanning the queue and native submission. Expired queued writes are rejected; a timeout cannot retract an operation already submitted to Bitwig. Read state before deciding what happened; never blindly retry a write.

The response is JSON with operation-specific fields, usually ok. MCP tools return this JSON as text, or Error: ... for an exception. A valid JSON response or ok: true is not proof of audible output or arranger content. Offline plan, export and Nitro operations need not contact the extension at all.

Copying a replacement .bwextension does not prove it has loaded: Java extension reload is asynchronous. Wait for read-only capability/readiness responses from the expected extension, Bitwig 6.1.1 and API 25 before mutation. Refresh all live identities after reload; never use a mutation as a readiness probe or replay one after a timeout.

Core commands

The notation below is descriptive: substitute observed values without angle brackets. UUIDs, module instance IDs, native parameter IDs and action IDs are different identifiers. Do not substitute one for another.

Command Meaning
ping Connection check
capabilities Protocol, extension/host versions and nested grid_graph capabilities
state Selected device's exposed controls, indexes 1–8, normalized values 0–1
inspect Selected device and container flags
history Observed project name/modified state and host undo/redo availability
set INDEX VALUE Write one exposed control, native protocol range 0–1
batch INDEX=VALUE ... Serialized exposed-control writes; not an all-or-nothing transaction
tracks / track INDEX List/select the observed flat track bank, indexes 0–63
track-first / track-next / track-previous Track navigation
next / previous / parent / device-first Device navigation; device-first works from an empty selection
device-primary / device-editor Host device selection/editor operations
device-catalog [QUERY] Search installed Bitwig device UUIDs
devices Selected device's 16-sibling window, native identities, selection_token, window_complete; not a whole recursive chain
insert POSITION UUID SELECTION_TOKEN Guarded insertion at before, after, start, end or replace; all require a selected track, before/after/replace also a selected device
device-remove SELECTION_TOKEN Guarded removal of the exact selected native device
actions [QUERY] / action ID Discover actions, then invoke the exact returned wire ID
undo / redo Latest global host operation, not a session-specific rollback

The MCP exposed-control scale is 0–128; its adapter converts to the native protocol's 0–1 scale. Neither is a Grid module's native parameter domain. Action IDs are percent-escaped wire tokens: pass the returned token unchanged. The flat track bank explicitly uses ALL_CHANNELS: it includes hidden children of collapsed groups, FX and master tracks. A bank index is not the native track position and not a main-track-only ordinal.

Device edits require the current 64-hex selection_token from selected-device properties or devices. This is distinct from a project token or graph revision. instance_id/track_id identify current native objects, not persistent UUIDs. Native edits revalidate selection and exact identities on the document thread. Public state/inspect can return null private identities and selection_token: null with selection_guard_available: false and a reason; these reads remain usable, but missing native guards cannot authorize edits.

Grid commands and revision guards

Command Meaning
graph-capabilities / graph-state Capability gate and selected graph snapshot
graph-catalog [QUERY] / graph-modulators [QUERY] Installed module/modulator metadata
graph-host-modulators Selected device's host-level modulation sources
graph-insert UUID X Y / graph-insert-modulator UUID X Y Insert at explicit integer coordinates, −4096 through 4096
graph-set MODULE PARAMETER_B64 VALUE / graph-set-modulator MODULE PARAMETER_B64 VALUE Write an exact native parameter ID and native number/boolean value
graph-resolve-value MODULE PARAMETER_B64 DISPLAY_B64 Non-mutating musical-unit resolution through Bitwig's native scale
graph-connect SOURCE SOURCE_PORT TARGET TARGET_PORT / graph-connect-modulator SOURCE SOURCE_PORT TARGET TARGET_PORT Connect live numeric ports
graph-disconnect TARGET TARGET_PORT Disconnect a live input
graph-move MODULE X Y Direct-protocol move, not a general MCP patch-session operation
graph-clear Destructive selected-graph clear; MCP grid_clear_graph requires reviewed expected_revision, authorization and retains a before snapshot
guard REVISION GRAPH_COMMAND... Require the exact reviewed graph revision before a graph mutation

PARAMETER_B64 and DISPLAY_B64 are URL-safe base64 of UTF-8 strings. Encode each separately, including parameter IDs such as C# or IDs containing spaces. MCP callers pass raw exact strings; the adapter performs this encoding. There is no uppercase-only parameter-ID convention.

Graph snapshots provide graph_id and a 64-lowercase-hex revision. Guarded writes check the selected graph identity and revision again at the native submission boundary. MCP grid_clear_graph requires expected_revision; other direct MCP graph writers accept it optionally. If omitted there, the adapter reads a fresh revision, which guards dispatch but does not bind the write to an older human-reviewed snapshot. Supply the reviewed revision explicitly. A graph guard accepts only graph mutations, not device, transport or song commands. Clear replies retain the full native payload through MCP, including ok: false and any before snapshot on failure. Preserve the caller's snapshot before acting anyway: transport loss may provide no reply. Inspect ok and resulting state; a returned payload is not necessarily successful.

Value resolution returns value, current_value, current_display, requested_display, display_unit and revision, with mutates_project: false. It supports editable continuous native parameters and compatible musical units; it does not write or promise a proposed round-trip display. Write the returned value against that revision, then read the actual display/value. Resolve enums and booleans from the live parameter's options/type instead.

Private Grid/device-catalog/native-arranger bindings support Bitwig 6.1.1 exactly. Unknown private runtimes fail closed: no guessed fallback. The public extension minimum, current host and compile-time Controller API are 25. When graph_available is false, exposed controls may still work, but no graph identity, topology or native parameter metadata may be inferred.

Song commands and observations

Command Meaning
song-state Project token, selected target, flat inventory, transport, conservative recording state, meters and capabilities
song-import TOKEN SHA256 NOTE_TRACK_COUNT PATH_B64 Submit a reviewed type-1 MIDI artifact to new arranger tracks after the selected native target at beat 0
song-import-status RECEIPT_ID Receipt plus current inventory observation; not arranger-note verification
song-save TOKEN DIRECTORY_B64 Save the controller-owned project through Bitwig into a caller-allocated fresh empty directory; native asynchronous completion, not MIDI export
song-arranger INDEX Read one track's bounded primary arranger clips and stored source-note summaries; index 0–63
song-clip-loop TOKEN INDEX CLIP_ID EXPECTED_ENABLED ENABLED Set only the exact clip's loop flag; signed 32-bit native clip ID and literal true/false booleans
song-transport-play TOKEN / song-transport-stop TOKEN Explicit transport operation
song-transport-tempo TOKEN BPM Explicit finite tempo, 40–220 BPM
song-transport-meter TOKEN METER Explicit meter, numerator 2–12 and denominator 4 or 8
song-transport-seek TOKEN POSITION_BEATS Explicit finite seek, 0–24576 quarter-note beats; refuses recording; no implicit tempo/meter change
song-transport-loop TOKEN ENABLED Set global arranger-loop enabled state using literal true/false; refuses recording; leaves loop range and clip flags unchanged
song-track-state TOKEN INDEX MUTED ARMED Each state is true, false or keep; index 0–63

TOKEN is the exact observed 64-hex project_token, not a stable project UUID. PATH_B64 is URL-safe base64 UTF-8 of an absolute local MIDI path. Native validation checks the regular, non-symlink file, size, source digest, type-1 structure and note-track count. MCP import adds the stronger TrackWorkflow contract: current session revision, workflow-owned export and one import attempt, including ambiguous timeouts. Prefer that reviewed workflow over constructing raw native imports.

The target must be an observed Group, Instrument, Audio or Hybrid track. Import requires an unscrolled, fully represented bank, capacity for note tracks plus one group slot, no recording, the same project token and the exact selected native target through submission. The import uses an arranger insertion point, not the public track-header insertFile path, which excluded clips.

The full exported MIDI retains tempo and meter metadata. Native submission uses a private derived MIDI without those global metadata events to avoid the observed tempo-import modal; the receipt reports artifact_sha256 and distinct submitted_sha256. Set global tempo/meter only through the explicit transport operations with a fresh token. Import never starts playback.

For compiler-generated exports this is the notes/markers delivery scope. The transformation removes tempo/meter events; it is not a general sanitizer for arbitrary raw MIDI event types.

Receipts can be queued, submitted, native_rejected or submission_error_observe_before_retry. verified remains false; requires_observation remains true. Track-count deltas, launcher slots, native acceptance and meter values cannot prove arranger-note placement, instrument assignment or a complete audible song. Inspect the actual arranger and listen. Playback refuses recording or armed tracks; tempo/meter, seek, arranger-loop and track-state changes also refuse recording. Stop remains an explicit token-guarded action. Arranger-loop returns status: "submitted", operation: "transport_loop", the requested enabled and verified: false. Read back the three arranger_loop_* song-state fields; enabled/start/duration are part of the token, unlike position/playing or project_save_pending.

song-arranger returns {ok, project_token, track_index, track_name, atomic: false, arranger}. Inspect arranger.available, truncation, metadata/count/ detail completeness and per-field reasons. Clip positions, lengths, loop geometry and source-note spans use native quarter-note beats without tick conversion. Source summaries do not expand loops or establish playback/audio.

For song-clip-loop, use the observed clip native_id and loop_enabled plus a fresh project token. It rechecks project/recording context before and inside the UI callback, request deadline, canonical track identity, exact clip object identity and expected loop state immediately before the native undo/ observer-backed setter. Success requires read-back of the desired flag. It does not change notes, timing, loop range, clip length or selection, and ambiguity never authorizes replay. Re-inspect source counts/spans and flags.

Native project save

DIRECTORY_B64 is URL-safe base64 of the UTF-8 absolute directory path, not a MIDI path or .bwproject filename. Raw clients must allocate and retain their own fresh private empty directory. Native validation rejects symlinks/noncanonical paths, non-directories, nonempty destinations and locations inside an existing Bitwig project folder. The adapter's grid_song_save does this allocation under the configured/explicit output root using a bitwig-project-* child.

The exact 6.1.1 private binding maps the controller project's native document to its same-document application wrapper on the UI thread; it does not select the globally focused document or invoke a Save action. Project token, native identity, recording state and request deadline are rechecked before submission. Plugin-bridge documents reject. The ordinary native save uses false, false flags, not Collect and Save: external assets can remain external. The replacement-capable host writer is not an atomic no-clobber API; the private empty destination avoids existing files.

The native callback returns {ok, status, project_file, error, verification_scope}: success is native_save_completed after the callback and presence of DIRECTORY/PromptTrack/PromptTrack.bwproject as a regular nonsymlink file; failure is requires_observation. This is not a project-content comparison or audio verification. project_save_pending blocks another save until native completion (or submission failure), not merely until a client stops waiting. A transport timeout after submission cannot cancel the host writer.

MCP retains output_directory and retry_performed: false; a bridge/native error becomes ok: false, status: "requires_observation", error and native_response (null when no native reply is available). Inspect fresh song state, pending status and the known directory; never automatically replay or delete a possibly in-use output. Raw clients must retain the directory themselves before sending. See checkpoint recovery.

Persistence and recovery

Shaping, incremental patch and song sessions are process-local; restarting the adapter loses their review authority. Parameter snapshots cover only observable parameters. Patch sessions retain a before-graph as evidence, not as an executable restore program. They apply one reviewed step at a time and freeze on stale state, failed verification or ambiguous outcomes; they never replay or roll back automatically.

Host undo/redo affects the latest global operation, which may belong to another writer. Re-read selection, graph and song state before recovery. A sequence of native writes is not one guaranteed undo transaction. Successful coordinate read-back also does not establish save/reload persistence: verify persistence separately when it is an acceptance requirement, without replacing the whole graph as an implicit recovery action.

Search docs

All words must match. Enter opens the first result.

Type a tool, argument, or guard to begin.