zeros-mcp
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., "@zeros-mcpGo to cue 5 on playback 1"
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.
zeros-mcp
An MCP server for controlling Zero 88 lighting consoles running ZerOS over OSC. It exposes playbacks, cues, the grand master, blackout and user macros as MCP tools.
Implements the OSC surface documented in ZerOS & OSC ("Open Sound Control"), which requires ZerOS 7.14 or later — OSC did not exist before that release.
Zero 88 document OSC for FLX, FLX S24/S48 and ZerOS Server. The 7.14 release notes also list ORB, Solution, SCD and Leap Frog under products affected, and the OSC section carries no console qualifier — but the manual's variant filter does not include them, so treat OSC on those desks as unconfirmed and try it rather than assuming either way.
This drives real lights. Commands take effect immediately on whatever the console is connected to. Point it at a desk with nothing patched, or one that isn't in front of an audience, until you trust it.
The thing to understand first
ZerOS receives OSC. It never sends any. The console has a Receive Port Number and no transmit port; there is no feedback, no acknowledgement, and no way to read the desk's state from here. This is not a gap in this server — it is the shape of the protocol.
Two consequences run through everything below:
No queries about the console exist, or can. There is no
get_active_cue. The only reads areget_command_journal(what this server sent) andget_connection_health(whether the link looks alive). Both say so in their own output, so a model reading them cannot quietly promote "I sent 50%" into "the desk is at 50%".ok: truemeans the packet left this machine, nothing more. Over UDP that is all it can ever mean, because UDP happily accepts writes addressed to a switched-off console. Every success result carriesconfirmed_by_console: falsepermanently.
If you want the console to talk back, it can't. If you want to know whether it's there, set
ZEROS_TRANSPORT=tcp — see Transports.
Related MCP server: Eos MCP
How it works
One outbound path:
commands -> ZEROS_PORT (console's "Receive Port Number")
zeros-mcp ─────────────────────────────────────────────────────► ZerOS console
(nothing comes back, ever)ZerOS takes its arguments in the address path — /zeros/cue/go/1/5 fires cue 5 on
playback 1 — rather than as OSC arguments. Every message this server sends therefore has an
empty argument list, which also sidesteps the fact that Zero 88 never document which OSC type
tag the console expects. It does mean every tool argument is interpolated into an address, so
validating them is load-bearing: a / slipping through wouldn't error, it would fire a
different command.
zeros_mcp/
├── app.py FastMCP instance
├── server.py entry point: logging, mcp.run()
├── config.py ZerosConfig, validated from the environment
├── journal.py what this server sent - not console state
├── errors.py ZerosConfigError / ZerosValidationError / ZerosSendError
├── logging_setup.py stderr logging (stdout carries the MCP protocol)
├── osc/
│ ├── address.py validates anything interpolated into an OSC address
│ ├── slip.py RFC 1055 framing for the TCP transport
│ └── client.py ZerosClient - lazy socket, UDP or TCP, structured errors
└── tools/ one module per area of the consolePrerequisites
A ZerOS console running 7.14 or later
uv— no separate Python install or clone needed;uvfetches Python and the server itself.
Setup
1. Enable OSC on the console. Setup → Triggers → OSC:
Setting | Value |
OSC | Enabled |
Receive Port Number |
|
Protocol | UDP (or TCP (SLIP) — see below) |
Receive Port Number must match this server's ZEROS_PORT, and the protocol must match
ZEROS_TRANSPORT. There is no transmit side to configure, which removes the most common
setup failure on other consoles — and replaces it with a quieter one: because nothing is ever
returned, a wrong port over UDP looks exactly like a working setup from this end. Commands
report ok: true and the rig does nothing.
A console that is not set to DHCP ships on a static 192.168.1.10 / 255.255.255.0.
2. Add it to your MCP client.
For Claude Desktop, add this to claude_desktop_config.json
(Settings → Developer → Edit Config):
{
"mcpServers": {
"zeros": {
"command": "uvx",
"args": ["--from", "git+https://github.com/MaybeItsAdam/zeros-mcp", "zeros-mcp"],
"env": {
"ZEROS_IP": "192.168.1.10",
"ZEROS_PORT": "8830"
}
}
}
}uvx fetches and caches the server straight from GitHub on first launch — nothing to clone or
install by hand. Restart Claude Desktop after editing the config. Any MCP client that launches a
command works the same way; drop the command/args/env above into its config format.
To pin to a specific commit instead of tracking main, append @<commit-sha> to the repo URL.
The server also publishes a system_instructions prompt covering the no-feedback rule, the
macro escape hatch, and when to confirm before acting.
Configuration
All optional. Defaults suit a console on the same machine.
Variable | Default | Description |
|
| Console address. A desk on factory settings is |
|
| Match the console's Receive Port Number. |
|
|
|
|
|
|
Invalid values are rejected at startup with a message naming the variable. Note there is one port here, not the TX/RX pair an Eos-style server needs — inventing a second would misdescribe the protocol.
Transports
UDP is the default and matches ZerOS's own default. It is fire-and-forget: nothing can be learned about the console from it at all.
TCP (SLIP) carries the same messages under RFC 1055
framing. It is worth choosing for one reason: a TCP connection either establishes or it does
not, which is the only evidence of the console's existence available anywhere in this
protocol. With it, get_connection_health can distinguish "something is listening on that
address" from "the packet left this machine". Without it, that question is unanswerable.
The TCP path is written from Zero 88's documented "TCP (SLIP)" option and is covered by tests against a local listener, but it has not been verified against a real console. UDP is the tested-in-anger default. If TCP misbehaves on your desk, please open an issue.
Tools
Every tool returns a structured result with an ok field. ok: false means the command never
left this machine, and error says why. ok: true means it did — and, as above, never more
than that.
Cues — fire_cue, go_cue, set_pending_cue
fire_cue takes a cue and an optional playback, and supports point cues such as 1.5.
set_pending_cue is ZerOS's "Next": it moves the standby cue without firing it.
The Master Playback is playback 0. Playback numbers start at 0, not 1. If a cue will not
fire, try omitting the playback — an FLX S48 user reported /zeros/cue/go/0/4 being ignored
where /zeros/cue/go/4 worked, so the cue-only form is worth trying before concluding the
console isn't listening.
Playbacks — pause_playback, release_playback, view_playback, set_playback_level
go_cue, pause_playback and release_playback all take an optional playback number.
Omitting it targets whichever playback the console currently considers active — which this
server has no way to know, so naming the playback is the safer call.
Omitting fade_seconds on a level is not the same as passing 0: ZerOS then uses the
playback's own raise and lower times, moving rather than snapping.
Whole rig — set_grand_master, set_blackout
Both affect everything at once, and because nothing is reported back you will not be able to tell that you have blacked out a show.
Macros — fire_macro
This is the escape hatch, and it is the answer to most "can it…?" questions. The documented OSC surface has no command line, no channel or colour control, and no way to record anything. Anything outside the list above is done by recording a user macro at the desk once, and firing it by number from here. So "set channel 1 to 50%" is not impossible — it is a macro.
This server — get_connection_health, get_command_journal
Neither reports console state, because none is observable. get_command_journal returns this
server's own history of sent messages, bounded to the most recent 50; an operator moving a
fader by hand a second after you sent a command leaves no trace in it.
Argument ranges are declared in each tool's schema, so out-of-range input is rejected before it reaches the console.
Troubleshooting
Start with get_connection_health. Over TCP it can tell you whether anything is listening,
which narrows the list below considerably. Over UDP it cannot, and it says so rather than guess.
Commands report ok: true but nothing happens. The likeliest failure, and the one with no
signal to go on. Check, in this order:
ZerOS version is 7.14 or later. Older software ignores OSC entirely while looking perfectly healthy — nothing in the UI indicates the feature is absent.
OSC is enabled under Setup → Triggers → OSC.
Receive Port Number equals
ZEROS_PORT.The console's protocol setting (UDP / TCP (SLIP)) matches
ZEROS_TRANSPORT. A UDP sender talking to a console expecting TCP produces exactly this symptom.
To confirm the packets are at least leaving this machine, listen for them yourself:
python3 -c "import socket;s=socket.socket(2,2);s.bind(('',8830));print(s.recvfrom(9999))"Point ZEROS_IP/ZEROS_PORT at that listener and fire a tool. If the datagram arrives, the
send path is fine and the problem is at the console.
Commands return ok: false with a send error. The console is unreachable at ZEROS_IP.
Check the address and that both machines are on the same network. Over TCP this is also what a
refused connection looks like, which is more informative than UDP's silence.
Firewall. On Windows, allow the Python interpreter through for the port you configured.
Nothing works and there is no log output. Set ZEROS_LOG_LEVEL=DEBUG. Logs go to stderr;
your MCP client may hide them.
Development
git clone https://github.com/MaybeItsAdam/zeros-mcp
cd zeros-mcp
uv sync --all-groups
uv run pytest # test suite; no console required
uv run ruff check .
uv run ruff format .
uv run mypyTo point a client at your local checkout instead of GitHub, use
"command": "uv", "args": ["--directory", "/absolute/path/to/zeros-mcp", "run", "zeros_server.py"]
in place of the uvx block above.
The integration tests bind real sockets on ephemeral ports and assert on the bytes that arrive, including the SLIP frame over TCP, so message construction and framing are covered without hardware. There is no receive path to test.
Two rules the test suite enforces mechanically:
Never write to stdout. Under the stdio transport stdout carries JSON-RPC frames; a stray
print()corrupts the session. Usezeros_mcp.logging_setup.get_logger. (tests/test_no_stdout.py)Validate anything interpolated into an OSC address. On ZerOS the address carries the arguments, so a
/in a tool argument silently becomes a different command. Use the helpers inzeros_mcp/osc/address.py.
A third is enforced by convention and worth stating: no tool may imply the console confirmed
anything. tests/test_schemas.py pins the set of get_* tools for that reason — a new one
would mean inventing a feedback path that does not exist.
Related
eos-mcp — the same idea for ETC Eos family consoles. Eos publishes its state over OSC, so that server mirrors the console live and has a far larger tool surface. The difference is the protocol, not the effort.
Licence
MIT — see LICENSE.
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.
Related MCP Servers
- AlicenseBqualityBmaintenanceAn MCP server that lets AI assistants control grandMA2 lighting consoles via Telnet, exposing 41 high-level tools for cue management, fixture control, preset management, executor control, macro editing, appearance assignment, bulk operations, console state queries, show file management, read-back verification, and music show workflows.10013Apache 2.0
- Alicense-qualityAmaintenanceTransforms an ETC Eos lighting console into a service controllable by AI assistants and automation tools via MCP and OSC, enabling cue management, preset recall, and channel level control.AGPL 3.0
- AlicenseAqualityDmaintenanceMCP server for controlling Behringer X-Air digital mixers via OSC, with symbolic naming and dB-to-float conversion.191Apache 2.0
- AlicenseBqualityCmaintenanceAn MCP server for controlling Voicemeeter (Basic, Banana, or Potato) on Windows: strip and bus gains, mutes, output routing, live levels, macro buttons, presets, and audio-engine restarts.17MIT
Related MCP Connectors
MCP server for Zooza — class scheduling, attendance, and booking for activity businesses.
The MCP server for Azure DevOps, bringing the power of Azure DevOps directly to your agents.
Remote MCP server for full read/write access to a Zotero library
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- 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/MaybeItsAdam/zeros-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server