Skip to content

Latest commit

 

History

98 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

SynthV Agent Bridge

English | 简体中文

A local Model Context Protocol (MCP) server that lets compatible AI clients inspect and control the project currently open in Synthesizer V Studio 2 Pro.

The bridge uses Synthesizer V's public Lua scripting API. It does not parse or rewrite .svp files, open a network port, or call an AI API by itself.

Video demo: Watch SynthV Agent Bridge on Bilibili

New here? Follow the host-neutral Quickstart, then choose the Codex or Claude Code project profile. 中文用户请参阅中文快速开始;环境检查、依赖与 Node.js 安装、构建、SynthV 脚本安装与诊断均不依赖具体 Agent 宿主。

Tip

The optional guided Twinkle Star demo and Agent operating rules are now maintained in the separate synthv-copilot skill plugin. This Runtime repository contains no startup prompt or mandatory Agent workflow.

Important

Because SynthV's official scripting API cannot read the current Vocal identity or enumerate untouched default-only singing style (Vocal Mode) names and parameters, first select a Note Group, then select or assign the Vocal you want to use for that Group. Only then attach a screenshot of its complete singing-style panel or type every style exactly as shown; the names cannot appear before a singer is selected. If no suitable Note Group exists or the Vocal Modes are not visible, first create—or ask the Agent to create—one temporary note in one temporary non-main Note Group at a harmless location, select that Group and its Vocal, then capture the complete panel. After changing Vocals, capture the new Vocal's complete panel or type all of its singing-style names again; do not reuse the previous Vocal's list.

Status: v0.3.1 / protocol v3 (reduced-stable surface). This release separates the host-neutral Runtime from portable Agent skills while keeping the six-tool semantic Facade, typed Query Contexts, compact Command outcomes, component build-coherence checks, Query Projector, common Command Kernel, semantic write-policy catalog, aggregate tuning, and dependent transaction recovery are implemented. Release validation has fresh evidence for 17/17 Query, 9/9 UI, and 31/38 write Actions. Seven clone/transaction/harmony paths with native-host risk are marked experimental and disabled before project IPC; no write Action remains pending. Human listening, the Stage 3 functional write/Undo matrix, and the user-approved one-hour soak (200 writes, 3,400 reads, 10 reloads) passed. The post-fix resource-monitor rerun was explicitly waived for this release and remains documented as follow-up risk rather than being represented as a pass. Test writes only on saved working copies.

See the v3 architecture, development plan, and SV2 API coverage matrix.

What it can do

Area Capabilities
Project inspection Read project metadata, tracks, library Groups, notes, selections, tempo/time-signature maps, computed phonemes and pitch, automation, mixer state, and editor context.
Notes and lyrics Add, edit, delete, clone, transpose, or humanize guarded notes; fit lyrics and edit language, singing/rap type, timing, detune, and note attributes.
Voice and phonemes Read and edit Group Voice, Vocal Mode axes, experimental Unison fields, phoneset overrides, syllable timing, pronunciation, and per-phoneme timing or strength.
Pitch and expression Adjust pitch transitions and pitch curves; manage Smart Pitch controls and AI Retakes; apply scoop, falloff, vibrato, crescendo, or breathiness presets.
Automation Read, add, replace, sample, simplify, or clear pitch deviation, loudness, tension, breathiness, voicing, gender, and Vocal Mode curves.
Tracks, Groups, and harmony Create, clone, reuse, update, or delete library Groups, Group references, and tracks; create an empty host-cloned Vocal template track; and create range-constrained harmony tracks. Shared Group content writes fail closed unless all references are explicitly acknowledged.
Local score import Inspect an explicitly supplied local MusicXML (.xml, .musicxml, .mxl) or SMF MIDI (.mid, .midi) file, then import one rights-confirmed monophonic lane through the guarded note-write path. URLs and .svp files are not accepted.
Timing, editor, and playback Convert seconds, quarter notes, and blicks; edit tempo/time signatures; control selection, viewport, clipboard, grid snapping, coordinates, mixer, and playback.
Safe editing Protect writes with fresh fingerprints, typed/scope-bound contextId values, and Guard Tokens; fully preflight independent transaction steps, resolve forward dependencies just in time, create one SynthV undo record, and optionally retain a guarded rollback plan.
Connection and local privacy Monitor Bridge/MCP heartbeats and hot-reload an online Bridge from the optional native side panel. File IPC stays local: the Bridge does not parse .svp files, open a network port, or call an AI API.

To avoid reproducible SynthV 2.2.1 native crashes, the current stable surface rejects isolated Group clone, Note Group/Track/Track-shell clone, harmony Track, and transaction apply/rollback before project IPC. The table describes the full design surface, not current availability of those experimental paths. Linked Group-reference clone remains available.

