Skip to main content
Glama
lhai-mcp
by ppzbr

lh-synthv-mcp

Give a program — not a person — control of the already open project in Synthesizer V Studio: read its tracks, add and edit notes, set lyrics, pitch, phonemes and timing, and run the transport. Nothing is clicked or typed to make that happen.

Synthesizer V is the one editor here that ships a scripting API: the host loads .lua files and hands them the SV, Project and Editor objects. So the in-editor half of this bridge is a resident Lua agent the editor itself loads — no DLL, no injection, no memory reading, no UI automation, no vendor patch.

Lua has no sockets. The agent therefore talks to Python through folders: it polls a command folder and answers into a result folder. The MCP server is the Python side (lhai-mcp), which turns those folder round-trips into typed tools.

 MCP client  <-->  lhai-mcp (Python)  <-->  folder IPC  <-->  LHai Agent (Lua, in the editor)

Requirements

  • Windows.

  • Synthesizer V Studio 1.x and/or 2.x. Both are supported; they are separate products with separate script folders, separate Lua hosts and separate processes, and the installer writes into every generation it finds.

  • Python 3.10+.

The client is stdlib at import time. The only installed dependencies are the mcp transport and comtypes.

Related MCP server: SV1 Agent Bridge

Install

git clone https://github.com/ppzbr/lh-synthv-mcp
cd lh-synthv-mcp
python -m pip install -e ".[mcp]"

Then, from an MCP client (or in plain Python — from lhai.live import synthv_live; every foo() below is synthv_live.foo()):

synthv_live_status()      # read this first
synthv_live_install()     # writes the agent into every generation found

One click is not automatable, and asking for it is not a workaround. A SynthV script has no programmatic entry point: the host runs one only from its Scripts menu. So ask the human to start it — Scripts → Start Script → LHai Agent — once per generation per install. Everything after that click is programmatic.

synthv_live_status()      # the agent now answers
synthv_live_version()     # host identity, generation, editor version
synthv_live_probe()       # which API calls this build answers, and how they were found

The agent is idempotent: a second start replaces the previous instance itself. Five measured starts produced five # agent started lines and one live agent.

Driving it

synthv_live_state(group=1)                  # what the open project holds
synthv_live_cmd(["VERSION", "TRACKS"])      # a batch of verbs, applied in order
synthv_live_cmd([...], edition="sv1")       # pick a generation when both are open
synthv_live_push(project="song.svp")        # push a project file's track into the editor

synthv_live_cmd takes a list of verbs — the agent's own command language:

verb

does

VERSION, PROBE

identity, and which host calls this build answers

TRACKS, TRACKSEL

list tracks / select one (TRACKSEL is handed the editor's own object, not an index)

GROUP

group operations

NOTE, LYRIC, PITCH, PHONEME, TIMESHIFT, DEL

note-level editing

STATE

read the current track back

CLEAR

clear the current track

SEEK, PLAY, STOP

transport

UNDO, REDO, SAVE

absent from the vendor API — see below

What is verified, and what is not

  • Synthesizer V Studio 2 — live-verified end to end: the agent loaded by the editor, commands round-tripped, notes edited in the open project. Everything in the tables above is measured, not inferred.

  • Synthesizer V Studio 1.x — the hard part was finding the script folder, and that is root-caused: HKCU\Software\Dreamtonics\Synthesizer V Studio\DataLocation is routinely stale (on the development machine it pointed at a folder nothing had written to in a month). The status tool therefore weighs every candidate and picks the one holding the newest content; editions[].roots shows all of them, best first. SV1 was not driven end to end in that session, so treat SV1 as installable and instrumented, not proven.

  • UNDO / REDO / SAVE are not in the vendor's Lua API. They are not omitted here by laziness; there is no call to make. The agent refuses them rather than pretending.

Traps this repository already handles

  • Lua indexes from 1. Converted in one helper, so the Python side can keep thinking in the editor's own numbering.

  • There is no newUndoBlock. It is Project.newUndoRecord().

  • Each generation gets its own folder (ipc/sv1, ipc/sv2), so two running editors cannot claim the same batch and apply it twice. A batch file is removed as it is read.

When something looks wrong

symptom

cause

the menu has no LHai Agent

the folder written to is not the folder the editor scans — compare editions[].root with what the editor's own Scripts menu lists, and read roots

every built-in appears twice in the menu

the script folder contains a nested copy; the scan is recursive — remove the duplicate, do not assume two installs

installed, but never answers

the editor was already running when it was installed: rescan or restart

answers with old behaviour

a stale agent from an earlier build is still running: Stop all running scripts, then start again

Layout

path

what

prompt.md

the paste-ready brief: the whole install-and-drive story for an agent that has never seen this repository

lhai/live/

the client: synthv_live.py, the Lua template synthv_lua.py, the folder IPC, and the shared live layer

lhai/mcp/

the MCP server that exposes the above as tools

docs/mcp-engine-bridge.md

the contract every bridge in this family follows: transport, tool vocabulary, diagnostics

docs/live-control.md, docs/mcp-singing.md

the live layer and the singing-model background

tests/

test_synthv_lua_host.py runs the Lua generation against a host stub; the rest is the client's own suite

MANIFEST.txt

sha256 of every tracked file; python tools/make-manifest.py --check re-derives it

This repository also carries the client's adapters for the other editors in the family (lhai/mcp/engines/). They are inert here: nothing in them runs unless that editor is the target. The tree is shipped whole so that one client has one copy and one test suite, rather than a fork per engine.

Tests

python -m pip install -e .
python -m pytest

Licence

MIT. See LICENSE.

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    D
    maintenance
    Controls OpenUtau (vocal synthesis software) from Claude Desktop, enabling project creation, editing, and live note manipulation via a bridge plugin.
    1
    -
  • F
    license
    B
    quality
    C
    maintenance
    Enables LLM agents to manipulate Synthesizer V Studio 2 Pro projects, including notes, lyrics, phonemes, vocal attributes, parameters, and playback through the official Dreamtonics Scripting API.
    26
    -
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables local AI-assisted tuning of Synthesizer V Studio 2 Pro projects via natural language, providing tools for reading selections, previewing and applying parameter adjustments, recording and comparing audio, and managing sessions.
    1
    MIT