zeros-mcp

zeros-mcp

An MCP server for controlling Zero 88 lighting consoles running ZerOS over OSC, exposing playbacks, cues, the grand master, blackout, and user macros as MCP tools.

Category
访问服务器

README

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 are get_command_journal (what this server sent) and get_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: true means 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 carries confirmed_by_console: false permanently.

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.

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 console

Prerequisites

  • A ZerOS console running 7.14 or later
  • uv — no separate Python install or clone needed; uv fetches Python and the server itself.

Setup

1. Enable OSC on the console. Setup → Triggers → OSC:

Setting Value
OSC Enabled
Receive Port Number 8830
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
ZEROS_IP 127.0.0.1 Console address. A desk on factory settings is 192.168.1.10.
ZEROS_PORT 8830 Match the console's Receive Port Number.
ZEROS_TRANSPORT udp udp or tcp. Must match the console's protocol setting.
ZEROS_LOG_LEVEL INFO DEBUG logs every OSC message sent.

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.

Cuesfire_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.

Playbackspause_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 rigset_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.

Macrosfire_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 serverget_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:

  1. 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.
  2. OSC is enabled under Setup → Triggers → OSC.
  3. Receive Port Number equals ZEROS_PORT.
  4. 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 mypy

To 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. Use zeros_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 in zeros_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.

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选