Responsibility boundaries

The Bridge separates musical judgment from deterministic execution. The Agent decides why, where, and how much to change. The MCP and Lua layers execute that explicit decision compactly, safely, and against current SynthV state. SynthV stores the result, and the user makes the final listening decision.

Work Owner Reason
Understand user intent, lyric emotion, and singing style Agent Requires language and musical-semantic judgment
Decide which words to strengthen, soften, lengthen, or connect with pitch transitions Agent This is an artistic decision
Ask for the current Vocal and every Vocal Mode name Agent + user The official API cannot read Vocal identity or enumerate untouched default-only Vocal Modes
Decide whether to tune a short phrase or a larger scope Agent Depends on the goal, review cost, and token budget
Convert terms such as warm, restrained, or bright into explicit parameters Agent The Bridge must not interpret artistic language
Choose a fresh target scope and explicit numeric batch transform Agent Target selection and musical values belong to the current task
Choose a legal local score and confirm the right to import it Agent + user The Bridge cannot determine copyright or license authority
Provide current Group, note, Voice, and automation data Lua Bridge SynthV's live object model is authoritative
Cache and expand typed, scope-bound contextId and Guard data TypeScript MCP Avoids repeating large fingerprints while failing closed on incompatible scope
Inspect and convert an explicitly supplied local MusicXML/MIDI lane TypeScript MCP Keeps bounded local parsing outside SynthV without implying permission to use the file
Project compact reads and minimal write acknowledgements TypeScript MCP Keeps irrelevant host data out of the model context
Detect SynthV restart or Bridge reload TypeScript MCP Old Context and Guard data must be invalidated before another write
Validate request structure, routing, indices, and stable protocol ranges TypeScript MCP Rejects malformed work before file IPC
Read the current Automation definition.range Lua Bridge The range can vary with the host, voice, and parameter
Expand deterministic note transforms and other batch mechanics Lua Bridge Mechanical calculations should be centralized and reproducible
Validate fingerprints and the complete prepared batch Lua Bridge Prevents overwriting user edits or partially applying invalid work
Block accidental edits to multiply referenced Note Group content Lua Bridge Group content is shared even when references appear on different tracks
Create one undo record and verify host postconditions Lua Bridge + SynthV Provides one recovery boundary and avoids false success
Save, audition, undo, and approve the final result User + SynthV The user is the final artistic authority

See the detailed Agent / MCP responsibility boundaries for the enforced layer rules and batch-operation admission criteria.

First MCP connection: user notice

On the first project-changing use in a conversation, the Agent must briefly tell the user:

  • An optional guided Demo is available. Reply Run the Twinkle Star demo. to create and tune an isolated example without changing existing material. The Agent prints five short progress headings and pauses once for Vocal/Vocal Mode onboarding because of the official API limitation.
  • Save important work before AI editing and avoid changing the same target while a Bridge write is running.
  • After undoing or manually editing the notes, Group, Voice, or Vocal Modes that the Agent is about to change, the Agent will compactly reread only that target. Unrelated edits do not require a reread.
  • SynthV's scripting API does not expose the current singer identity or enumerate untouched default-only Vocal Mode names and parameters. Only when a request uses or changes Vocal Modes, the Agent asks the user to select the intended Note Group and Vocal, then provide every exact singing style or a screenshot of the complete Vocal Mode panel. Explicit mechanical edits that do not depend on singing styles do not require this handoff. After the Vocal changes, the styles must be provided again before another Vocal-Mode-dependent write.
  • The Agent does not display a fixed How to use section or preflight checklist. It asks only for missing user-owned decisions, suggests saving a working copy once, and shows a small preview before writing. Fresh reads, guards, preflight, and verification stay internal. Undo guidance appears only when an actual result reports undoRequired: true.
  • Users may request token-saving mode. For an ordinary command that returns verified: true, the Agent then skips its extra independent post-write query. The fresh target read and all Bridge-side validation and host postcondition checks remain enabled; required recovery, dependent-step, UI-state, and Demo reads are not skipped.

When Vocal Mode information is needed, a concise prompt from the user is sufficient:

Current singer Vocal Modes: Airy, Bright, Cool, Dark, Emotional, Power, Solid,
Sweet.

Alternatively, attach a screenshot that clearly shows the complete Vocal Mode panel.

Architecture

Codex / Claude Code / another local stdio MCP host
                    │
                    │ MCP over stdio
                    ▼
         TypeScript MCP server
                    │
                    │ correlated JSON file IPC
                    ▼
       SynthVAgentBridge.lua (persistent)
                    │
                    │ SynthV scripting API
                    ▼
       Open Synthesizer V Studio project

File IPC is deliberately used for the first version because it works within SynthV's documented Lua environment and is easy to inspect and recover. See docs/architecture.md.

