osc-bridge

io.github.roomi-fieldsPublished by GitHub account roomi-fieldsv0.19.1Updated Oct 31, 2026

OSC ↔ MIDI bridge for synthesizers and DAWs, with the SynthHub catalogue. A MIDI MCP and OSC MCP.

VerifiedStreamable HTTPWeb executableKnowledge & MemoryDeveloper ToolsMedia & Design

Overview

AI-generated overview

Bridges MIDI/SysEx hardware synths and OSC software to an assistant, with the SynthHub driver catalogue and shared presets.

What you can do
  • Search the driver catalogue and read a device's documentation and OSC routes
  • Export a driver's namespace as OSCQuery JSON or MIDNAM
  • Report driver results, learned MIDI mappings, new drivers and fixes to the catalogue
  • Find, read, share, version, comment on, star and withdraw shared presets
  • Detect, send to and listen on the user's hardware through a relay, and take a sound from the synth
  • Load a shared preset into the user's device, and manage collections, follows, profile and account linking
When to use it
Useful when the user wants an assistant to work with synthesizers, drum machines, controllers or DAWs: looking up how a device is controlled, sending notes and parameter changes to real hardware, or finding and loading shared sounds. Also fits contributing corrections and new device drivers back to the catalogue.
Requirements
Either the hosted remote endpoint or the local npm package run over stdio with Node.js. Hardware access goes through a relay the user opens and pairs with a code; the local variant needs MIDI ports and a running bridge for OSC targets. No API keys or environment variables are declared.
Before you install
The server issues an anonymous account per session and asks the assistant to pass a user_id and to switch to a personal URL to keep it; treat that as account handling, not a neutral default. Loading a preset replaces the sound the device holds, and restore-style operations overwrite device memory. Sharing, commenting, starring and reporting publish data publicly under CC BY-SA 4.0. Relay detection sends MIDI identity requests to every port, and catalogue lookups send port names and device…

Installation

In SourceWeft

  1. Open osc-bridge in the dashboard and add it to a workspace.
  2. Enable the server for the chats that should use its tools.

Web executable via Streamable HTTP. Remote servers run from the web runtime once configured in a workspace.

Use with an agent

Paste this prompt into Claude Code, Codex, Cursor or another agent — or into SourceWeft chat. The agent reads this server's install guide, shows you its publisher, endpoint and sign-in, and adds it to your client once you agree. Keys never go into a command.

Read https://sourceweft.com/mcp/io.github.roomi-fields%2Fosc-bridge/install.md and connect the MCP server it describes to my client. Before changing any config, show me its publisher, endpoint and sign-in method and wait for my OK. Never put an API key in a command or in a file I would commit; ask me where it should come from.

Read the install guide the agent follows

Other MCP clients

Add this to your client's mcpServers config.

{
  "mcpServers": {
    "osc-bridge": {
      "type": "http",
      "url": "https://mcp.synthhub.roomi-fields.com/mcp"
    }
  }
}

README

osc-bridge

[Release] [CI] [License: AGPL-3.0-or-later] [mcptry]

Declarative OSC bridge for music hardware and software — and an MCP server to drive it from an LLM.

Hardware synthesizers over MIDI / SysEx, plus DAWs and live-coding environments over OSC (Ableton, Bitwig, Reaper, Sonic Pi, SuperCollider, Pure Data, TouchDesigner, VCV Rack). Every device gets a clean, named OSC surface described by one JSON file, its driver; the catalogue of drivers lives on SynthHub, which hands them out one at a time. Drive it from a live-coding client, a DAW, a script, the CLI — or from Claude via the built-in MCP server (a MIDI MCP and OSC MCP).

[osc-bridge — clients (OSC clients, the CLI, an LLM via MCP) feed one osc-bridge core that fans out to hardware synthesizers over MIDI/SysEx and music software (Ableton, Bitwig, Reaper, Sonic Pi) over OSC]

Install

Hosted MCP server, nothing to install — the SynthHub server, run by the maintainer of osc-bridge, with the catalogue, trust from real use and the relay to your own hardware:

  • Claude (web, desktop): Settings → Connectors → Add custom connector → https://mcp.synthhub.roomi-fields.com/mcp
  • Claude Code: claude mcp add --transport http synthhub https://mcp.synthhub.roomi-fields.com/mcp
  • Cursor and other clients: {"mcpServers": {"synthhub": {"url": "https://mcp.synthhub.roomi-fields.com/mcp"}}}

On your machine — the MCP server over stdio, with hardware detection and OSC to a running bridge (each driver fetched from SynthHub when needed and kept in a cache; you choose what it shares):

bash
npx -y @roomi-fields/osc-bridge mcp

As a standalone bridge / CLI:

bash
npm install -g @roomi-fields/osc-bridge      # downloads the prebuilt binary# or grab a binary directly from the Releases pageosc-bridge run --device arturia/minilab3 --out-port 4   # a driver id, or a JSON file of yours

MCP client config and the tools → docs/MCP.md. Full quick-start with MIDI port discovery → § Install & quick start.

Why a bridge?

