MCP ETC Nomad
Control ETC Eos-family lighting consoles (including ETCnomad) over OSC: run command-line instructions, set levels, fire cues, and read back console state.
Command line:
eos_command(/eos/cmd),eos_new_command(/eos/newcmd),eos_event— withenter/hash/noneterminators for record, patch, copy, save, and other CLI-only operations.Levels & selection:
channel_select,channel_set_level(0–100),channel_set_dmx(0–255),group_set_level(0–100),at_set_levelfor the current OSC selection.Playback:
cue_select,cue_fire(direct, no GO sequencing),cue_go(sequential Go key),macro_fire,submaster_set_level,magic_sheet_open.Keys:
key_pressany Eos hardkey by OSC name (go,clear,stop) withdown/up/tapedges.Queries (read-only):
get_console_state(live/blind, user, connection),get_active_cue,get_command_line,wait_for_osc(exact address or regex, ≤30s),osc_reset.Safety gating: write tools accept
confirm(required whenEOS_REQUIRE_CONFIRM=true) so live shows aren't changed accidentally.Caveat: the schema types
submaster_set_levelas 0.0–1.0, whereas the README documents submaster/GM APIs as 0–100 — worth verifying against the desk.
Click on "Deploy 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., "@MCP ETC Nomad fire cue 5"
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.
MCP ETC Nomad
GitHub: https://github.com/eva-akselrad/mcp-etc-nomad
TypeScript Model Context Protocol server for ETC Eos Family lighting consoles — including ETCnomad on PC/Mac.
Control ETCnomad and Eos desks over OSC so an LLM can operate cues, levels, subs, macros, and the full Eos command line.
See PLAN.md for the full roadmap to operator parity.
Lighting-ops pack API: mcp-etc-nomad-specs/LIGHTING_OPS_SPEC.md (LOCKED).
Phase status
Phase | Status |
0 Foundation | Implemented |
1 Playback parity | Implemented |
2 Programming parity | Implemented |
2.5 Lighting Expert pack | Implemented |
3 Show & system admin | Implemented |
4 Hardening & distribution | Implemented |
Related MCP server: Eos MCP
Phase 1 (playback)
Live-write tools require confirm=true when EOS_REQUIRE_CONFIRM=true (default) and allow_live=true when the console is LIVE (or state is unknown) and EOS_ALLOW_LIVE=false (default). Read get_console_state / eos://playback/state first.
Intensity scales: channel/group levels and color_set_rgb / channel_set_param are 0–100 (percent, converted at TX). fader_set_level stays 0.0–1.0 (OSC native). Grand master and submaster tool APIs are 0–100 (mapped to OSC 0.0–1.0). Cue-fire rate limit (default 12/min) is bypassed with override_rate_limit=true — confirm does not bypass rate limits.
Group | Tools |
Playback |
|
GM / BO |
|
Channel check |
|
Park |
|
Cue list banks |
|
Faders / subs |
|
Palettes / presets |
|
Keys / macros |
|
Direct selects |
|
Command line |
|
Levels |
|
Color / params |
|
Queries |
|
Resources: eos://playback/active, eos://playback/pending, eos://playback/state, eos://playback/faders, eos://console/keys
Prompts: eos-operator, eos-live
OSC addresses follow the ETC OSC Dictionary. Go is go_0; Stop/Back is stop. Create fader / cue-list / direct-select banks before paging or reading labels.
Phase 2 (programming)
Programming writes use the same confirm / allow_live gates as playback. Destructive deletes also require confirm_delete=true when EOS_REQUIRE_CONFIRM=true.
Group | Tools |
Record / update |
|
Copy / move / delete |
|
OSC set |
|
Patch |
|
Sync / get |
|
Command line |
|
Resources: eos://show/groups, eos://show/cuelists, eos://show/cues/{list}, eos://show/patch, eos://show/presets, eos://show/palettes/{type}
Prompts: eos-programmer, eos-patch
Sync uses OSC /eos/get/* request/response (node-eos-console / EosSyncLib pattern): count → index → cache in listener state. Subscribe with /eos/subscribe + int arg 1 on sync (default).
Phase 3 (show & system admin)
Eos OSC domain rules: no OSC Save/Load verbs — Browser + key_press + CLI only. Never invent usb1:/ or .esf paths.
Group | Tools |
Show files |
|
Patch extras |
|
Troubleshoot |
|
Network |
|
Gates: user_intent for load/merge/join; confirm_save / confirm_path when EOS_REQUIRE_CONFIRM=true. Prefer Blind for load/merge. After load/merge, sync_show_targets + reconfigure banks.
TCP transport (real TCP OSC, not UDP retarget): EOS_PROTOCOL=tcp. 3032 = OSC TCP 1.0 length headers (bidirectional); 3037 = Third Party OSC 1.1 SLIP (~realtime /eos/out). Custom ports OK (4703–4727+). Enable OSC RX+TX in Setup. UDP remains default; ETC prefers TCP.
Resources: eos://console/info, eos://console/session, eos://console/version, eos://show/path
Prompts: nomad-setup, eos-showfile
Phase 4 (hardening & distribution)
Item | Status |
OSC address + CLI test suite |
|
Golden trace replay |
|
CI (no hardware) | GitHub Actions — |
npm package |
|
Cloudflare Worker relay | Not implemented — no prior sketch; documented as future remote-desk option |
Install
From npm (recommended)
npm install -g mcp-etc-nomad
# or as a project dependency:
npm install mcp-etc-nomadRun the MCP server (stdio):
mcp-etc-nomad
# equivalent: npx mcp-etc-nomadFrom source
npm install
npm run build
npm startDevelopment:
npm run devETCnomad OSC setup
Setup → System Settings → Show Control → OSC:
Setting | Value |
OSC RX | On |
OSC TX | On |
String RX | On |
UDP RX Port |
|
UDP TX Port |
|
Use the console IP from Nomad Shell (not always 127.0.0.1 when MCP runs on another machine).
Copy .env.example to .env and adjust.
Testing
Mock OSC (no Nomad hardware): test/harness.ts + test/mock-osc-peer.ts listen on a local UDP port, capture MCP tool TX packets, and send canned /eos/out/* replies (see PLAN.md §11.1).
npm testFile | Coverage |
| Address builders, |
| Full |
| CLI Enter/ |
| OSC hardkey aliases ( |
|
|
| Lighting-ops blockers: |
| Anonymized |
| CLI programming builders (Copy/Delete Thru), tool TX, |
| Show save/load/merge/export gates ( |
| Canned |
| Recorded Nomad-style OSC captures for regression |
Fader level tests assert TX only — Eos echoes /eos/out/fader after ~3s, so the harness does not expect an immediate echo.
Programming tools (record_cue, update_cue, etc.) refuse LIVE/unknown console state unless allow_live=true (mock tests cover this). sync_show_targets + get_groups / get_cuelists / get_cues populate listener cache; MCP resources eos://show/* read that cache.
Automated gates in test/show-admin.test.ts: show_load / show_merge require user_intent (≥8 chars), refuse LIVE/unknown without allow_live, and require confirm_path when EOS_REQUIRE_CONFIRM=true. Default path is needsManual (no unverified Browser OSC keys); opt-in via press_unverified_browser_keys. network_session_leave requires user_intent when gating is on and returns needsManual only (Stop Mirroring / ALT+F2 — no invented /eos/key/exit).
Nomad offline smoke (manual): with ETCnomad running and OSC enabled (see above):
Playback / programming: channel level, cue fire, group+cue record via CLI (
record_cue), delete withconfirm_deleteLighting-ops:
go_to_cue(CLIGo To Cue Nvia/eos/newcmd— not/eos/key/go_0); confirm blackout (/eos/key/blackout) is separate from grandmaster_set_level(0) (BO≠GM);highlight/homewith channel selection (reject bare calls without selection)Show files (Browser):
show_save(quick save + path echo);show_loadandshow_mergewithuser_intent+confirm_path— complete the CIA Browser wizard on the desk (tools returnneedsManual; no auto-load/merge)Network:
network_session_leavewithuser_intent— complete mirror exit on desk via Stop Mirroring softkey or ALT+F2 (tool returnsneedsManual; no OSC key TX)Gates: verify
show_merge/show_loadrefuse LIVE withoutallow_live;network_session_leaverequiresuser_intentwhen gating is on
Full checklist: PLAN.md §11.2.
Cursor / Claude Desktop
{
"mcpServers": {
"etc-nomad": {
"command": "mcp-etc-nomad",
"args": [],
"env": {
"EOS_HOST": "192.168.1.50",
"EOS_PORT_TX": "8000",
"EOS_PORT_RX": "9001",
"EOS_ALLOW_LIVE": "false",
"EOS_REQUIRE_CONFIRM": "true"
}
}
}
}When installed from source instead of npm, use "command": "node" with "args": ["/absolute/path/to/mcp-etc-nomad/dist/index.js"].
Project layout
src/
├── index.ts # MCP stdio entry
├── config.ts # Environment config
├── eos/
│ ├── client.ts # OSC TX
│ ├── listener.ts # OSC RX + state cache (+ multipart /list/0)
│ ├── state.ts # Typed desk state
│ ├── addresses.ts # OSC path builders
│ ├── keys.ts # OSC Dictionary hardkey map + aliases
│ ├── command.ts # CLI terminators
│ ├── context.ts # Shared context + live/confirm gates
│ ├── sync.ts # sync_show_targets (/eos/get/* cache)
│ ├── show-admin.ts # Phase 3 show-file workflow builders
│ └── programming.ts # Phase 2 CLI builders
├── tools/ # MCP tools (Phase 0–3)
├── resources/ # MCP resources (playback + show + console)
└── prompts/ # eos-operator, eos-live, eos-programmer, eos-patch, nomad-setup, eos-showfileLicense
MIT
Available Tools
20 toolsat_set_levelADestructive
Set level for the current OSC selection via /eos/at
Inputs: level (required), confirm.
channel_selectB
Select an Eos channel (leaves command line unterminated)
Inputs: channel (required).
channel_set_dmxBDestructive
Set a channel DMX level (0-255)
Inputs: dmx (required), channel (required), confirm.
channel_set_levelCDestructive
Set a channel intensity (0-100)
Inputs: level (required), channel (required), confirm.
cue_fireADestructive
Fire a cue (does not follow GO sequencing unless using cue_go)
Inputs: cue (required), confirm, cueList.
cue_goBDestructive
Press the console Go key (sequential cue advance)
Inputs: confirm.
cue_selectC
Select a cue, optionally within a cue list
Inputs: cue (required), cueList.
eos_commandADestructive
Send an Eos command-line instruction via OSC (/eos/cmd). Use for record, patch, copy, save, and any CLI-only operations.
Inputs: text (required), confirm, terminator.
eos_eventC
Send a console event via /eos/event (same syntax as eos_command)
Inputs: text (required), confirm, terminator.
eos_new_commandCDestructive
Clear the command line, then send an instruction via /eos/newcmd
Inputs: text (required), confirm, terminator.
get_active_cueARead-only
Return the active cue text and completion percent from OSC cache
Inputs: no named parameters.
get_command_lineARead-only
Return the current command line text from OSC cache
Inputs: no named parameters.
get_console_stateARead-only
Return cached console state (blind/live, user, connection)
Inputs: no named parameters.
group_set_levelCDestructive
Set a group intensity (0-100)
Inputs: group (required), level (required), confirm.
key_pressADestructive
Press an Eos hardkey by OSC name (e.g. 'go', 'clear', 'stop')
Inputs: key (required), edge, confirm.
macro_fireBDestructive
Run a macro by number
Inputs: macro (required), confirm.
magic_sheet_openB
Open a magic sheet, optionally a specific view
Inputs: sheet (required), view.
osc_resetC
Send /eos/reset to clear OSC switches and refresh implicit output
Inputs: confirm.
submaster_set_levelCDestructive
Set a submaster level (0.0-1.0)
Inputs: sub (required), level (required), confirm.
wait_for_oscBRead-only
Wait for an incoming OSC address pattern (timeout in ms)
Inputs: address (required), useRegex, timeoutMs.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 20 tools
Several tools overlap heavily: eos_command, eos_new_command, and eos_event are easily confused, especially since eos_event is described as using 'same syntax as eos_command.' Also, cue_fire, cue_go, and key_press all relate to the GO action, while channel_set_level and at_set_level both set intensity, creating boundary ambiguity.
Naming is not chaotic and consistently uses snake_case, but conventions vary: object-first names like channel_set_level and cue_fire sit alongside verb-first names like get_console_state and wait_for_osc, with oddities like eos_command and eos_new_command that have no clear action verb. It is readable but not predictable.
20 tools is on the heavy/borderline side. The Eos Nomad control domain is fairly broad and most tools target distinct console resources, but several overlapping command/event/Go tools could be consolidated, making the count feel higher than necessary.
The set covers core console workflows well: channels, groups, cues, submasters, macros, command-line entry, key presses, and state read-back. The generic eos_command tool helps fill CLI-only gaps, though there are minor missing read-back operations such as querying submaster or channel levels directly.
Maintenance
Related MCP Connectors
Control Unreal Engine to browse assets, import content, and manage levels and sequences. Automate…
Operate Linux, macOS and Windows from your LLM. Every action runs through an auditable allowlist.
MCP connector that lets ChatGPT list, search, and run your Apple Shortcuts via a local Mac agent
OpenAI-compatible LLM MCP (7 tools); chat via balance key or x402 USDC on Base
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceEnables natural language control of OSC (OpenSoundControl) messages, allowing users to generate, interpret, validate, and debug OSC messages through an LLM interface for parametric control of multimedia devices.3MIT
- AlicenseNot gradedqualityBmaintenanceTransforms 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.4AGPL 3.0
- AlicenseNot gradedqualityDmaintenanceEnables LLMs to control QLab live over OSC, including querying workspaces, managing cues, and sending raw OSC or AppleScript commands.MIT
- FlicenseAqualityDmaintenanceMCP server that enables control of an ETC Eos lighting console over OSC, supporting cues, channel levels, faders, and macros, with safety guards for destructive actions.132-