Local score inspection is the bounded exception to the Node server's project-data pass-through role: it reads only an explicitly supplied absolute MusicXML/MIDI path. Inspection stays in Node; an approved import sends converted notes through the same guarded Lua add_notes path. It never parses .svp.

Requirements

  • Synthesizer V Studio 2 Pro 2.1.2 or later.
  • Node.js 20.10 or later.
  • An MCP host that supports local stdio servers. Codex and Claude Code have maintained project profiles in this repository.

This project targets the scripting environment in Synthesizer V Studio 2 Pro; it does not target the Basic edition.

Installation

New users can follow the end-to-end Quickstart or 中文快速开始. It covers cloning the repository, Node.js setup, script installation, host-specific MCP registration, and connection verification. Agent skills and guided musical workflows are installed separately from SynthVCopilot/SKILLS.

1. Build the MCP server

git clone https://github.com/SynthVCopilot/synthv-agent-bridge.git
cd synthv-agent-bridge
npm install
npm run build

2. Install the SynthV scripts

In Synthesizer V Studio, use Scripts → Open Scripts Folder, then pass that directory to the installer:

npm run install:synthv -- --target "/path/to/Synthesizer V Studio 2/scripts"

The installer copies these files into a SynthV Agent Bridge subfolder of the directory you selected:

  • SynthVAgentBridge.lua
  • StopSynthVAgentBridge.lua
  • SynthVAgentSidebar.lua (optional)

Alternatively, set SYNTHV_SCRIPTS_DIR to the scripts directory before running npm run install:synthv. The installer creates a SynthV Agent Bridge subfolder. When the side-panel file changes, close and reopen SynthV so it reloads SynthV Agent as a custom side-panel section. Scripts → Rescan may leave an already-rendered panel layout unchanged. After reopening, run Start SynthV Agent Bridge once.

The Bridge and every ordinary MCP read/write tool work without the side panel. For a core-only installation, add --without-sidebar; this skips the optional panel without deleting an existing installation:

npm run install:synthv -- --target "/path/to/scripts" --without-sidebar

If a hot-reload-capable Bridge session is already running, the installer asks it to load the copied Lua file and waits for a new session heartbeat. This uses the Bridge's file IPC and Lua loadfile()—not UI automation or hooks. Use --no-reload to copy without requesting a reload. The first installation of a hot-reload-capable version must still be started manually once. A changed side-panel layout requires closing and reopening SynthV, so the Bridge also needs one manual start afterward. SynthV may reuse cached menu-script code after a project or app restart, so when the Bridge runtime itself changed, the installer also asks for one Scripts → Rescan before the next manual start. Hot reload keeps the current session usable until then.

3. Start the in-editor bridge

In Synthesizer V Studio, run:

Scripts → SynthV Agent Bridge → Start SynthV Agent Bridge

The script remains active and writes a heartbeat while SynthV is running. To stop only the Bridge, run Stop SynthV Agent Bridge; the side panel remains alive and shows B offline. SynthV's Abort All Running Scripts also stops the side panel itself, so the already-rendered panel freezes and neither its status nor its buttons can update. Reopen SynthV afterward to restore it.

4. Connect an MCP host

Both maintained adapters launch the same node dist/src/cli.js Runtime and keep registration scoped to this project:

Other local MCP hosts can use the same command when they support STDIO servers. No installer or Doctor command writes user-global host configuration.

Optional native connection panel

The side panel shows Bridge (B) and MCP (M) connection states on separate rows plus Restart Bridge. It does not collect instructions, preview changes, or apply edits. B becomes online only after the panel observes a new heartbeat, and Restart Bridge waits for a replacement Session. A permanent warning explains that Abort All Running Scripts freezes the displayed states; use the dedicated Stop command when only the Bridge should stop. Start an offline Bridge from the Scripts menu. See docs/sidebar.md.

5. Verify the connection

Open an MCP-enabled conversation and ask it to call sv_status, followed by sv_query with action: "get_project_info" and contextMode: "readOnly". A healthy status contains:

{
  "connected": true,
  "fresh": true
}

MCP v3 tools

The public MCP surface exposes six stable tools. Individual SynthV actions and their full schemas are returned just in time by sv_describe, rather than placing every action schema in the model context.

Tool Purpose
sv_status Read connection, Session, capability, trace, and component-build status.
sv_describe List actions or return one compact Query/Command/UI/Review schema.
sv_query Run a read projection and create a readOnly or writeIntent Context.
sv_command Run validated edit, delete, clone, import, or bounded batch commands.
sv_ui Control selection, viewport, clipboard, dialogs, snapping, coordinates, or playback.
sv_review Read optional Sidebar connection and runtime status.