Modern synths — hardware and software alike — expose themselves over MIDI, SysEx, and OSC with proprietary, scattered protocols. Using them from live-coding environments, a DAW, a script, or an LLM is painful:

  • CC / NRPN addresses are cryptic
  • SysEx byte formats are hand-rolled per device
  • Bidirectional state (what the device CURRENTLY knows) is hard to track

osc-bridge gives every supported synth a clean, named OSC surface:

supercollider
~mb = NetAddr("127.0.0.1", 7777);~mb.sendMsg("/minilab3/knob/3/cc_number", 64);     // reconfigure knob 3~mb.sendMsg("/minilab3/pad/0/color", 127, 0, 0);    // pad 1 red~mb.sendMsg("/minilab3/display/text", "Hello", "World");

Each synth is described by one JSON file. No Rust recompile required to add a device.

Where the drivers come from

The catalogue lives on SynthHub, not in this repository: browse and search it at synthhub.roomi-fields.com. osc-bridge asks the SynthHub server for one driver at a time, when it needs it:

  • osc-bridge run --device korg/minilogue (a driver id) or --device minilogue (a slug: the device's best variant) fetches that driver and keeps it in the cache (~/.cache/osc-bridge/drivers/, or $XDG_CACHE_HOME, %LOCALAPPDATA%), then downloads it again only when the server's copy changed;
  • osc-bridge detect and the MCP tool detect_hardware ask the server which makers' identity requests to send, then send it the names of the MIDI ports found here and what the devices answered, and it names the matching drivers and firmware; list_devices searches the catalogue there;
  • offline (osc-bridge privacy --offline on, OSC_BRIDGE_OFFLINE=1), only the drivers already cached are used and nothing is sent.

These requests present the anonymous account of this machine. A JSON file on your machine is used as it is (--device my-synth.json, osc-bridge mcp --devices-dir my-drivers/).

What makes it different

  • One JSON = one driver. Adding a synth is ~30 lines of declarative JSON — CC numbers, SysEx frame templates, optional parameter tables. No Rust, no bindings, no build step. Ship a PR, osc-bridge run picks it up.
  • A shared catalogue. Prophets, Oberheims, the Yamaha DX family, MatrixBrute, Hydrasynth, Virus TI, Digitone, Matrix-1000… the SynthHub catalogue covers most synths, drum machines and DAWs, and grows with what users and agents contribute. Searchable at synthhub.roomi-fields.com.
  • Hardware and software. The same named OSC surface drives a hardware synth over MIDI/SysEx or a DAW / live-coding environment over OSC — Ableton, Bitwig, Reaper, Sonic Pi, SuperCollider, Pure Data, TouchDesigner, VCV Rack. See § Software targets.
  • An MCP server built in. osc-bridge mcp exposes the SynthHub catalogue to Claude (or any MCP client) — a MIDI MCP and OSC MCP. Discover devices, read a device's OSC surface, send OSC to synths and DAWs. See docs/MCP.md.
  • Honest provenance. Each device declares its source in _sources[]: ✅ hardware-verified, ✅ software-verified, 📘 vendor-doc, 📡 vendor-osc-api / 📡 third-party-osc, 🎛️ electra-preset, 📦 pencilresearch. You always know whether a mapping was tested on the device or lifted from a spec sheet.
  • Bidirectional out of the box. Incoming MIDI (knob turns, SysEx replies, NRPN) is decoded and re-emitted as OSC. Multi-client fan-out is a --osc-client flag.
  • N-to-N orchestration. One process can drive several synths at once (osc-bridge orchestrate --config bridge.toml), each reachable under its own OSC prefix — so two MatrixBrutes live side-by-side as /matrixbrute-1 and /matrixbrute-2.
  • First-class reconfigurable controllers (Electra One MK2). Upload a generated preset as one OSC call; the bridge parses the JSON, reconfigures the device over SysEx, and dynamically rewires its own CC↔OSC routing so each knob on the new layout is reachable by name. Self-describing over OSC: /bridge/docs returns the integration guide, /electra1/routes/list returns the authoritative address table, so clients (or LLM-driven integrators) never hardcode slugification or protocol details. See § Reconfigurable controllers below.
  • Escape hatch when JSON isn't enough. For devices with checksums, quirky scaling, or stateful protocols, an optional per-parameter transform / per-command script runs Lua 5.4 sandboxed (1 MiB / 10 ms caps, no os/io/loaders). Used sparingly — osc-bridge lint warns on every script use — but it lets the declarative core stay small without giving up on edge cases. See docs/scripting.md.
  • Runtime you can trust. Rate-limiting per device, backpressure-aware, zero-alloc hot path, no GC. Single static binary on Windows / Linux / macOS.

Supported devices

The catalogue — synths, drum machines, controllers, DAWs and live-coding environments, with each driver's source and how far users confirmed it — is on SynthHub:

Each driver declares its source in _sources[]: ✅ hardware-verified, ✅ software-verified, 📘 vendor-doc, 📡 vendor-osc-api / 📡 third-party-osc, 🎛️ electra-preset, 📦 pencilresearch.

Share your own device

New here? The 30-minute tutorial builds a working driver end to end. Otherwise — three common cases, pick yours:

Your synth isn't listed → write its driver and send it to SynthHub.

  1. Find a source: vendor programmer's reference, MIDI implementation PDF, or a canonical CSV.
  2. Follow docs/DEVICE_JSON_SCHEMA.md; the driver of a similar device (/api/v1/devices/<id>.json on SynthHub, or the copy in your cache) is a good template.
  3. Check it: osc-bridge lint my-synth.json, then osc-bridge run --device my-synth.json on the device.
  4. Contribute it: from an MCP client, the submit_driver tool (it is checked, then added to the catalogue); or open an issue here with the file.

A driver is wrong, or you tested it on the hardware → tell SynthHub: report_result and report_mapping (MCP) record what works on which firmware, and submit_fix turns learned mappings into a corrected driver.

Full contributor guide (schema extensions, bug reports, Lua escape hatch) → CONTRIBUTING.md. For devices whose protocol can't be expressed declaratively, see docs/scripting.md — use sparingly; osc-bridge lint warns on every use.

Reconfigurable controllers (Electra One MK2) — the scripts stress-test

Most synths have a fixed set of controls — MiniLab 3's knobs always mean the same thing. The Electra One MK2 is different: its 216 controls are defined by a preset that you upload to the device, and the meaning of every CC changes when the preset changes. A static JSON spec can't describe that; the bridge treats it as a first-class case.

This integration is what validates the whole Lua scripting subsystem in anger. The MK2 driver exercises every feature of the scripting.rs layer on real hardware (firmware 4.1.4, verified 2026-04-14):

  • Native JSON codec (ob.json_decode / ob.json_encode) — parses a full Electra preset (up to 100 KB of nested pages/devices/groups/controls/overlays) in a single Lua block, under the 500 ms preset_ingest profile.
  • Persistent per-device state (ob.state) — the driver stores the active preset name so /electra1/preset/current can report it on demand.
  • Dynamic CC↔OSC route registration (ob.register_cc_route / ob.clear_routes / ob.set_current_page) — every preset upload rebuilds the bridge's routing table from scratch, zero restart.
  • Multi-block SysEx emission (ob.emit_sysex) — the upload script emits the wrapped SysEx preset data block directly from Lua.
  • Outbound OSC emission (ob.emit_osc) — powers the introspection endpoints: /routes/list, /preset/current, /page/current.
  • Reply scripts with matched bindings (ctx.bindings) — when the device reports a page switch over SysEx, a reply script updates the bridge's active page so CC routing tracks the hardware UI automatically.
  • Companion markdown auto-load — the driver's notes (electra-one.md, next to its JSON) are loaded at startup and served over /bridge/docs, so LLM-driven integrators read the device-specific quirks (hex-color requirement, inputs[{potId}] mandatory, envelope-segment cycling gesture, MIDI port selection, etc.) without any code-side knowledge.

Every item above has a unit test, an end-to-end test against the real .json driver, and a hardware-verified green light. If you're building a driver for another reconfigurable controller (Faderfox custom, programmable MIDI Fighter), the Electra driver is the template — copy its custom_commands block, adapt the JSON→routes parsing to your device's preset format, done.

What the bridge does

 Kanopi / your client                   osc-bridge                     Electra One MK2─────────────────────                 ────────────────               ────────────────────
 /electra1/preset/upload  ───► parse preset JSON (preset_ingest   "<preset JSON>"                profile: 500 ms / 4 MiB Lua)                                ┌─ ob.clear_routes()                                ├─ ob.register_cc_route × N                                │    (one per cc7 control,                                │     per-page, with channel)                                └─ ob.emit_sysex(…)  ──────────► F0 00 21 45 01 01 <json> F7                                                                          (reconfigures device)                                                   ◄────────── F0 00 21 45 7E 01 …  ACK
 (user turns knob on page 2)                     ◄────────── B4 4A 53  (CC#74 ch5 = 83)                             route lookup: page=2, ch=4, cc=74                             → /electra1/page2/cutoff 0.65 ───► /electra1/page2/cutoff 0.65
 (user switches page on device)                  ◄────────── F0 00 21 45 7E 06 03 F7                             reply.script fires:                             ob.set_current_page(3)                                                               ───► /electra1/page/switched 3

Discovery from zero

Every piece of device-specific knowledge is exposed over OSC — clients never hardcode slugification rules, page indexing, or SysEx opcodes:

SendReceive
/bridge/statusOne /bridge/status/device <slug> <status> per connected device
/bridge/docs/bridge/docs/device <slug> <markdown> — full integration guide (the device's companion .md, loaded automatically)
/electra1/routes/listN× /electra1/routes/entry <addr> <ch> <cc> <page> <min> <max> then /electra1/routes/done
/electra1/preset/current/electra1/preset/current <name>
/electra1/page/current/electra1/page/current <n>

An LLM-driven integrator needs exactly four steps to go from cold start to routing knob turns: /bridge/status → /bridge/docs → /electra1/preset/upload → /electra1/routes/list. Everything else is in the markdown guide embedded in the bridge itself.

Generalising to other reconfigurable controllers

The machinery (DynamicRoutes, ob.register_cc_route, ob.emit_sysex, custom_commands, companion .md auto-loading) is device-agnostic. Adding a reconfigurable Faderfox, a custom MIDI Fighter Twister layout, or any programmable controller is the same recipe: a preset-parsing Lua block inside the device JSON that calls ob.register_cc_route per control. No core changes.

Install & quick start

Prebuilt binaries

Grab the latest osc-bridge.exe (Windows), osc-bridge (Linux/macOS) from the Releases page.

From source

git clone https://github.com/roomi-fields/osc-bridgecd osc-bridgecargo build --release./target/release/osc-bridge list

Minimal MiniLab 3 workflow

bash
# 1. Find your synth, its driver and its MIDI portsosc-bridge detect
# 2. Start the bridgeosc-bridge run --device arturia/minilab3 \  --out-port 4 --in-port 0 \  --bind 127.0.0.1:7777 --osc-client 127.0.0.1:8888
# 3. From another terminal, send OSCosc-bridge osc-send /minilab3/display/text "Hello" "World"osc-bridge osc-send /minilab3/pad/0/color 127 0 0osc-bridge osc-send /minilab3/knob/3/cc_number 100

Incoming MIDI events (knob turns, pads played, pitch-bend, SysEx GET replies) are forwarded to --osc-client as OSC:

/minilab3/cc/18 95 0        ← knob moved/minilab3/note/on 60 127 0/minilab3/param/value 0 7 0 0 1   ← reply from a /param/get

Browser clients (OSC over WebSocket)

Browsers can't speak UDP. Pass --ws-bind to expose the same OSC surface over WebSocket:

bash
osc-bridge run --device arturia/minilab3 \  --out-port 4 --in-port 0 --ws-bind 127.0.0.1:7890

Binary WS frames carry raw OSC packets — the exact bytes the UDP transport uses, so a minimal dependency-free OSC encoder/decoder in JS covers both directions. Every connected WS client behaves like an extra --osc-client: it receives all outbound events (decoded MIDI-in, SysEx replies, /bridge/status) and its frames go through the same dispatch as UDP. Under orchestrate, set ws_bind = "127.0.0.1:7890" in the [osc] section of bridge.toml. Disabled by default; keep it on 127.0.0.1 unless you really want LAN clients.

Only pages served from this machine (localhost, 127.0.0.1) and non-browser clients may connect: any other website open in your browser is refused (HTTP 403), so it cannot reach your synths. Allow a specific site with --ws-allow-origin https://example.org (repeatable; null for file:// pages; * for any), or ws_allow_origins = [...] in bridge.toml.

OSCQuery and MIDNAM

--oscquery-bind 127.0.0.1:7891 (or oscquery_bind in the [osc] section of bridge.toml) answers OSCQuery requests: http://127.0.0.1:7891/ lists every OSC address the bridge answers, with its types and ranges, so OSCQuery clients build their controls by themselves. osc-bridge export --device <driver> --format oscquery|midnam writes the same namespace, or the driver's MIDI names as a MIDNAM file for DAWs. See docs/EXPORT.md.

Device not showing up? (Windows 11 24H2+)

Since the March 2026 cumulative update (KB5079473), Windows 11 ships Microsoft's new USBMidi2-ACX driver which enforces stricter USB descriptor checks. Devices that pass the old checks but fail the new ones appear in Device Manager with Status: Unknown, or bind to a driver that exposes them only through the new MIDI Services API — invisible to midir (and therefore to osc-bridge) which queries the legacy MME interface.

Confirmed affected: Polyend Synth / Play / Tracker / Mess / Step (VID 16D0). Likely affected: any older USB-MIDI device whose descriptor doesn't meet the new spec.

Workaround — force the legacy usbaudio driver:

  1. Device Manager → Sound, video and game controllers → right-click the device → Update Driver.
  2. Browse my computer for drivers → Let me pick from a list of available drivers on my computer.
  3. Select USB Audio Device (FR: "Périphérique audio USB"). If not visible, uncheck "Show compatible hardware" and look under the Standard USB section.
  4. Install, then unplug/replug the USB cable to force MME to re-enumerate.
  5. osc-bridge list should now show the device.

Track Microsoft's progress on KB5079473 if you want a permanent fix — Pete Brown (Microsoft) acknowledged the packet-size issue publicly but classified it as non-blocking. Polyend's firmware-side fix is not announced at the time of writing.

Ergonomics

Which synth is plugged in, and which driver fits?

osc-bridge detect

Lists MIDI ports, asks each device who it is (the standard MIDI Identity Request, then the makers' own requests the drivers name — harmless), has the SynthHub server match the answers against the drivers' identity blocks (offline: the drivers cached here), with the firmware read from them, and prints a ready-to-run osc-bridge run line. --no-probe matches by port name only.

Back up and restore presets (SysEx librarian)

osc-bridge backup  --in-port minilab --out backups/minilab3.syx   # then start the dump on the deviceosc-bridge restore --out-port minilab backups/minilab3.syx        # overwrites the device's memory

Ports take an index or a name fragment. backup --request "F0 … F7" --out-port … sends a dump request first; restore --gap-ms paces older devices.

Drum machines: play sounds by name

Drivers with a drum map expose each voice: /drm1_mkiv/drum/kick 110 fires the Vermona DRM1 MKIV kick at velocity 110 (note 36, channel 10). When a device documents several trigger modes, the address carries the mode, e.g. /tr_8s/drum/default_note_map/bass_drum. See DEVICE_JSON_SCHEMA.md.

Explore a device spec without connecting anything

osc-bridge inspect arturia/minilab3

Live-debug the OSC traffic

osc-bridge osc-listen --bind 127.0.0.1:8888

Send raw SysEx (power user)

osc-bridge osc-send /minilab3/raw/syx "F0 00 20 6B 7F 42 02 00 16 04 7F 00 00 F7"

How device JSONs work

A device file declares three things:

  1. Framing — the SysEx header/footer bytes.
  2. Commands — high-level OSC routes (pad colors, display text, preset recall) that build frames by substituting OSC args into placeholder templates.
  3. Params — a flat table of parameter addresses for bulk GET/SET via a shared opcode.

Example snippet (the arturia/minilab3 driver):

jsonc
{  "commands": [    {      "osc": "/pad/{pad}/color",      "args": [        {"name":"pad","type":"u7","range":[0,7]},        {"name":"r","type":"u7"},        {"name":"g","type":"u7"},        {"name":"b","type":"u7"},        {"name":"mode","type":"enum",         "values":{"user":0,"arturia":1,"daw":2},"default":"user"}      ],      "pre": [{"bind":"pad_id","expr":"pad + 4"}],      "frame": [2, "{mode}", 22, "{pad_id}", "{r}", "{g}", "{b}"]    }  ],  "params": {    "get_frame": [32, "{pr}", "{p}", "{c}", "{r}"],    "set_frame": [33, "{pr}", "{p}", "{c}", "{r}", "{val}"],    "value_type": "u7",    "entries": [      {"osc":"/global/backlight", "pr":7, "p":0, "c":0, "r":0, "range":[0,1]}    ]  }}

Software targets — DAWs and live coding environments

osc-bridge isn't only for hardware synthesizers. Since version 0.10 it also treats DAWs and live-coding environments as first-class devices, behind the same /<env> OSC surface as a Prophet or a Matriarch. A driver JSON declares device.transport.kind = "osc" and the bridge forwards OSC to the target's UDP port instead of going through a MIDI cable.

Two flavors:

Declarative drivers — when the host software has a fixed, documented OSC surface (Ableton via AbletonOSC, Bitwig via DrivenByMoss, Reaper's native OSC). The driver enumerates commands[] with typed args, plus replies[] for incoming events.

Passthrough drivers — when the host software has no fixed OSC surface and each user defines their own paths in their project (Sonic Pi, SuperCollider, Pure Data, TouchDesigner, VCV Rack). The driver just declares transport.passthrough_prefix and the bridge forwards anything under /<env>/... verbatim. Replies travel the other way with the prefix added back.

Currently supported:

TargetModeStatus
Ableton Live 12.2.7 + AbletonOSCdeclarative✅ software-verified
Bitwig Studio + DrivenByMossdeclarative📡 third-party-osc
Reaper 7 (Default.ReaperOSC)declarative📡 vendor-osc-api
Sonic Pi 4.5passthrough📡 vendor-osc-api
SuperCollider sclang 3.13passthrough📡 vendor-osc-api
Pure Data 0.55-xpassthrough📡 vendor-osc-api
TouchDesigner 2023passthrough📡 vendor-osc-api
VCV Rack 2 + vcv-osc pluginpassthrough📡 third-party-osc

Each driver comes with its .md notes on SynthHub that document the required setup on the host side (Remote Script installation, ports, conventions).

Combined with osc-bridge orchestrate, you can drive a hardware MiniLab 3, an Ableton Live, and a Sonic Pi loop from a single process. With the new [[routes]] section in bridge.toml, a knob turn on the MiniLab can drive an Ableton track volume or a Sonic Pi cue, without writing any client code:

toml
[osc]bind = "127.0.0.1:7777"clients = ["127.0.0.1:8888"]# ws_bind = "127.0.0.1:7890"   # optional — browser clients over WebSocket
[[devices]]spec = "arturia/minilab3"      # a driver id or slug, or a JSON filemidi_out_port = 4midi_in_port = 0
[[devices]]spec = "ableton/live.third-party-osc.fw-12.2"   # AbletonOSC: no MIDI port needed
[[routes]]from = "/minilab3/cc/74"to = "/ableton/track/0/volume"map.from = [0, 127]map.to = [0, 1]

Use from Claude via MCP

osc-bridge ships a Model Context Protocol server — a MIDI MCP and OSC MCP. Point any MCP client at it and the model can browse the SynthHub catalogue, read a device's OSC surface, and send OSC to synths and DAWs.

Hosted — add https://mcp.synthhub.roomi-fields.com/mcp as a remote MCP server (see Install). Nothing to install; your synth joins through the relay page, synthhub.roomi-fields.com/connect.

On your machine:

jsonc
{  "mcpServers": {    "osc-bridge": {      "command": "npx",      "args": ["-y", "@roomi-fields/osc-bridge", "mcp"]    }  }}

Nine local tools — list_devices, get_device_docs, list_routes, export_device, send, get_status, detect_hardware, backup_presets, restore_presets — plus the server's: reports, trust, contributions and shared presets (find, load, take from the synth, share). Then in conversation: "What can the MatrixBrute do? Sweep its filter cutoff." — the model calls list_routes("matrixbrute"), then send. No glue code.

Full setup — Claude Desktop / Cursor config, the workflow, driving software targets → docs/MCP.md.

Project genesis

Started as a MatrixBrute OSC driver (patch format reverse-engineered from the GPL-3 sysex-controls and the community MBPV tool). Grew into a generic declarative bridge once the Arturia protocol family became clear.

License

AGPL-3.0-or-later. Running a modified version as a network service obliges you to offer its source to the users of that service. The sysex-controls reverse engineering that seeded our MiniLab 3 parameter table is GPL-3.0, which GPL-3.0 section 13 allows to combine with AGPL-3.0 code.

Third-party device data

The driver catalogue is SynthHub's, each driver with the credit and licence of its sources in _sources[]. The few drivers kept here for the tests (tests/fixtures/devices/) keep theirs: those of type pencilresearch are adapted from MIDI Guide by Pencil Research and contributors, licensed CC BY-SA 4.0 (source: pencilresearch/midi); each records the licence, the attribution and the exact upstream CSV and commit; the change made is the conversion of CSV rows to the osc-bridge JSON schema.

Source: README.md at commit 365159a

Tools

29

list_devices

List devices

Find device drivers in the catalogue of synths, drum machines, controllers and DAWs. Without arguments it lists them all; `query` keeps drivers whose vendor, name or slug contain every word (e.g. 'korg minilogue'). Returns name, vendor, OSC prefix (slug), kind, source tier and firmware version when the source states one. Pass the slug to list_routes for the full CC/NRPN/SysEx map.

Parameterskindlimitqueryvendoruser_id

get_device_docs

Get device docs

Fetch the markdown companion documentation for one device, if present. The slug is the device's OSC prefix without the leading slash (e.g. 'ableton' for /ableton).

Parametersslugrequireduser_id

list_routes

List device routes

Return the OSC routes a device exposes: declarative commands (OSC paths it accepts), cc/nrpn params, sysex params, named note triggers (drum sounds), and reply patterns. Use this to discover what a device can do.

Parametersslugrequireduser_id

export_device

Export a driver

Write one driver in a format other tools read: 'oscquery' gives its OSC namespace as OSCQuery JSON (every route with type tags, ranges and access, for OSC controllers and browsers); 'midnam' gives its MIDI names as a MIDI Name Document (controllers incl. NRPN/RPN, named values, drum notes per channel, for DAWs such as Ardour or Logic). Both carry the credit and licence of the driver's sources. The document is the text content; an OSCQuery namespace is large (every address, each CC 0-127 included).

Parametersdevicerequiredformatrequireduser_id

report_result

Report a test result

Tell the catalogue how a driver behaved on a real device, after testing it: 'works', 'fails' or 'partial', for the whole driver or one OSC address (from list_routes). Give the firmware version, and the device's reply to the MIDI Identity Request (F0 7E 7F 06 01 F7) as identity_hex when you can: trust is counted per firmware, so a failure on another firmware does not count against the driver, and a report of unknown firmware cannot be placed. Several accounts that agree on one firmware mark the driver usage-verified there; a report that several others contradict is rolled back and puts its account under review. Report only what was actually tested.

Parametersnotedevicerequiredaddressoutcomerequireduser_idfirmwareidentity_hex

get_trust

Get a driver's trust

How far a driver has been confirmed by people who used it, per firmware: status (unreported, unconfirmed, usage-verified, firmware-dependent, failing, disputed), how many users report it works / fails / partly works, each firmware's own status, the device identities seen for each firmware, and the same per OSC address. needs_firmware: true means reports disagree and some have no firmware — identify the device before reporting (see learn). Check it before relying on a driver, together with its source_tier.

Parametersdevicerequireduser_id

report_mapping

Report what a control sends

Teach the catalogue which MIDI message a control really sends: after the user moved one control on the device (see relay_listen), give the driver address it is (from list_routes) — or, for a control the driver lacks, its panel label — and the CC, NRPN or note it sent, with the firmware and the device's Identity Reply when you have them. When several accounts observe the same thing on one firmware the mapping is learned; get_trust shows learned mappings and where they differ from the driver.

Parametersccnotelabeldevicerequiredaddresschanneluser_idfirmwarenrpn_lsbnrpn_msbidentity_hex

submit_driver

Contribute a driver

Contribute a driver for a device the catalogue lacks (or a better one): the full driver file as a JSON object, in the osc-bridge device schema (device.name, device.vendor, device.osc_prefix, and cc_params / params / commands / triggers — see https://synthhub.roomi-fields.com/DEVICE_JSON_SCHEMA/). It is checked, then merged into the SynthHub catalogue by the merge job if it parses, lints and passes the tests, as its own file of source 'agent-contributed'. Say where the data comes from (manual page, tested on the device).

Parametersnotedriverrequiredsourceuser_idfirmware

submit_fix

Contribute a fix from learned mappings

Contribute a corrected variant of a driver from what the catalogue learned: where learned mappings (get_trust → mappings, differs: true) disagree with the driver on one firmware, builds a copy of the driver with the learned CC / NRPN numbers, as a new file for that firmware, and queues it for the merge job.

Parametersdevicerequireduser_idfirmware

get_contribution

Contribution status

Where a contribution stands: pending (waiting for the merge job), merged (with its pull request), rejected (with the reason), or held (its account is under review).

Parametersidrequireduser_id

share_preset

Share a preset

Share something the user made on a device with every SynthHub user, under CC BY-SA 4.0: a sound, a sequence or pattern, a kit, a project, a bank of their own sounds, or a MIDI clip any device can play. Its content: the device's own data (SysEx, e.g. from backup_presets), settings by driver address (from list_routes, e.g. {'/filter/cutoff': [90]}, which also works for devices without dumps), and/or a standard MIDI file. Only what the user made: never factory presets, nor sounds or sequences bought or downloaded from others — set own_sound only after asking the user. Made from someone else's shared preset? Pass derived_from: it credits them, as the licence requires. Describe it well (category, genres, tags, tempo, key, tips): that is how people find it. The same content shared twice returns the existing id; the author publishes new versions with update_preset and can withdraw it (withdraw_preset). Through a relay, the device data can be captured from the device itself: pass code and start the dump from the device's menu during the call, or give request_hex (the device's dump-request message, which the user accepts at the relay). An audio preview is added by its author with PUT /u/<account>/v1/presets/<id>/audio (MP3, Ogg, M4A or WebM, 1 MB at most).

Parametershexkeycodekindnamerequiredporttagstipstempodevicerequiredgenresseconds+10 more

update_preset

Update a preset

Publish a new version of a preset this account shared: new content (hex, file, settings or midi_file) makes a new version, kept with a change note — earlier versions stay available; the description fields alone change it in place. Someone else's preset: share yours with derived_from instead.

Parametersidrequiredhexkeynametagstipstempogenresuser_idcategoryfirmwaresettings+3 more

find_presets

Find presets

Search what SynthHub users shared (CC BY-SA 4.0): sounds, sequences, kits, projects, banks, MIDI clips. Filter by device, kind, category, genre, tag, author (pseudonym) or words; sort by newest, most stars, most loaded into a device or most trusted (confirmed on real devices). Returns, per preset, its id, name, kind, device, description, author, version, whether it has device data, settings, a MIDI file or an audio preview (URL), and its counts. Get one with get_preset.

Parameterstagkindsortgenrelimitqueryauthordeviceoffsetuser_idcategory

get_preset

Get a preset

One shared preset in full: its content (SysEx hex, settings by driver address, MIDI file), description and playing tips, versions with their change notes, what it was derived from and its derivatives (remixes), comments, preview URLs, author, licence and attribution line, trust and counts. Load it with load_preset; credit it as the attribution line says when you publish something made from it.

Parametersidrequireduser_idversion

report_preset

Report on a preset

Tell SynthHub how a shared preset behaved once loaded on a real device: 'works' (it loaded and sounds as described), 'fails' (refused, wrong sound), or 'factory' (it is a factory preset or someone else's sound: presets that several users flag are hidden until reviewed). Give the firmware.

Parametersidrequirednoteoutcomerequireduser_idfirmware

withdraw_preset

Withdraw a preset

Withdraw a preset this account shared: it is no longer listed nor served. Copies others already made stay under CC BY-SA.

Parametersidrequireduser_id

comment_preset

Comment on a preset

Comment on a shared preset — how it sounds, how you used it, what you changed — optionally attaching your remix (a preset you shared with derived_from). Comments are public at once. Also: remove one of this account's comments (remove), or flag someone else's as abusive or off-topic (flag); comments several accounts flag are hidden until reviewed.

Parametersidflagtextremixremoveuser_id

star_preset

Star a preset

Star a shared preset for this account, as on GitHub (on: false takes the star back). Without id, lists the presets this account starred.

Parametersidonuser_id

preset_collection

Preset collections

Collections of shared presets, public, made by one account (e.g. 'Dark basses for minilogue'). action: create (name, description), rename (collection, name, description), add or remove (collection, id), delete (collection), get (collection: its presets), list (this account's collections, or author: someone's).

Parametersidnameactionrequiredauthoruser_idcollectiondescription

follow_author

Follow an author

Follow an author of shared presets (by pseudonym), or stop (on: false); with author alone and on omitted, shows their page: profile, presets, followers. Without author, lists the newest presets of the authors this account follows.

Parametersonlimitauthoruser_id

set_profile

Set the public profile

Set the public profile shown on this account's author page and with its shared presets and comments, instead of its pseudonym alone: display name, link (https), a few words, the presets put first, where they are, more links, their instruments and a README. A field left out stays as it is; an empty one is cleared. Ask the user what they want shown; all of it is public.

Parametersbiogearlinknameaboutlinksuser_idfeaturedlocation

relay_status

Relay status

Check a relay: the user opened https://synthhub.roomi-fields.com/connect/ (or ran osc-bridge connect) and gave you its pairing code. Returns the MIDI output and input ports of their machine, and devices: the driver the user confirmed for each port on the page (use it directly, no detection needed). Nothing is sent to the hardware.

Parameterscoderequireduser_id

relay_detect

Detect devices through a relay

Find which devices are connected to the user's machine through a relay: sends the MIDI Identity Request (F0 7E 7F 06 01 F7, changes nothing on the device) to every output and matches the answers — manufacturer, model, firmware version — against the drivers' identity blocks. With maker_requests, also sends the makers' own identity requests the drivers name (they change nothing either, but the relay asks the user to accept them, once per output: tell the user first), which recognise devices that ignore the universal one. Returns the best driver ids (recognised_by and firmware when an identity block recognised the device) and identity_hex to pass to report_result. A device that does not answer is found by its knobs with listen_ms (by_controls), or by what people confirmed of its port name (learned); when several remain, ask names the control to have the user turn next (expect: what each candidate would send), then call again with listen_ms.

Parameterscoderequireduser_idlisten_mstimeout_msmaker_requests

relay_send

Send through a relay

Play or set something on the user's hardware through a relay: give a driver (id or slug) and one of its OSC addresses from list_routes with its arguments (e.g. address '/filter/cutoff', args [64]; '/note/on', args [60, 100]) — the server turns it into the right CC, NRPN, note or SysEx message. Or give raw MIDI bytes as hex. Values are the device's own numbers, clamped to the parameter's range. Any SysEx but the Identity Request (patch dumps, stores, settings, preset restores) may overwrite the device's memory: the relay asks the user to accept it first and this call waits for the answer (up to 2 minutes), so tell the user what you are about to send.

Parametershexargscoderequiredportdevicegap_msaddressuser_id

relay_listen

Listen through a relay

Listen to what the user's hardware sends through a relay for a few seconds: notes, CC, NRPN, SysEx, decoded. With a device, each CC or NRPN that moved is matched to the driver's OSC addresses — ask the user to move one control on the device while listening to learn which address it is, or to check that the driver's map is right (then record what you saw with report_mapping, so the catalogue learns it).

Parameterscoderequireddevicesecondsuser_id

take_sound

Take a synth's sound through a relay

Take the sound the user's synth is playing — or one of its stored programs — straight from the synth through a relay, with its name. The synth is found among those SynthHub's librarian can talk to (the KnobKraft Orm adaptations, about 90 synths) by the identity and detect messages, then asked for its sound. The person accepts each step at the relay (finding the synth, asking it): tell them first. To share it: ask the user whether they made this sound themselves (never a factory preset, nor one bought or downloaded), then call share_preset with the device, name, hex, librarian and firmware returned here, and own_sound: true. When several synths answer, or none did, call again with port.

Parameterscoderequiredportprogramuser_id

load_preset

Load a preset through a relay

Load a shared preset (find_presets, get_preset) into the user's device through a relay: its settings are sent through the driver, its patch data as SysEx — which replaces the sound the device holds, so the relay asks the user to accept it and this call waits for the answer (up to 2 minutes): tell the user first. Afterwards, tell SynthHub how it went with report_preset.

Parametersidrequiredcoderequiredportdevicegap_msuser_id

claim_presets

Claim imported presets

Claim presets SynthHub imported from another site (their page says 'imported', with the author's name and page there) when the user is that author: give the id of one of them; the server answers with a code for the user to add to their author page at that site (profile or bio). Once it is there, call again with verify: true: every preset imported from that author becomes the user's, to edit or withdraw.

Parametersidrequiredverifyuser_id

Version history

6
  1. v0.19.1LatestOct 31, 2026
  2. v0.19.0Oct 31, 2026
  3. v0.17.0Oct 29, 2026
  4. v0.16.0Oct 24, 2026
  5. v0.15.0Oct 23, 2026
  6. v0.10.1Sep 16, 2026

Score

100% of the applicable checks met

How complete this listing is, computed from the registry entry, the endpoint and public sources. Not a rating of the server and not a statement that it is safe or working today: reachability is a dated check, and no installs or reviews go into the score.

  • Reached in the last 30 daysRequired25 pts
  • Auth declaredRequired10 pts
  • Tools listedRequired15 pts
  • DescriptionRequired15 pts
  • Logo10 pts
  • Documentation15 pts
  • License10 pts