oscine
Allows Max/MSP to control Oscine parameters (e.g., faders, params, notes, slot switching) and receive feedback via the OSC gateway.
Click on "Install 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., "@oscinecreate a new song with a poly synth and drum track"
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.
Oscine
A synth composer that runs entirely in the browser. No build step, no dependencies, no samples: every sound is synthesized live with Web Audio, and a whole song saves as a few KB of JSON.
The part that matters is underneath. Everything Oscine can do is one command in one catalog, and that catalog is the product. Five surfaces drive it: the UI, the browser console, the bundled Claude plugin over MCP, an OSC gateway, and live MIDI. So Oscine is two things at once. It is a synth you play with your hands, and it is a performance bridge that an agent or a controller can play through, on any surface that speaks MCP, OSC, or MIDI. The synth is the concrete part you can hear. The bridge is the point.
Because the catalog is the contract, the agent surface is not bolted on, it is the same surface you use. Claude can compose, sound-design, mix, switch patterns, and play notes in your live session, and read back the performance ledger (an always-on log of what you played) to grab a riff after the fact. The architecture is shaped so the larger parts (an arrangement timeline, audio clips, and automation) bolt on without a rewrite. See "Where it's going" below.
Run it
Four ways:
Hosted: https://chazmaniandinkle.github.io/oscine/ . The app is static files, so the repo serves it directly via GitHub Pages. Projects autosave to your browser's localStorage; export/import JSON for real files. If the Oscine sidecar (from the Claude plugin) is running on your machine, the hosted page connects to it automatically, which lights up MCP and OSC control of the page you are looking at. (Chrome, Edge, and Firefox let a secure page reach 127.0.0.1; Safari blocks it, so use another option there.)
Claude plugin: add this repo as a marketplace, then install it.
claude plugin marketplace add chazmaniandinkle/oscine, thenclaude plugin install oscine@oscine. Claude runs the sidecar, which serves the app athttp://127.0.0.1:7321/. Ask Claude to "open oscine", or open the URL yourself. Update later withnpm run release:local.Claude Code preview: with the repo open in Claude Code, the built-in preview hosts the app from
.claude/launch.json(theoscinelaunch config). It is a real browser context, so Web Audio, WebMIDI, and the sidecar bridge all work, and the previewed app is agent-drivable inline.Dev server:
./start.sh(orpython3 -m http.server 8443) from the repo, then open the printed URL. Any static server works; one is required because native ES modules do not load overfile://.
The sidecar only accepts bridge connections from localhost plus origins in
OSCINE_ALLOWED_ORIGINS (the plugin pre-allows this repo's Pages URL), so
arbitrary websites cannot reach your session.
First open loads a small demo song ("First Light"). Press Space. Click once anywhere first if you hear nothing: browsers keep audio suspended until a user gesture.
Related MCP server: FL Studio MCP
Using it
Transport bar: play/stop, tempo (drag the bpm number), swing, metronome, pattern slots A-D, bar length per slot, undo/redo, song name, File menu (copy share link, export audio WAV, export/import JSON, new project), master level.
Two ways to get a song out. "Copy share link" packs the whole project into
the URL itself (a few KB of pattern data, no upload), so a link is the song;
open that link and Oscine loads it before the UI draws. The link is
gzip-compressed (via CompressionStream) for a shorter URL, and older
uncompressed links still open. "Export audio (.wav)"
bounces the active slot through the full mix and master FX with an
OfflineAudioContext and downloads a 16-bit WAV. Both run through the same
command catalog as everything else, so Claude can trigger them over MCP
(oscine_share, oscine_export_wav) too.
Pattern slots are four independent pattern sets sharing the same tracks, like scenes. Click a slot (or keys 1-4) to switch; while playing, the switch queues and lands exactly on the next loop boundary. Copy moves the active slot's patterns to another slot.
Tracks: "+ Add" creates a Poly Synth, FM Synth, or Drum Kit track. Select a track to edit it; double-click the name to rename; M/S to mute/solo. The editor in the middle follows the selected track's type.
Piano roll (synth tracks): click to add a note and drag to set its length; drag notes to move, drag the right edge to resize; alt+drag for velocity (brightness shows it); shift+drag for marquee select; right-click or double-click deletes; Delete clears the selection; cmd/ctrl+A selects all; ctrl/cmd+wheel zooms time; the left key gutter auditions pitches.
Step grid (drum tracks): click toggles a step, drag paints, shift+click cycles velocity soft/med/hard. Lane labels audition the sound.
Keyboard footer: play the selected synth track with the mouse or with A-row keys (A W S E D F T G Y H U J ...), Z/X shifts octave. On a drum track the footer becomes pads on A-K. You can also play a hardware MIDI controller; see "Where it's going" for velocity shaping, record, and the OSC bridge that works even where WebMIDI is blocked.
Inspector (right): every instrument parameter as knobs, rendered from the instrument's own schema, plus presets, pan, and FX sends per track.
Mixer (bottom): fader, meter, pan, delay/reverb sends, mute/solo per track; the master strip carries the shared delay (tempo-synced) and reverb plus the master fader.
Everything autosaves to localStorage; File > Export writes the song as JSON you can commit, share, or re-import.
Architecture
src/
core/ no DOM, no audio. Importable from node.
bus.js event bus: the only channel between layers
store.js single source of truth + all mutations + undo
schema.js project format, factories, demo song
persist.js autosave + JSON import/export
util.js helpers
engine/ audio only. Never mutates the project.
engine.js track channel strips, FX buses, master chain, scheduling
transport.js lookahead scheduler, beat clock, swing, loop/slot logic
context.js lazy AudioContext
effects/ delay, reverb (send buses)
instruments/ registry + poly synth, FM synth, drum kit
api/ the programmatic surface (the catalog is the contract)
commands.js command catalog: names, descriptions, JSON Schemas
api.js CommandAPI: binds the catalog to store/engine/transport
bridge.js WebSocket client that links the app to the MCP sidecar
crosstab.js BroadcastChannel + Web Locks cross-tab coordination
ui/ DOM only. Never touches audio nodes.
app.js layout shell, editor routing, the single rAF loop
pianoroll.js canvas note editor
stepgrid.js drum grid
midi.js WebMIDI input, velocity shaping, record, cross-tab owner
mixer.js inspector.js tracklist.js transportbar.js keyboard.js
widgets.js knob/fader/meter/menu primitives
main.js wires everything; exposes window.oscine for console work
plugin/ the Claude plugin (see below)
tools/ sync-plugin.mjs keeps plugin/app identical to the repo;
midi-osc-bridge.mjs forwards a controller into Oscine over OSCThe data flow is one-directional and event-driven:
UI gesture ----\
console call ---\
MCP tool --------> store action -> mutation + bus event -> engine mirrors audio
OSC message ----/ -> UI re-renders
MIDI in -------/The engine and UI never call each other directly; both react to the store through the bus. Undo, import, and autosave fall out of that: any project replacement emits one event and every layer rebuilds itself.
The catalog is the contract
src/api/commands.js is the contract: 21 commands covering everything the UI
can do (transport, project ops, tracks, instrument params and presets,
piano-roll notes, drum steps, mixer, master FX, pattern slots, preview,
live MIDI, and the performance ledger). Each command carries a JSON Schema;
CommandAPI validates,
clamps, resolves tracks by name or id, and returns JSON. The UI, the browser
console, MCP, OSC, and MIDI are five consumers of the same surface:
// browser console
await oscine.api.execute('status')
await oscine.api.execute('set_notes', { track: 'Bass', mode: 'replace',
notes: [{ start: 0, pitch: 33, dur: 0.5, vel: 0.9 }] })The test suite executes every command headlessly, so catalog, handlers, and store cannot drift apart.
Claude plugin (MCP)
plugin/ is a complete Claude plugin; oscine.plugin is its packaged form.
Its sidecar is one zero-dependency node process that Claude starts and stops
via the plugin's .mcp.json:
MCP server over stdio:
oscine_open_app,oscine_sessions, plus oneoscine_*tool per catalog command (23 total), schemas taken directly from the catalogHTTP server on
127.0.0.1:7321(next free port if busy) serving the bundled app fromplugin/app/WebSocket bridge at
/bridgethat the app connects back through; the green dot in the transport bar shows the link is up. With several tabs open, the sidecar tracks each as an addressable session and routes commands to the active one (oscine_sessionslists and switches).
So the full loop is: Claude calls a tool, the sidecar forwards it over the socket, the app executes it against the same store the UI uses, and you hear and see the result live. The plugin also bundles a composing skill so Claude knows the conventions (beats, MIDI, lanes, slots).
The sidecar also runs an OSC gateway (udp://127.0.0.1:7340), mapping the
/oscine/* address space onto the same catalog: TouchOSC, Max/MSP, Pd,
SuperCollider, Sonic Pi, and friends can fade tracks, tweak params, play notes,
switch slots, and feed in MIDI (/oscine/midi/in), and subscribers get
position, meters, tempo, and slot feedback back. Address table in
plugin/README.md. OSC, MCP, MIDI, the UI, and the console are five consumers
of one contract.
After changing the app, run node tools/sync-plugin.mjs and repackage; the
tests fail if the bundled copy drifts.
Timing uses the standard lookahead pattern: a 25ms JS timer schedules the next 120ms of events at sample-accurate AudioContext time. The transport walks beats and emits scheduling windows that are segmented at loop boundaries, which is what makes queued pattern-slot switches land exactly on the 1. Notes are stored in beats (floats), so finer grids and triplets are a UI option later, not a format change.
Extending it
New instrument: create src/engine/instruments/yoursynth.js, subclass
BaseInstrument, implement noteOn/noteOff (or trigger for kits), call
defineInstrument({...}) with a param schema, and import the file from
instruments/index.js. It then appears in the Add menu, gets a generated
inspector, presets, mixer strip, and sequencing for free. fmsynth.js is the
template: a complete instrument in ~150 lines.
New effect: follow effects/delay.js (an input/output node pair), add it to
the engine's bus wiring, and surface params via store.setFx.
New editor or panel: subscribe to bus events, render from the store, call store actions on input. Nothing else to hook up.
Project format: plain JSON, versioned (version: 1), shape defined in
core/schema.js.
Verifying
node test/smoke.mjs # zero-dep: import graph, store, scheduler math,
# every API command headless, plugin integrity
node test/e2e-mcp.mjs # full chain: real MCP stdio -> sidecar -> WS ->
# headless Chromium running the app
# (needs playwright-core + CHROME_BIN)UI pixels and audio output are exercised in the browser; the suites cover everything below that line, including the entire MCP path.
Where it's going
The synth is the reference instrument. The direction is to make the bridge underneath it do more, while the larger DAW parts bolt on as they earn their place.
Already shipped:
MIDI input: plug in a MIDI controller, enable MIDI from the transport bar, and play the selected track. Record-arm captures the notes (or drum steps) quantized to the grid, and you can map knobs to instrument params. Incoming velocity is shaped in software so stiff mini-keys still play loud: set a floor (the loudness of the softest press), a curve (gamma; below 1 makes soft presses more sensitive), or an optional fixed velocity that ignores the controller entirely. A velocity monitor reports the raw values you play back (last, min, max, count, and the recent run) so you can match the curve to your controller by feel. Only one tab owns the hardware at a time: enable MIDI in one tab and a second tab defers, offering a "Take over" control that claims ownership for itself. Autosave is per-tab keyed now, so two open tabs no longer clobber each other's work in localStorage. Also drivable through the
midicommand (settakes floor/curve/fixed,monitorreads the raw spread, andclaimtakes MIDI ownership for the current tab) and the/oscine/midi/*OSC addresses (including/oscine/midi/floorand/oscine/midi/curve).MIDI over OSC (works where WebMIDI is blocked): some surfaces deny the WebMIDI permission outright (the Claude Code preview is one), so there is a second path in.
npm run midi-bridge(after a one-timenpm i @julusian/midi) reads a connected controller and forwards its raw messages to Oscine over OSC at/oscine/midi/in <status> <d1> [d2]. Those bytes feed the same input pipeline WebMIDI uses, so velocity shaping (floor/curve/fixed), the velocity monitor, record-arm, and drum-lane mapping all apply identically. The bridge takes--listto print available input ports,--device <substring>to pick one by name, and--host/--portto target a sidecar elsewhere (default127.0.0.1:7340, the OSC gateway).@julusian/midiis an optional install, not a runtime dependency: the app and sidecar stay zero-dependency, and the bridge prints an install hint if the module is absent. Any OSC source can play Oscine the same way by sending/oscine/midi/in, so a controller on any surface, including a phone over the local network, becomes an input.Performance ledger: an always-on, bounded log of what you play live (on-screen keys, computer keyboard, drum pads, and hardware/OSC MIDI). It records even when the transport is stopped (free play), wall-clock time-stamping each event and adding the musical beat when the transport is running. The
ledgercommand reads it back, with a derived view that pairs note-ons with note-offs into played notes and lists drum hits, so an agent can transcribe a phrase straight intoset_notes/set_steps. Agent auditions (preview) are not recorded, only your own play. This is the observer half of the agent surface that makes the jam loop real.
Planned, roughly in order of effort (see ROADMAP.md for the full picture):
Song arrangement: a timeline view that sequences slot patterns into a song. The transport already segments scheduling windows; an arrangement is a map of bar -> slot per track.
Per-step locks, probability, ratchets: a step-schema extension plus scheduler support, and a new vocabulary for an agent to drive.
Per-track insert effects and automation: the channel strip is already a node chain; inserts are an array between gain and panner, and automation lanes are time-indexed param events scheduled in the same windows as notes.
Audio/sample tracks: a new instrument kind whose patterns hold clip references;
decodeAudioData+AudioBufferSourceNodeslots into the existing channel strip unchanged.Worker clock and OSC timetag scheduling: move the timer into a Worker so background tabs keep steady time, and honor OSC bundle timetags for sample-tight external sequencing.
New features land as catalog commands first, UI second; OSC, MCP, and MIDI then consume them for free.
Notes
Param knob tweaks are intentionally outside undo history; structural edits (notes, steps, tracks, slots, presets) are undoable.
Shortening a slot's bar count keeps note/step data beyond the loop end in the file; it just does not play until you lengthen the loop again.
Chrome, Firefox, and Safari current versions all work. Safari needs one interaction before sound starts (autoplay policy), same as the others, and has no WebMIDI (use the OSC bridge for hardware there).
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/chazmaniandinkle/oscine'
If you have feedback or need assistance with the MCP directory API, please join our Discord server