The normal tuning sequence is:

  1. Call sv_describe for unfamiliar actions.
  2. Read current state with sv_query; use contextMode: "writeIntent" before a project command.
  3. Reuse the returned contextId in one sv_command.
  4. Query again after an unknown Context, Session change, or any STALE_* result.

contextId stores only locators and concurrency guards in bounded Node memory. Each handle is bound to a target kind and source scope. Reusing it with an incompatible action, or combining it with a conflicting explicit locator or guard, fails closed instead of silently retargeting the call. Locator-only readOnly Contexts do not authorize writes. A writeIntent Context is minted only from a fresh host read. SynthV still checks every complete private fingerprint before creating an Undo record.

Phrase reads accept an include projection over notes, voice, automation, analysis, recommendations, pitchAnalysis, selection, and diagnostics. The v3 default is notes, voice, and analysis. Results with at least 24 notes use a column/row representation when dense: "auto"; use dense: "never" for ordinary objects. V3 note rows omit derivable absolute end positions and report noteDefaults.absolutePitch: "pitch" when equal absolute/local pitches were omitted.

Collection reads are bounded by default and return page/continuation metadata. This includes Tracks, library Groups, time-axis marks, Track Groups/notes, computed performance data, and Smart Pitch controls. Automation defaults to a compact full-curve summary and returns point arrays only for an explicitly requested closed range. An unscoped default Query above the 20,000-character response budget fails with narrowing guidance instead of flooding the Agent context.

Action catalog

These actions are routed internally through the six MCP v3 tools. They are not registered as standalone MCP tools; request their current schemas through sv_describe only when needed.

