LhBridge
by ppzbr
README.md
# lh-vocaloid6-mcp
Get a program **inside** a running **VOCALOID 6**, holding its own object graph, so
it can read and (once calibrated) change the open song — with no clicking and no
typing.
VOCALOID 6 has no scripting API, and unlike CeVIO its engine is not a managed library
that can simply be referenced: the note model is native code inside the editor
process. So the bridge is a **DLL loaded into VOCALOID 6** which hosts an MCP server
*in-process* and publishes it on loopback HTTP. Not screen scraping, not keyboard, not
mouse.
One C++ source file builds two artifacts:
| artifact | purpose |
|---|---|
| `lhai_bridge.dll` | injected into VOCALOID 6; hosts MCP in-process |
| `lhai_bridge.exe` | the same server standalone, so the transport can be tested without injecting into anybody's editor |
The bridge is the same source as the VoiSona one, built with the VOCALOID 6 identity;
the tool prefix and the engine guard differ, nothing else.
## Read this before you plan anything
Two measured facts change what is worth attempting here. Both come from injecting the
bridge into a real VOCALOID 6 (`6.13.0.1`) and looking.
1. **VOCALOID 6's editor is WPF on .NET, not a native C++ editor.** Its host image is
only `0x3d000` bytes, and its windows are `HwndWrapper[VOCALOID6;;...]` — the
editor is a shell over managed assemblies.
2. **A note map is a chain of raw pointers read from a module base, and the GC moves
managed objects.** A chain that resolves today can go stale under you, and a stale
chain does not fail: it reads plausible garbage and writes it back.
**Therefore: do not start a note-map discovery pass on VOCALOID 6 until someone has
settled whether a stable chain exists at all.** VoiSona is JUCE and native and fits
that workflow as written; VOCALOID 6 does not, yet. `capabilities.notes` will read
`"none"` and that is the honest state, not a missing step.
## Requirements
* Windows, VOCALOID 6 installed, and the editor **running** before you attach.
* Python 3.10+.
* `ziglang` — the only toolchain the native bridge needs.
## Install
```powershell
git clone https://github.com/ppzbr/lh-vocaloid6-mcp
cd lh-vocaloid6-mcp
python -m pip install -e ".[mcp]"
python -m pip install comtypes
python -m pip install ziglang
```
Build the bridge:
```powershell
powershell -ExecutionPolicy Bypass -File bridges/native/build.ps1
```
It writes `lhai_bridge.build-info.txt` beside the artifacts. That record, not the
compiler, is the proof of what was built. If the build fails, stop and report the
compiler output.
## Prove the transport with no editor involved
Run `lhai_bridge.exe` and drive it over HTTP:
```
initialize -> serverInfo LhBridge, protocol 2024-11-05
tools/list -> the vocaloid_* surface
```
This step exists so that a later failure is known to be about *the host*, not about
the bridge.
## Attach, and know that it worked
```python
bridge_inject(engine="vocaloid6")
```
What a healthy injection looked like on the development machine (the shape matters,
not the counts):
```
host image in the module list 255 modules
scan "4D 5A" found at the image base
chain u16 at the image base 0x5A4D ("MZ")
read at the image base 4d5a90000300000004000000ffff0000
windows the editor's own HwndWrapper[...] windows
status level: partial, capabilities.notes: "none"
```
Then the surface:
```python
bridge_list() # every bridge answering right now, and its engine
bridge_status(engine="vocaloid6") # version, app baseline, per-capability levels
bridge_tools(engine="vocaloid6") # the tools with their real argument schemas
bridge_call(engine="vocaloid6", tool=..., arguments=...)
```
The engine-prefixed tools are the memory primitives — modules, windows, `scan`,
`read`, `write`, `chain`, `load_map`, `status`. `chain` resolves exactly as a map file
states it: `p = base; for each offset o: p = *(void**)p + o`, then read the typed value
at `p`.
The wrong-engine guard is deliberate: a VOCALOID 6 bridge rejects a `voisona_*` tool
name, and vice versa. That answer means you are talking to the wrong bridge.
## Detach
```python
bridge_eject(engine="vocaloid6")
```
**Always eject before rebuilding.** Windows will not overwrite a DLL loaded in a
running process.
## Rules this bridge lives by
1. Do not modify, replace or delete any VOCALOID 6 file.
2. Never kill the editor process.
3. Never substitute UI automation, keystrokes or clipboard for a bridge capability.
4. If a step fails, stop at that step and report exactly what happened.
## What is verified, and what is not
* **Verified:** the bridge loads into a real VOCALOID 6 (`6.13.0.1`), publishes its
endpoint, and answers the process, module, scan, read, chain and window primitives —
the MZ evidence above is from that run.
* **Not verified, and deliberately not attempted:** any note-level read or write. The
WPF/GC facts above are why. The bridge will tell you `capabilities.notes: "none"`.
* **The fallbacks that do work today:** the project-file route, and the UIA live layer.
## When something looks wrong
| symptom | cause |
|---|---|
| `bridge_inject` cannot find the process | VOCALOID 6 is not running, or it runs under a different name — check `live_status()` |
| the DLL will not overwrite | it is loaded in the process: `bridge_eject` first |
| the engine tools refuse a call | the wrong-engine guard: the tool prefix does not match the host |
| `capabilities.notes: "none"` and you expected edits | no note map exists for this editor; that is the state, not a bug |
## Layout
| path | what |
|---|---|
| `prompt.md` | the paste-ready brief: the whole install-and-drive story, including the two facts above |
| `bridges/native/lhai_bridge.cpp` | the bridge: one file, two artifacts |
| `bridges/native/build.ps1` | the build, and the build record it writes |
| `bridges/native/install.py` | injection without an MCP client (`python bridges/native/install.py vocaloid6`) |
| `lhai/live/` | the client: the injector, the live layer, the channels |
| `lhai/mcp/` | the MCP server, which is how an MCP client reaches `bridge_*` |
| `docs/mcp-engine-bridge.md` | the contract every bridge in this family follows |
| `tests/` | the client's suite, plus the repository's own consistency checks |
| `MANIFEST.txt` | sha256 of every tracked file; `python tools/make-manifest.py --check` re-derives it |
The client ships with adapters for the other editors in the family
(`lhai/mcp/engines/`). They are inert unless that editor is the target.
## Tests
```powershell
python -m pip install -e .
python -m pytest
```
## Licence
MIT. See `LICENSE`.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo recent community issues