Action Access Purpose
bridge_status Read Read the heartbeat without requiring a round trip.
sidebar_status Read Read the MCP heartbeat and optional native side-panel runtime status.
ping Read Test the complete Node → Lua → Node path.
reload_bridge Control Reload the installed Lua Bridge in the current script session.
get_host_info Read SynthV host version, OS, language, project, and IPC information.
host_clipboard Control Read or write text through SynthV's host clipboard API.
show_dialog Control Show message, input, confirmation, or custom-form dialogs.
convert_pitch Read Convert MIDI pitch and frequency and identify black keys.
get_project_info Read Project, timing, playback, host, and current editor location.
inspect_score_file Read Inspect an explicitly supplied local MusicXML or SMF MIDI file in Node, return a SHA-256 file guard and selectable parts/voices/staves or tracks/channels, and preview a bounded monophonic lane without changing SynthV.
get_time_axis Read Bounded, independently paged tempo/time-signature marks; private full-state guards are captured behind Contexts.
convert_time Read Convert seconds, quarter notes, or blicks through the current tempo map, with optional Blick-grid rounding.
set_time_axis Destructive Add, replace, or remove tempo/time-signature marks.
list_tracks Read A bounded page of Track summaries, Group/note counts, and mixer state.
list_note_groups Read A bounded page of reusable library Group summaries and reference counts; private identities and guards remain Context-backed.
create_note_group Write Create an optionally populated reusable library group.
clone_note_group Write Deep-clone a track or library group into the library.
delete_note_group Destructive Delete a library group and all references to it.
add_group_reference Write Place a library group on a track.
clone_group_reference Write Make a linked or deep-copied reference on another track.
get_track_notes Read Independently bounded Group and note pages with attributes and offsets; private Group/note guards remain Context-backed.
get_group_voice Read Typed group voice defaults, Vocal Modes, experimental Unison fields, and target selection context.
get_note_phoneme_data Read User/computed phonemes, phoneset overrides, per-phoneme attributes, and note selection state, with optional compact note-index or seconds-range filtering.
get_phrase_context Read One compact, write-ready selected/ranged phrase read with note and automation Guard Tokens, voice/Vocal Modes, diagnostics, and recommendation-only review targets.
get_selection Read Selected groups, notes, Smart Pitch controls, and requested automation points.
set_selection Control Replace, add, remove, or clear editor selections and return the selection actually reported by SynthV.
get_computed_group_data Read Computed phonemes/rap attributes and optional pitch samples.
add_track Write Create a track and return its main Group locator.
update_track Write Rename, recolor, or change Render Panel inclusion.
clone_track Write Host-clone a track's main Vocal context with optional clear/transpose. A source containing non-main vocal Groups is rejected by default; nonMainGroupPolicy=detach makes their Group content independent, but their non-main Vocal identities must be reviewed manually.
clone_track_shell Write Host-clone the source track's main Vocal context into one verified-empty track, removing notes, pitch controls, known automation, non-main Groups, and—by default—mixer state. The API cannot read or name the inherited Vocal identity.
delete_track Destructive Delete a fingerprint-verified non-final track.
update_group Write Change vocal/instrumental reference state and supported vocal properties.
set_group_voice Write Fingerprint-verified typed voice, Vocal Mode, and host-validated experimental Unison updates, with an optional current-Group guard.
apply_group_tuning Destructive Prevalidate and apply one same-Group Voice/Vocal Mode, note/phoneme, and multi-automation tuning pass in one undo record. Unexpected execution failures explicitly require one SynthV Undo before retrying.
delete_group_reference Destructive Remove a non-main vocal or instrumental reference.
import_monophonic_score Write Import at most 512 notes from one freshly inspected, rights-confirmed local MusicXML/MIDI lane through guarded add_notes; the SHA-256 guard must match and source tempo is reported but not applied.
add_notes Write Add notes to a target group. V2 defaults to grouping=ensureNonMain, creating a reusable non-main group/reference when the target is the track main group; use grouping=target to write to the exact group.
edit_notes Write Edit fingerprint-verified notes.
transform_notes Destructive Apply one explicit guarded batch offset/scale to note onset, duration, or pitch. V2 can transform every note in a fresh Context without repeating indices.
set_note_phoneme_properties Write Edit fingerprint/Guard-verified phoneme, phoneset, syllable, timing, and strength properties, with optional compact acknowledgement and current-Group/selected-note guards.
delete_notes Destructive Delete fingerprint-verified notes.
get_note_retakes Read Read take count and Bridge-tracked Take IDs.
generate_note_retake Write Generate duration, pitch, or timbre variations.
activate_note_retake Write Activate the default or a Bridge-tracked Take.
delete_note_retake Destructive Delete a Bridge-tracked non-default Take.
get_pitch_controls Read Read point and curve Smart Pitch objects and fingerprints.
add_pitch_controls Write Add point or curve Smart Pitch objects.
edit_pitch_controls Write Edit fingerprint-verified Smart Pitch objects.
delete_pitch_controls Destructive Delete fingerprint-verified Smart Pitch objects.
get_automation Read Read a parameter definition and control points, optionally returning a compact Guard Token instead of the verbose curve fingerprint.
sample_automation Read Sample native or linear curve values at requested positions.
simplify_automation Destructive Remove insignificant points in a curve range.
set_automation_points Write Add/update fingerprint/Guard-verified points, optionally clearing all or a range first and returning a compact acknowledgement.
clear_automation Destructive Clear a complete curve or a selected range.
get_editor_view Read Read editor time/value ranges and pixel scales.
set_editor_view Control Move or scale the main-editor or arrangement viewport and return the host's resulting navigation state.
snap_position Read Snap a position using current editor grid settings.
convert_editor_coordinates Read Convert time/value and x/y editor coordinates.
script_data Read/Write Manage namespaced Bridge JSON metadata on SynthV objects.
get_track_mixer Read Read gain, pan, mute, and solo.
set_track_mixer Write Change gain, pan, mute, and solo.
apply_transaction Destructive Apply up to 32 writes in one undo record. Independent steps are fully preflighted; later steps may consume earlier results with $result and are preflighted just in time. This is a single-Undo recovery boundary, not automatic rollback.
rollback_transaction Destructive Apply the stored guarded reverse steps for a transaction in one new undo record.
create_harmony_track Write Clone a guarded vocal track, transpose it, octave-fit an optional voice range, and set its mixer.
humanize_notes Destructive Apply deterministic fingerprint-guarded onset/duration variation, optionally preserving chord alignment.
apply_expression_preset Destructive Apply scoop, falloff, vibrato, crescendo, or breathiness through note attributes or automation.
fit_lyrics Destructive Assign syllables and optional phonemes to fingerprint-verified notes.
playback Control Read status, play, pause, stop, seek, or loop, then return the host's observed status and playhead.

All track, group, and note indices are 1-based, matching the SynthV Lua API. Note and automation coordinates are group-local blicks unless the returned field explicitly says absolute. Playback positions are seconds.

Compact tuning responses

get_note_phoneme_data, get_automation, and sample_automation accept responseMode: "compact". Full mode remains the default.

  • get_track_notes compacts its nested groups[].notes on the sv_query projection path. Blick and quarter duplicates of the same position (absoluteOnset, absoluteEnd, absoluteEndSeconds, endPosition, onsetQuarters, durationQuarters) are dropped in favor of group-local onset/duration plus absoluteOnsetSeconds/absoluteDurationSeconds, and a group of 24 or more notes is returned as {columns, rows} with noteFormat: "rows". Note guards are captured before projection, so contextId stays valid.

  • sv_query.fields filters top-level keys of the result root only. Nested collections such as groups[].notes are not column-filtered; asking for note field names returns just the envelope plus a projectionWarning listing the root keys that were actually available.

  • Prefer get_phrase_context before phrase tuning. It can locate the current piano-roll Group without a prior selection call, prefers selected notes when no explicit scope is supplied, and combines compact pitch/timing/phoneme notes, Group voice/Vocal Modes, and bounded automation summaries in one request. Nested note and automation fingerprints become short Guard Tokens.

  • Phrase diagnostics identify timing overlaps, large pitch transitions, sustained notes, breath-sized gaps, and dense short notes without editing the project. pitchAnalysisFrames optionally summarizes the computed contour without returning raw frames.

  • Phrase-note seconds are rounded to 0.1 ms. Empty/default phoneme overrides, zero detune, and false selection flags are omitted; non-default values remain, and the response reports noteDefaultsOmitted plus secondsPrecision.

  • Absolute ranges default to rangeMatch: "overlap", which preserves a long note crossing the range start. Use rangeMatch: "onset" only when onset-only coverage is acceptable; it binary-seeks into the sorted Group and reports coverage: "onset_only" plus mayExcludeEarlierSustains: true.

  • Unscoped phrase pages return an opaque page.cursorToken when more notes remain. Pass it back as cursorToken instead of repeating the Group locator and numeric offset. The server rejects an expired token, and SynthV rejects it with STALE_RANGE_CURSOR if the boundary note changed.

  • get_phrase_context.ranges accepts up to 32 absolute ranges. The executor sweeps the Group once, serializes each unique matched note once, and returns one shared notes array; each range references it through noteIndices and has its own diagnostics, automation summaries, and optional pitch summary.

  • Phoneme reads can filter by exact noteIndices and/or an overlapping absolute startSeconds/endSeconds range. Compact notes include timing, lyrics, computed phonemes, user overrides, and a short guardToken; large raw and computed attribute objects are omitted unless explicitly requested.

  • Exact-index and ordinary paginated reads only fetch the returned note page. Time ranges convert their two boundaries once and stop scanning after the first later note. Set includeComputedPhonemes: false when only refreshing Guard Tokens or user overrides, avoiding the whole-Group host computation.

  • Pass a note guardToken to set_note_phoneme_properties instead of its verbose fingerprint.

  • Compact automation reads return guardToken; pass it as expectedGuardToken to set_automation_points.

  • These Guard Tokens also work inside apply_transaction steps; they are resolved before the request reaches file IPC.

  • Compact write responses contain counts and replacement Guard Tokens instead of complete notes or automation curves.

Guard Tokens are opaque and live only in the current MCP server process. MCP v3 automatically detects a changed SynthV/Bridge session token and clears every cached context and Guard Token. A write then returns SYNTHV_SESSION_CHANGED; read the target again and build the write from its fresh context. A fresh read can proceed immediately and reports sessionReset. Eviction or UNKNOWN_GUARD_TOKEN likewise requires a reread. An MCP-requested hot reload waits for the new session token and clears these caches before sv_status returns, closing the reload acknowledgement race. The server resolves each token to the original complete fingerprint before the request reaches SynthV, so existing stale-write protection is unchanged.

Phoneme writes are verified on a detached clone before an undo record is created, then verified again on the project note. A host or older Voice that quantizes or ignores a requested value fails with HOST_POSTCONDITION_FAILED. Stable phoneme ranges are validated directly: position/activity 0..1, strength -1..1, and finite-second leftOffset without a Bridge-imposed bound. No startup or first-use range probe is needed.

Track colors

Track write tools accept the backward-compatible #RRGGBB form or a native AARRGGBB value. The bridge converts #RRGGBB to opaque ffRRGGBB before calling SynthV and verifies the value retained by the host. Track reads preserve SynthV's raw displayColor and also return normalized displayColorArgb and displayColorRgb fields when the host value is recognizable.

SynthV's editor offers a small preset palette, but the public scripting API only defines the value as a hexadecimal string. The bridge therefore validates the encoding without restricting callers to undocumented palette constants.

Host capability differences

Some SynthV hosts expose Note:getPitchAutoMode() but fail to expose or execute Note:setPitchAutoMode(). If a requested value already matches the note, the bridge safely skips the setter. A real mode change on an incompatible host fails with UNSUPPORTED_HOST_CAPABILITY before an undo record is created.

Time-axis replacement is performed as remove-then-add at occupied positions. Every successful set_time_axis response has verified: true; a host that does not retain the requested marks returns HOST_POSTCONDITION_FAILED instead of a false success.

Safe editing workflow

Any Agent host performing a guarded write should use this sequence:

  1. For phrase tuning, call get_phrase_context immediately before editing. For Group Voice or Vocal Modes, call get_group_voice with no locator to target the current piano-roll Group. V2 returns only the parameters, Vocal Modes, target indices, and contextId by default; request full fields only for diagnostics. For other work, read only the object that owns the intended change.
  2. Present or internally construct a small, reviewable change.
  3. Reuse the contextId from that read with contextMode: "writeIntent". The Runtime fills the group/reference UUIDs and fingerprints, track fingerprint, automation/time-axis fingerprint, and note or Smart Pitch guards from that Context, so a note edit needs only noteIndex and its changes. Copy guards by hand only when writing without a contextId; a copied value that disagrees with the Context fails with CONTEXT_SCOPE_MISMATCH.
  4. Call the smallest write tool that completes the intended change. Group content writes reject a multiply referenced Note Group by default. Use sharedGroupPolicy=allowAllReferences only when changing every linked occurrence is intentional, and pair it with the fresh expectedReferenceCount. Prefer apply_group_tuning when one pass changes Voice/Vocal Modes, notes/phonemes, or multiple automation curves in the same Group. Use apply_transaction for a bounded multi-object batch; independent steps are preflighted before writing, while a step that uses an earlier $result is necessarily checked just before that dependent step executes.
  5. If SynthV reports any STALE_* error, read again rather than guessing.

One compact read should feed one complete batch of related changes. Do not refresh contextId by reading the whole selection or song when only Group Voice changed.

Large edits stay batched rather than maximal. edit_notes and delete_notes accept up to 512 items per call, but that ceiling is a protocol bound: SynthV 2.2.1 is fragile with large note batches, so keep each call at or below roughly 60 items.

One writeIntent contextId can serve several of those batches. A Context guards each note individually, so a batch succeeds while every note it targets still matches the fingerprint that read captured. Read one page that covers all target notes, then send disjoint batches from that single contextId.

Read again when a guard can no longer be fresh:

  • a note the Context already changed is rejected with STALE_NOTE and retry: query_again, so re-touching a note needs a new read;
  • add_notes or delete_notes shifts the indices after the edited position, and every shifted note fails STALE_NOTE against the older Context.

Both cases fail before any write, so an over-optimistic reuse costs a rejected call rather than a wrong edit.

A note fingerprint includes the group UUID, note index, onset, duration, pitch, detune, lyrics, phonemes, language, musical type, pitch mode, rap accent, retake count, and note attributes. This prevents an agent from applying an old plan to a note that the user has already changed.

Example requests

Read the notes currently selected in SynthV. Show the planned change, then extend
only the final note by half a quarter note. Use the fingerprints from the latest read.
Read the current group's loudness automation. Add a gentle 3 dB crescendo across
the selected phrase without deleting points outside that phrase.
Read track 1 and create a new harmony track a minor third below the selected notes.
Do not apply anything until you have listed the resulting pitches and warned about
notes outside MIDI 0–127.
Read track 1, then clone it as "Harmony -3st" with transposeSemitones -3.
Use the latest track fingerprint. If it has non-main vocal Groups, stop unless
I explicitly approve detaching their content and reviewing their Vocals.
Inspect D:\scores\melody.musicxml without editing SynthV. Show the selectable
part/voice/staff, overlap status, SHA-256 guard, and note preview. Import one
chosen monophonic lane only after I confirm that I have the right to use it.

More examples are in examples/prompts.md.

Configuration

The Node server and SynthV script must resolve the same physical IPC directory.

Variable Default Meaning
SYNTHV_AGENT_BRIDGE_DIR OS temporary directory Shared IPC directory.
SYNTHV_AGENT_BRIDGE_TIMEOUT_MS 30000 Maximum response wait. The default leaves room for a cold SynthV host answering its first request.
SYNTHV_AGENT_BRIDGE_POLL_MS 10 Node response polling interval.
SYNTHV_AGENT_BRIDGE_LOCK_WAIT_MS 1000 How long a client waits for the single-writer lock before reporting BRIDGE_BUSY. Clamped to the response timeout.
SYNTHV_AGENT_BRIDGE_STALE_REQUEST_MS 60000 Age at which abandoned request files and locks can be recovered. Must be greater than the response timeout.
SYNTHV_AGENT_BRIDGE_STATUS_STALE_MS 5000 Maximum heartbeat age considered connected.

When a custom IPC directory is used, create it before starting the SynthV script. The Node process also creates the directory, but the documented startup order starts SynthV first.

Windows and WSL

The simplest setup is to run the MCP server with Windows Node.js when SynthV runs on Windows. When the MCP host runs inside WSL, point Node at the existing Windows temporary directory that SynthV uses by default:

  • SynthV/Windows: leave SYNTHV_AGENT_BRIDGE_DIR unset so the script uses %TEMP%.
  • Node/WSL: set SYNTHV_AGENT_BRIDGE_DIR=/mnt/c/Users/you/AppData/Local/Temp.

For a dedicated subdirectory, create it first and set equivalent Windows and WSL path spellings for the two processes. The SynthV GUI must inherit its Windows environment variable, so restart SynthV after changing it. The MCP server can receive its own value through the host project's MCP environment configuration.

Development

npm run typecheck
npm test
npm run check
npm run inspector

Lua syntax can be checked with:

luac5.4 -p synthv/SynthVAgentBridge.lua synthv/StopSynthVAgentBridge.lua synthv/SynthVAgentSidebar.lua

CI runs TypeScript tests on Node 20 and 22, parses all three production Lua files with Lua 5.4, and exercises both the persistent Bridge and side panel through mock SynthV integration harnesses.

For a local installation and connection report, run:

npm run doctor -- --target "/path/to/Synthesizer V Studio 2/scripts"

The default Doctor checks only host-neutral Runtime state: source/installed versions and exact script contents, compiled MCP freshness, running capability fingerprints, Bridge/MCP heartbeats, the resolved IPC directory, and residual processing/control files. Add --host profiles to discover and validate every project profile in the repository; add --json for machine-readable output. Doctor never reads or writes user-global host settings, the SynthV project, or installed files.

Current limitations

  • One request may be in flight at a time. A second client waits up to SYNTHV_AGENT_BRIDGE_LOCK_WAIT_MS (1 s by default) for the single-writer lock and then reports BRIDGE_BUSY. Sustained parallel driving of the bridge from two hosts is still unsupported.
  • A client-side timeout is ambiguous: SynthV may still finish the operation. The processing marker remains until the Lua host completes, and the agent should read the current project before deciding whether to retry a write.
  • The current build classifies isolated Group clone, Note Group/Track/ Track-shell clone, harmony Track, and transaction apply/rollback as experimental and rejects them before project IPC. Linked Group-reference clone remains available.
  • The generic transaction schema and Fake Host implementation remain for diagnosis: they reject conflicting guarded scopes, support complete-field $result references, and perform full/just-in-time preflight for independent and dependent steps. Public transaction apply/rollback is not runnable in the current build.
  • atomicity: "singleUndoRecord" means one SynthV recovery boundary, not automatic rollback. An independent preflight failure makes no project changes. A dependent validation or unexpected host failure can occur after earlier steps have written; when the error reports undoRequired, immediately use Edit > Undo once before rereading or retrying.
  • Rollback-plan design remains project/Session-bound; current rollback_transaction is experimental-disabled together with apply.
  • The optional side panel is connection-only. Requests, review, and Undo guidance remain in the Agent conversation and SynthV editor.
  • SynthV's public scripting API does not expose project save, audio rendering, selecting an installed singer database by display name, reading Vocal identity, or Voice Panel scale/mode settings. The clone_track_shell schema describes host-cloned main-Vocal inheritance, but the current host-clone path is disabled after native crashes and still cannot name that Vocal.
  • Local score support is intentionally import-only and bounded. It accepts absolute local .xml, .musicxml, .mxl, .mid, or .midi paths after explicit inspection and rights confirmation. It rejects URLs, .svp, XML DOCTYPE/ENTITY, ambiguous/polyphonic lanes, changed file hashes, and imports above 512 notes. Source tempo is returned for review but is not silently applied to the project.
  • singers and spacing are returned by SynthV 2.2.1 but are not documented in the public getVoice field list. The typed Unison surface is therefore experimental and refuses writes unless the host returns and retains the requested fields on a cloned reference.
  • The Retake API does not enumerate Take IDs or expose the active Take ID. The bridge therefore activates and deletes only the default Take or IDs it generated and stored itself.
  • Expression presets are intentionally small building blocks, not phrase analysis or pronunciation-quality scoring.
  • The bridge has not yet been validated against every SynthV 2.x patch and every voice database.
  • A chat surface must be able to launch a trusted local stdio process to connect directly. Remote access would require a separate authenticated transport adapter.

See docs/roadmap.md.

Security and privacy

This is a local control bridge. It does not upload project data. However, any connected MCP host can receive project metadata and can request edits, so connect only trusted clients and review destructive tool calls. See SECURITY.md.

Acknowledgements

The architecture was inspired by Haruki Okada's proof-of-concept ocadaruma/mcp-svstudio, which demonstrated that a local MCP server and a persistent SynthV Lua script can communicate through files. This repository reimplements the bridge around request correlation, validation, stale-context protection, undo records, cross-platform paths, tests, and a broader tool surface.

Synthesizer V and Synthesizer V Studio are products and trademarks of Dreamtonics. This independent project is not affiliated with or endorsed by Dreamtonics.

License

Apache License 2.0. See LICENSE.

About

No description, website, or topics provided.

Resources

Contributing

Security policy

Stars

67 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages