GMA2 MCP
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., "@GMA2 MCP store cue 1 with fixtures 1 thru 10 at full"
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.
GMA2 MCP
An MCP server that lets AI assistants control grandMA2 lighting consoles via Telnet. It exposes 101 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, music show workflows, and more through the Model Context Protocol.
Table of Contents
Related MCP server: Eos MCP
Overview
grandMA2 consoles accept commands over Telnet, but building correct command strings requires knowledge of the MA2 syntax rules -- keyword ordering, preset type mappings, option flags, and object hierarchies. This project handles that complexity in layered components:
Command Builder (
src/commands/) -- Python functions that construct valid grandMA2 command strings following the official syntax rules. Each function is a thin wrapper that returns a string; it never touches the network.MCP Server (
src/server.py) -- A FastMCP server that exposes 101 tools covering cue management, fixture control, presets, executors, global state, labeling, appearance assignment, macro editing, bulk cue operations, sequence playback, console state queries, show file management, read-back verification, music show workflows, and raw commands over stdio transport. It manages a persistent Telnet connection to the console and delegates command construction to the builder layer.Response Parser (
src/response_parser.py) -- Pure functions for parsing grandMA2 Telnet output: tabularListdata into structured dicts, and inlineError #NN: REASONfailures (with ANSI stripping) for the verified execution path.Execution Core (
src/execution.py) --ExecutionResultplus the purebuild_result()that turns a raw Telnet reply into a structured{ok, echo, error_code, error_text, raw}. Mutating tools route throughGMA2TelnetClient.execute()so they report the console's real outcome instead of fabricating success.GMA2Client (
src/gma2_client.py) -- A high-level orchestration class that composes multiple command builder calls into workflow-level methods (e.g., build an entire cue list, set up a fixture group with a preset, create song objects for music shows).CommandSequence (
src/command_sequence.py) -- A builder-pattern class for composing multiple commands into an ordered batch that can be previewed and executed as a unit.
The command builder covers all grandMA2 command-line keywords organized by category: object keywords (fixtures, channels, groups, presets, cues, sequences, executors), function keywords (store, delete, copy, move, goto, label, assign, and many more), and helping keywords (thru, at, +).
Features
100 MCP tools -- Cue management (store/update/delete/goto, CMD assignment, timing, bulk operations), fixture control (set values/attributes, clear programmer, advanced selection: next/previous/invert/locate/align/fix), preset management (store/apply), executor control (on/off/go/kill/toggle/release/top, fader, rate/speed, flash/swop/stomp/temp busking), global state (blackout, highlight), blind/preview modes, object labeling, appearance assignment, copy/move and extended delete (group/preset/fixture/show), park/unpark, macro editing, effect control (apply, speed, form, range, phase, width, envelope, seconds, speed group, sync), MAtricks fan effects, show/user variables, timecode (SMPTE), MIDI output (note/control/program), clone fixtures, console state queries, show file management, read-back verification, music show workflows, and raw command execution.
Verified command execution -- grandMA2 reports failures inline in the Telnet reply (
Error #NN: REASON). Mutating tools route through a verified execution core (src/execution.py) that parses the reply and returns the console's real outcome, so the assistant is not given false success on a rejected command. Multi-command tools abort on the first error.Range/batch selectors -- Object tools accept grandMA2 selection expressions (
1 thru 10,1 + 3 + 5,1 thru 10 - 4) validated bysrc/commands/selector.py, so a whole range copies/moves in one call instead of looping per ID.Show-aware name resolution --
src/introspection.pyqueriesList Attribute(cached) and resolves friendly, show-specific attribute names (e.g.White->COLORRGB5) before sending, rejecting unknown names with suggestions.Fixture-profile resolver --
src/profile_resolver.pyparses MA2 fixture-type / GDTF XML and resolves named functions (open/closed/strobe/random/iris/frost/prism) to the correct per-fixture-type value, so the same logical preset (e.g. "Strobe Fast") gets the right DMX value on every profile.Palette builders --
build_color_paletteand the generalizedbuild_preset_paletteprogram whole preset palettes in one call, with per-fixture-type values, Global/Selective scope, and per-type merge (extend a palette to a new fixture group non-destructively).Destructive command safety warnings -- Delete tools include informational warnings about downstream effects (orphaned executor handles, lost cue programming) to help AI assistants understand impact before confirming.
Complete command builder -- Over 350 Python functions covering all grandMA2 command-line keywords across 30+ modules, each returning a correctly formatted command string.
High-level client --
GMA2Clientprovides workflow-level methods: build cue lists, set up fixture groups with presets, quick look programming, batch executor assignments. Uses grandMA2's inline naming syntax to minimize Telnet round-trips.Command chaining --
CommandSequencelets you compose multiple commands, preview them, and execute them as a batch.Resilient Telnet client -- Built on
telnetlib3with automatic login, persistent connections, connection health checking, auto-reconnection with bounded exponential backoff, command serialization viaasyncio.Lock, and graceful shutdown. If the console restarts or the network drops, the client detects the failure and reconnects transparently before the next command.Connection error surfacing -- MCP tools catch connection failures and return human-readable error messages instead of unhandled exceptions, so the AI assistant knows when commands are not reaching the console.
Configurable transport -- Supports
stdio(default, single client) andstreamable-http(multi-client, web-based access) transports. HTTP host and port are configurable via environment variables.Configurable via environment -- Host, port, user, password, and transport settings set through
.envor environment variables.
Getting Started
Prerequisites
Python >= 3.12
A grandMA2 console (or onPC) with Telnet access enabled
uv (recommended) or pip
On macOS, if you need a Telnet client for manual testing:
brew install telnetInstallation
git clone <repository-url>
cd gma2-mcpUsing uv:
uv syncUsing pip:
python -m venv .venv
source .venv/bin/activate
pip install -e .Configuration
Copy the template and fill in your console details:
cp .env.template .envVariable | Description | Default |
| IP address of the grandMA2 onPC |
|
| Telnet port |
|
| Login username |
|
| Login password |
|
| MCP transport protocol ( |
|
| HTTP bind address (streamable-http only) |
|
| HTTP port (streamable-http only) |
|
GMA_HOST should be set to the IP address of the machine running grandMA2 onPC. You can find this in the onPC network settings or by checking the machine's network configuration.
Port 30000 is the standard command port. Port 30001 is read-only (log output).
To enable HTTP transport for web-based or multi-client access:
MCP_TRANSPORT=streamable-http
MCP_HOST=0.0.0.0 # bind to all interfaces (default: 127.0.0.1)
MCP_PORT=3000 # custom port (default: 8000)When using streamable-http, concurrent commands from multiple clients are automatically serialized via an internal lock to prevent interleaved Telnet commands, since the grandMA2 console processes commands sequentially.
MCP Registration
Add the server to your MCP client configuration.
Claude Desktop (~/Library/Application Support/Claude/claude_desktop_config.json on macOS):
{
"mcpServers": {
"gma2": {
"command": "uv",
"args": [
"--directory",
"/path/to/gma2-mcp",
"run",
"python",
"-m",
"src.server"
],
"env": {
"GMA_HOST": "2.0.0.1",
"GMA_USER": "administrator",
"GMA_PASSWORD": "admin"
}
}
}
}Without uv -- point directly to the virtualenv Python:
{
"mcpServers": {
"gma2": {
"command": "/path/to/gma2-mcp/.venv/bin/python",
"args": ["-m", "src.server"],
"cwd": "/path/to/gma2-mcp",
"env": {
"GMA_HOST": "2.0.0.1",
"GMA_USER": "administrator",
"GMA_PASSWORD": "admin"
}
}
}
}Claude Code (CLI / IDE extensions)
Claude Code manages MCP servers through its own configuration, separate from Claude Desktop. You can set it up using either the CLI command or by editing the settings file directly.
Option 1: Using the claude mcp add command (recommended)
Run the following command in your terminal:
claude mcp add gma2 \
-e GMA_HOST=2.0.0.1 \
-e GMA_USER=administrator \
-e GMA_PASSWORD=admin \
-- uv --directory /path/to/gma2-mcp run python -m src.serverThis registers the MCP server with Claude Code. The -e flags set environment variables that the server reads at startup. Replace /path/to/gma2-mcp with the actual path to your cloned repository, and adjust the GMA_HOST, GMA_USER, and GMA_PASSWORD values to match your console.
To register the server for a specific project only (instead of globally), add the -s project flag:
claude mcp add gma2 -s project \
-e GMA_HOST=2.0.0.1 \
-e GMA_USER=administrator \
-e GMA_PASSWORD=admin \
-- uv --directory /path/to/gma2-mcp run python -m src.serverOption 2: Editing the settings file manually
Add the server entry to your Claude Code settings file. The file location depends on the scope:
User-level (available in all projects):
~/.claude/settings.jsonProject-level (available only in the current project):
.claude/settings.jsonin the project root
{
"mcpServers": {
"gma2": {
"command": "uv",
"args": [
"--directory",
"/path/to/gma2-mcp",
"run",
"python",
"-m",
"src.server"
],
"env": {
"GMA_HOST": "2.0.0.1",
"GMA_USER": "administrator",
"GMA_PASSWORD": "admin"
}
}
}
}Verifying the setup
After registering the server, verify it is working:
# List all registered MCP servers
claude mcp list
# Check the server details
claude mcp get gma2When you start a new Claude Code session, the server starts automatically. You can confirm the tools are available by asking Claude to list its MCP tools or by directly requesting a grandMA2 operation (e.g., "toggle blackout on the console").
Managing the server
# Remove the server
claude mcp remove gma2
# Re-add with different settings
claude mcp add gma2 \
-e GMA_HOST=192.168.1.100 \
-- uv --directory /path/to/gma2-mcp run python -m src.serverUsage
MCP Tools
The server exposes 101 tools:
Tool | Description |
| Report version, registered tools, and profile schema version (contract surface; no console connection) |
| Select fixtures and store as a named group (2 commands) |
| Store current programmer state as a cue |
| Delete a cue (includes downstream safety warnings) |
| Jump to a specific cue (executor or sequence) |
| Set fixture(s) to a dimmer value (0-100) |
| Set a specific attribute (Pan, Tilt, etc.) on fixture(s) |
| Clear the programmer (all, selection, active, default) |
| Store current values as a preset |
| Apply an existing preset to the current selection |
| On/off/go/kill/toggle an executor |
| Set executor fader level (0-100) |
| Assign a sequence to an executor (supports named page paths) |
| Toggle grand blackout |
| Toggle highlight mode |
| Assign a name label to any MA2 object |
| Label a cue within a specific sequence |
| Set frame/background colors on pool objects and cues (RGB/HSB/hex) |
| Set the command for a specific macro line |
| Execute a macro by ID (Go+ Macro) |
| Create a macro with command lines (store + assign lines + label) |
| Label a macro in the macro pool |
| List macros in the macro pool |
| Delete a macro (with destructive operation warnings) |
| Apply effect from pool to current fixture selection |
| Set effect speed in BPM or Hz |
| Set effect waveform (sine, ramp, square, etc.) |
| Set effect high and/or low values |
| Set effect phase offset in degrees |
| Set effect width (percentage of cycle) |
| Stop running effects for current selection (Off Effect) |
| Synchronize all running effects |
| Assign a command to a cue's CMD field |
| Store a cue across a range of sequences in one call |
| Label a cue across a range of sequences in one call |
| Set cue appearance across a range of sequences in one call |
| Go, pause, or goto a cue in a sequence |
| List all defined groups (returns raw console response) |
| List cues in a sequence (returns raw console response) |
| List presets by type with validation (returns raw console response) |
| Read user-added annotation text on a cue |
| Read user-added annotation text on a group |
| List show or user variables with optional filter |
| Generic query for any MA2 object type (list or annotation mode) |
| Save the current show file (optional name) |
| Load a show file (destructive -- warns about unsaved changes) |
| Create a new empty show (destructive -- warns about unsaved changes) |
| List available show files on the console |
| Read macro line content (parsed into structured data) |
| Read cue properties: label, CMD, fade (parsed) |
| Read the label of any pool object (sequence, page, macro, etc.) |
| Create and label a Sequence + Page pair for a song |
| Create a macro with SetVar command for song variable assignment |
| Build a set-list sequence with cue-to-macro links |
| Send any grandMA2 command-line instruction |
Query / Introspection Tools
The query tools use send_command_with_response() to capture the grandMA2 Telnet output and return raw text. The grandMA2 manual does not document the exact Telnet wire format for List and Info responses, so these tools return unprocessed console output that the AI can interpret directly.
list_groups,list_cues,list_presets-- Use the grandMA2Listkeyword to retrieve show data. Accept optional ID ranges (e.g.,list_groups(group_id=1, end_group_id=10)).list_presetsvalidates the preset type against the 9 known types before sending.get_cue_annotation,get_group_annotation-- Use the grandMA2Infokeyword, which reads user-added descriptive text annotations on objects (set viaInfo Group 3 "some note"on the console). These do NOT return object properties like fade times or fixture composition -- uselist_cuesorlist_groupsfor that.list_variables-- Routes toListVar(show variables) orListUserVar(user variables) based on thevariable_typeparameter. Supports an optional filter pattern.query_object-- Generic query for any grandMA2 object type not covered by the dedicated tools. Supportsmode="list"(default) andmode="annotation".
All query tools return a descriptive message instead of an empty string when the console returns no data.
Show File Management Tools
save_show_tool-- Saves the current show file. Accepts an optionalshow_nameto save as a specific name. Uses/noconfirmto suppress the overwrite confirmation popup that would block Telnet.load_show_tool-- Loads a show file by name. This is a destructive operation: unsaved changes to the current show are lost. Acceptssave_first=Trueto save the current show before loading. Uses/noconfirmto suppress the GUI popup.new_show_tool-- Creates a new empty show. Same destructive behavior andsave_firstoption asload_show_tool.list_shows_tool-- Lists available show files on the console's selected drive. Accepts an optional filter pattern.
Read-Back Tools
The read-back tools use send_command_with_response() to capture grandMA2 List command output and parse it into structured dicts via src/response_parser.py. Each tool returns a dict with parsed fields plus a raw_response field for debugging. If the response format is unrecognized, the tools return parsed: False with the raw output.
read_macro_lines-- SendsList Macro {pool}.{id}and parses each line's number and CMD content. Returns{"macro_id": N, "parsed": True, "lines": [{"line_number": 1, "cmd": "..."}], "raw_response": "..."}.read_cue_info-- SendsList Cue {id} Sequence {seq}and extracts label, CMD, and fade time. Returns{"sequence_id": N, "cue_id": N, "label": "...", "cmd": "...", "fade": "...", "raw_response": "..."}.read_object_label-- SendsList {type} {id}and extracts the object's name/label. Works with any pool object type (sequence, page, group, etc.). For macros, theobject_idmust be pool-qualified (e.g.,"1.5"for Macro 5 in Pool 1).
Music Show Workflow Tools
High-level tools that automate common multi-step patterns for music show programming. These delegate to GMA2Client workflow methods.
create_song_objects-- Creates and labels a Sequence + Page pair with the same ID and name. This is the standard pattern for per-song programming (e.g.,create_song_objects(song_id=101, song_name="Opening+Childhood")sends 2 commands).setup_song_macro-- Creates a labeled macro with aSetVarcommand on line 1 for tracking the current song. Accepts an optionalvar_name(default:$song). Sends 3 commands: store macro, label, assign CMD.build_set_list-- Creates a set-list sequence with cues linked to song macros. For each song, stores a cue with the song name as label and assignsMacro {id}as the cue CMD. Accepts a list of{cue_id, macro_id, name}dicts.
delete_show is intentionally not exposed as an MCP tool -- it is irreversible and too dangerous for AI-initiated operations. The Backup command is also excluded because it opens a GUI menu on the console (per grandMA2 Manual p368), which is not functional over Telnet. Use save_show_tool with a specific name as the practical backup mechanism.
Command Builder
The src/commands/ module can be used independently to build command strings:
from src.commands import fixture, at_full, store_group, label_group
fixture(1, end=10) # "fixture 1 thru 10"
at_full() # "at full"
store_group(5) # "store group 5"
store_group(5, name="Front Wash") # 'store group 5 "Front Wash"' (inline naming)
label_group(5, "Front Wash") # 'label group 5 "Front Wash"' (separate label command)GMA2Client (Workflow Orchestration)
The GMA2Client class provides high-level workflow methods that compose multiple commands. These methods use grandMA2's inline naming syntax to minimize the number of Telnet round-trips:
from src.gma2_client import GMA2Client
async with GMA2Client.create("192.168.1.100") as client:
# Build a cue list with names and fade times
# Uses inline naming: 1 command per named cue (store cue N "Name"),
# plus 1 command per fade time
await client.build_cue_list(1, [
{"id": 1, "name": "Preset", "fade": 0},
{"id": 2, "name": "Look 1", "fade": 3.0},
{"id": 3, "name": "Blackout", "fade": 2.0},
])
# Select fixtures, store as named group, apply a preset (3 commands)
# Uses inline naming: store group N "Name" in a single command
await client.setup_group_with_preset(
fixtures=(1, 10), group_id=1,
group_name="Front Wash", preset_type="color", preset_id=3,
)
# Quick look: set fixtures to a value, optionally store as cue
await client.quick_look(fixtures=(1, 20), value=75, store_as_cue=5)
# Batch assign sequences to executors
await client.assign_sequences_to_executors([(1, 1), (2, 2), (3, 3)])
# Clone fixture programming (with /noconfirm for telnet)
await client.clone_fixtures(source_fixture=1, target_fixture=11,
source_end=5, target_end=15, mode="overwrite")
# Apply effect to a group with parameters
await client.setup_effect_on_group(group_id=1, effect_id=5,
bpm=120, form="sin", high=100, low=0)
# Set up a full executor page
await client.setup_executor_page(page=1, assignments=[
{"executor_id": 1, "sequence_id": 1, "label": "Wash", "fader_level": 80},
{"executor_id": 2, "sequence_id": 2, "label": "Spots"},
])
# Label multiple objects at once
await client.batch_label("group", {1: "Wash", 2: "Spots", 3: "Beams"})
# Create and optionally run a macro
await client.create_and_run_macro(
macro_id=10, commands=["Go Sequence 1", "Go Sequence 2"],
name="Start Show", run=True,
)
# Music show workflows: create song objects (sequence + page pair)
await client.create_song_objects(song_id=101, song_name="Opening+Childhood")
# Set up a song macro with SetVar on line 1
await client.setup_song_macro(macro_id=101, song_name="Opening+Childhood")
# Build a full set list with cue-to-macro links
await client.build_set_list(
sequence_id=100, sequence_name="Set List",
songs=[
{"cue_id": 1, "macro_id": 101, "name": "Opening+Childhood"},
{"cue_id": 2, "macro_id": 102, "name": "Nostalgia"},
{"cue_id": 3, "macro_id": 103, "name": "Finale"},
],
)CommandSequence (Command Chaining)
The CommandSequence class lets you compose multiple commands and execute them as a batch:
from src.command_sequence import CommandSequence
from src.commands import fixture_at, store_group, at_full
seq = CommandSequence()
seq.add(fixture_at(1, 50)).add(at_full()).add(store_group(1))
# Preview before sending
print(seq.preview()) # ['fixture 1 at 50', 'at full', 'store group 1']
# Execute all commands
result = await seq.execute(client)
# {'commands_sent': [...], 'count': 3, 'success': True}Direct Telnet Access
For manual testing via the Makefile:
make server # Connect to grandMA2 command port (30000)
make log # Connect to log output port (30001)To exit a Telnet session: press Ctrl + ], then type quit.
Running the MCP Server Manually
uv run python -m src.serverCommand Reference
The command builder follows the official grandMA2 command-line syntax. The basic pattern is [Function] [Object]. All objects have a default function, and most functions have a default object type. Objects are arranged in a hierarchical tree.
1. Helping Keywords (Prepositions/Conjunctions)
Used to create relations between functions and objects.
Keyword | Description | Example |
| Range selection |
|
| Add to selection |
|
| Set values |
|
2. Object Keywords (Nouns)
Allocate objects in the show file. Usually combined with numbers, IDs, names, or labels.
Object | Function | Example |
| Select fixtures by Fixture ID |
|
| Select fixtures by Channel ID |
|
| Select fixtures in a group |
|
| Apply a preset |
|
| Reference a cue |
|
| Reference a sequence |
|
3. Function Keywords (Verbs)
Perform a task or function, often followed by the object they apply to.
Function | Description | Example |
| Store objects in show file |
|
| Store cue with optional inline name |
|
| Store preset with options |
|
| Store a group (with optional inline name) |
|
| Label a group |
|
| Delete a group |
|
| SelFix function |
|
| Clear programmer |
|
| Clear selection only |
|
| Clear active values |
|
| Clear all |
|
| Start sequence playback |
|
| Pause sequence |
|
| Jump to cue |
|
4. At Keyword (Special)
At functions as both a Function Keyword and a Helping Keyword.
Function | Description | Example |
| Set dimmer to value |
|
| Apply cue values |
|
| Set fade time |
|
| Set to 100% |
|
| Set to 0% |
|
| Set attribute value |
|
| Set fixture to value |
|
| Copy from fixture |
|
| Set channel to value |
|
| Set group to value |
|
| Set executor fader |
|
| Set preset type values |
|
5. Copy and Move Keywords
Copy creates duplicates. Move relocates objects (swaps if the destination is occupied).
Function | Description | Example |
| Copy to target |
|
| Copy range |
|
| Copy to target range |
|
| Copy to clipboard |
|
| Copy cue |
|
| Move object |
|
| Move range |
|
Copy options: overwrite, merge, status, cueonly, noconfirm
6. Assign Keyword
Defines relationships between objects, patching, and property assignment.
Function | Description | Example |
| Assign seq to executor |
|
| Patch DMX to channel |
|
| Assign to layout |
|
| Assign function to button |
|
| Assign fade time to cue |
|
| Assign to layout position |
|
| Set macro line command |
|
| Set cue CMD field |
|
Assign options: break_, multipatch, reset, x, y, noconfirm, special, cue_mode, password
7. Label Keyword
Gives names to objects. Numbers in names auto-enumerate for ranges.
Function | Description | Example |
| Label group |
|
| Label range |
|
| Label preset |
|
| Label cue in sequence |
|
| Label cue range |
|
8. Appearance Keyword
Changes frame colors of pool objects and background colors of cues.
Function | Description | Example |
| Set RGB color |
|
| Set HSB color |
|
| Set hex color |
|
| Copy from source |
|
| Reset appearance |
|
9. Macro Placeholder (@ Character)
The @ character (distinct from the At keyword) is used as a placeholder for user input in macros.
Function | Description | Example |
| @ at end of macro line |
|
| @ at start of macro line |
|
Project Structure
gma2-mcp/
├── src/
│ ├── commands/ # Command builder module
│ │ ├── __init__.py # Public API exports
│ │ ├── constants.py # PRESET_TYPES, store option sets
│ │ ├── helpers.py # Internal helper functions
│ │ └── functions/ # Function keywords by category
│ │ ├── advanced_edit.py # Flip, CircularCopy, Import, Export
│ │ ├── assignment.py # Assign keyword functions
│ │ ├── blackout.py # Blackout, Freeze, Highlight, Solo
│ │ ├── blind.py # Blind, Preview modes
│ │ ├── call.py # Call keyword
│ │ ├── conditionals.py # EndIf, IfActive, IfOutput, Or, With
│ │ ├── crossfade.py # Crossfade, ManualXFade
│ │ ├── cue_timing.py # Delay, Fade timing
│ │ ├── edit.py # Copy, Move, Delete, Remove
│ │ ├── effect.py # Effect, EffectBPM, EffectForm
│ │ ├── executor_control.py # Off, On, Kill, Flash, Swop
│ │ ├── fixture_control.py # Align, Fix, Locate, Next, Prev
│ │ ├── flash_swop_ext.py # FlashGo, SwopGo, StoreLook
│ │ ├── helping.py # Helping keywords (Thru, +)
│ │ ├── info.py # List and Info queries
│ │ ├── intensity.py # Full, Zero, Load, Learn
│ │ ├── labeling.py # Label and Appearance
│ │ ├── list_ext.py # ListShows, ListOops, ListVar
│ │ ├── macro.py # Macro placeholder functions
│ │ ├── matricks.py # MAtricks keywords
│ │ ├── midi.py # MIDI control functions
│ │ ├── navigation.py # Down, Up, NextRow, Search
│ │ ├── network.py # Remote, Telnet, JoinSession
│ │ ├── park.py # Park/Unpark functions
│ │ ├── playback.py # Go, GoBack, Goto, DefGo
│ │ ├── programmer.py # Block, Clone, Default, Update
│ │ ├── rate_speed.py # Rate, Speed control
│ │ ├── rdm.py # RDM functions
│ │ ├── selection.py # SelFix and Clear functions
│ │ ├── show_data.py # CrashLog, Lua, PSR, Thru
│ │ ├── step_timing.py # SnapPercent, StepFade, FadePath
│ │ ├── store.py # Store functions
│ │ ├── system.py # Backup, Setup, Shutdown, Login
│ │ ├── values.py # At and value setting
│ │ └── variables.py # Variable functions
│ ├── command_sequence.py # CommandSequence for multi-command batching
│ ├── gma2_client.py # High-level workflow orchestration client (15 methods)
│ ├── response_parser.py # Parse grandMA2 Telnet output into structured data
│ ├── execution.py # Verified execution core (ExecutionResult, build_result)
│ ├── server.py # MCP server (FastMCP, 101 tools, configurable stdio/streamable-http transport)
│ └── telnet_client.py # Async Telnet client with health check, auto-reconnect, command lock, state tracking
├── tests/ # Pytest test suite (one file per module)
├── doc/ # grandMA2 user manual (PDF)
├── connect.sh # Telnet connection script with auto-login
├── Makefile # Utility commands (server, log, test)
├── pyproject.toml # Project metadata and dependencies
└── .env.template # Environment variable templateDevelopment
Running Tests
make testOr directly:
uv run pytest -vRun a specific test file:
uv run pytest tests/test_playback.py -vDependencies
Package | Purpose |
| Model Context Protocol library |
| Environment variable loading |
| Async Telnet client |
| Testing framework (dev) |
| Async test support (dev) |
Architecture
The project has six layers:
Telnet Client (
src/telnet_client.py) -- Low-level async Telnet communication with the console. IncludesConnectionStatetracking (DISCONNECTED/CONNECTING/CONNECTED/RECONNECTING), health check probing, auto-reconnection with bounded exponential backoff (configurable retries and delay), health check TTL to skip redundant probes during rapid command sequences,asyncio.Lock-based command serialization for concurrent access safety, graceful shutdown via the server lifespan hook, and a verifiedexecute()that reads and checks the console reply.Command Builder (
src/commands/) -- Pure functions that construct command strings. No network access.Response Parser (
src/response_parser.py) -- Pure functions that parse grandMA2 Telnet output:Listtables into structured dicts (parsed: Falseon unrecognized formats), and inlineError #NNfailures viadetect_error()/strip_ansi().Execution Core (
src/execution.py) -- Purebuild_result()+ExecutionResult; turns a raw reply into{ok, echo, error_code, error_text, raw}so mutating tools report real outcomes.Orchestration (
src/gma2_client.py,src/command_sequence.py) -- High-level workflow methods (15 methods including music show workflows) and command batching that compose builders + telnet.MCP Server (
src/server.py) -- FastMCP server that exposes 101 tools over configurable transport (stdioorstreamable-http), connecting the builder to the Telnet client.
All console communication goes through the Telnet client layer.
Troubleshooting
Connection fails -- Verify the console IP and port. Ensure Telnet is enabled on the console. Test manually with make server.
Connection drops mid-session -- The Telnet client auto-reconnects with up to 3 retries (exponential backoff: 1s, 2s, 4s). If all retries fail, tools return a clear error message. Check that the console is running and reachable.
Authentication errors -- Check username/password in .env. Confirm the user account exists on the console. Login is case-sensitive.
Fixture setup locked by stale connection -- If a previous session crashed without calling disconnect(), the console may still hold a Telnet lock. Restart the console or wait for its session timeout. The MCP server now calls disconnect() on shutdown to prevent this.
Command not working -- Verify the syntax against the grandMA2 manual. Ensure referenced objects (fixtures, groups, presets) exist in the current show file.
License
This project is licensed under the Apache License 2.0. See LICENSE for details.
Contributing
Fork the repository
Create a feature branch (
git checkout -b feature/name)Commit your changes
Push to the branch and open a Pull Request
Run tests before submitting: make test
Available Tools
101 toolsadd_user_variableA
Add to / extend a user-profile-specific variable (AddUserVar).
Numeric values are summed; text values are concatenated.
Args:
var_name: Variable name (should start with $)
value: Value to add (numeric) or append (text)
Returns:
str: Operation result message
Inputs: var_name (required), value (required). Returns: result
add_variableA
Add to / extend a global show variable (AddVar).
Numeric values are summed; text values are concatenated.
Args:
var_name: Variable name (should start with $)
value: Value to add (numeric) or append (text)
Returns:
str: Operation result message
Inputs: var_name (required), value (required). Returns: result
align_selectionC
Align attribute values across the selected fixtures (fan first-to-last).
Inputs: target. Returns: result
appearance_cue_across_sequencesA
Set appearance (color) on a cue across a range of sequences.
Iterates over every sequence in the range and applies the color to the
specified cue. Supports RGB values (0-100) or hex color codes.
Args:
cue_id: Cue number (e.g., 1, 0.5)
sequence_start: First sequence number in the range
sequence_end: Last sequence number in the range (inclusive)
red: (Optional) Red component (0-100)
green: (Optional) Green component (0-100)
blue: (Optional) Blue component (0-100)
color: (Optional) Hex color code (e.g., "FF0000")
Returns:
dict: Result with commands_sent, count, and summary
Examples:
- Set cue 0.5 to black across sequences 101-125 (red=0, green=0, blue=0)
- Set cue 1 to red across sequences 101-103 (color="FF0000")
Inputs: cue_id (required), sequence_start (required), sequence_end (required), red, +3 more.
apply_effectB
Apply a predefined effect from the effect pool to the current fixture selection.
Fixtures must be selected first using set_fixture_value or create_fixture_group.
Args:
effect_id: Effect number from the effect pool
Returns:
str: Operation result message
Examples:
- Apply effect 5 to selected fixtures
Inputs: effect_id (required). Returns: result
apply_presetA
Apply an existing preset to the current selection.
Args:
preset_type: Preset type (dimmer, position, gobo, color, beam, focus, control, shapers, video)
preset_id: Preset number
Returns:
str: Operation result message
Examples:
- Apply color preset 3
- Apply position preset 1
Inputs: preset_type (required), preset_id (required). Returns: result
assign_appearanceA
Assign an appearance (frame/background color) to a grandMA2 pool object or cue.
Colors can be specified via RGB (0-100), HSB (hue 0-360, sat/bright 0-100),
hex color string, or by copying from a source object. Use reset to clear.
Args:
object_type: Object type (e.g., "group", "cue", "preset", "macro")
object_id: Object number or compound ID (e.g., 1 or "0.1")
end: (Optional) End ID for applying to a range of objects
source_type: (Optional) Source object type to copy appearance from
source_id: (Optional) Source object ID to copy appearance from
reset: Reset appearance to default
color: Hex color code (e.g., "FF0000") or gel name
red: Red component (0-100)
green: Green component (0-100)
blue: Blue component (0-100)
hue: Hue (0-360)
saturation: Saturation (0-100)
brightness: Brightness (0-100)
Returns:
str: Operation result message
Examples:
- Set group 1 to red: object_type="group", object_id=1, red=100, green=0, blue=0
- Set preset 0.1 to hex color: object_type="preset", object_id="0.1", color="FF0000"
- Copy appearance from macro 13 to macro 2: object_type="macro", object_id=2, source_type="macro", source_id=13
- Reset group 1 appearance: object_type="group", object_id=1, reset=True
Inputs: object_type (required), object_id (required), end, source_type, +9 more. Returns: result
assign_timecode_slotA
Assign a timecode show to a timecode slot for cue triggering.
Args:
tc_id: Timecode show ID
slot: Timecode slot number
Returns:
str: Operation result message
Inputs: tc_id (required), slot (required). Returns: result
assign_to_executorC
Assign a sequence to an executor.
Args:
sequence_id: Sequence number to assign
executor_id: Target executor number
Returns:
str: Operation result message
Examples:
- Assign sequence 1 to executor 6
Inputs: sequence_id (required), executor_id (required). Returns: result
build_color_paletteA
Build (or extend) a color preset palette for a fixture selection in one call.
For each color: selects ``target``, sets R/G/B/W, stores the preset (Global by
default), labels it, and sets its pool appearance swatch.
To extend an existing palette to a new fixture group without disturbing
already-stored values, pass that group as ``target`` and ``merge=True``.
Args:
target: A grandMA2 selection command (e.g. "Group 3", "Group 1 Thru 5").
colors: List of {id, name?, r, g, b, w?} with r/g/b/w in 0-100.
scope: "global" (default), "selective", or "universal".
merge: Merge into existing presets (non-destructive extend).
label: Apply each color's name as the preset label.
appearance: Set each preset's pool swatch from its color.
Returns:
str: Operation result message
Examples:
- Build a palette on LED Par: target="Group 3", colors=[{"id":7,"name":"Red","r":100,"g":0,"b":0}]
- Extend it to Wash: target="Group 4", merge=True, same colors
Inputs: target (required), colors (required), scope, merge, +2 more. Returns: result
build_preset_paletteA
Build a preset palette of any type from per-fixture-type value sets.
Generalizes color/beam/focus palette building: each preset carries one or
more targets (fixture selections), each with its own attribute values. The
first target uses ``scope``; subsequent targets of the same preset merge
(per-fixture-type accumulation into one preset).
Args:
preset_type: "color", "beam", "focus", "dimmer", "position", ...
presets: list of {id, name?, by_target: [{target, attrs}]} where target
is a selection command (e.g. "Fixture 101 Thru 128") and attrs is a
list of [attribute, value] pairs.
scope: "global" (default), "selective", or "universal".
merge: if True the first target also merges (extend an existing preset).
label: apply each preset's name as its label.
Returns:
str: Operation result message
Examples:
- Beam strobe across types: preset_type="beam", presets=[{"id":3,"name":"Strobe","by_target":[{"target":"Fixture 401 Thru 428","attrs":[["SHUTTER",50]]},{"target":"Fixture 201 Thru 215","attrs":[["MASTERSHUTTERSTROBE",21]]}]}]
Inputs: preset_type (required), presets (required), scope, merge, +1 more. Returns: result
build_set_listA
Create a set-list sequence with cue-to-macro links.
Stores a sequence, then for each song creates a cue and assigns a
macro trigger to its CMD field. Each song dict must contain:
cue_id (int): Cue number in the set-list sequence
macro_id (int): Macro to trigger via cue CMD
name (str): Name for the cue
Args:
sequence_id: Sequence number for the set list
sequence_name: Label for the set-list sequence
songs: List of song definition dicts
Returns:
str: Operation result message
Examples:
- Build a set list with 3 songs linking cues to macros
Inputs: sequence_id (required), sequence_name (required), songs (required). Returns: result
capabilitiesA
Report this server's version, registered tools, and profile schema version.
Machine-readable contract surface for the gma2-workflow startup self-check
(issue #85). Pure metadata: it does NOT open a console connection, so it is
intentionally not wrapped with ``@handle_connection_error``.
Returns:
dict: ``{version, tools (sorted), tool_count, profile_schema_version}``.
Inputs: no named parameters.
clear_programmerB
Clear the programmer.
Args:
mode: Clear mode - "all" (clear everything), "selection" (clear selection only),
"active" (clear active values only), or "default" (standard clear)
Returns:
str: Operation result message
Examples:
- Clear all programmer data
- Clear selection only
Inputs: mode. Returns: result
clone_fixturesA
Clone all programming from source fixture(s) to target fixture(s).
WARNING: mode="overwrite" replaces existing target programming.
Args:
source_fixture: Source fixture number (or start of range)
target_fixture: Target fixture number (or start of range)
source_end: Optional end of source range
target_end: Optional end of target range
mode: "default", "overwrite", or "merge"
Returns:
str: Operation result message
Inputs: source_fixture (required), target_fixture (required), source_end, target_end, +1 more. Returns: result
control_executorA
Control an executor (on, off, go, kill, toggle).
Args:
executor_id: Executor number
action: Action to perform: "on", "off", "go", "kill", or "toggle"
Returns:
str: Operation result message
Examples:
- Turn on executor 1
- Kill executor 3
- Go on executor 2
Inputs: executor_id (required), action (required). Returns: result
control_timecodeA
Control timecode playback/recording.
Args:
tc_id: Timecode show ID
action: One of "go" (play), "pause", "off" (stop), "top" (rewind),
or "record" (arm real-time event recording)
Returns:
str: Operation result message
Examples:
- Start timecode 1: action="go"
- Record events into timecode 1: action="record"
Inputs: tc_id (required), action (required). Returns: result
copy_objectA
Copy an object (or range) to a new location.
``source`` and ``target`` accept grandMA2 selection expressions: a single ID
or a range/list using thru / + / - (e.g. "1 thru 10", "1 + 3 + 5"), so a
whole range copies in one call.
Args:
object_type: Object type ("cue", "preset", "group", "sequence", "macro", ...)
source: Source selection expression
target: Target selection expression
mode: "default", "overwrite", or "merge"
Returns:
str: Operation result message
Examples:
- Copy cue 1 to cue 10: object_type="cue", source="1", target="10"
- Copy groups 1 thru 5 to 11: object_type="group", source="1 thru 5", target="11"
Inputs: object_type (required), source (required), target (required), mode. Returns: result
create_fixture_groupA
Create a group containing a specified range of fixtures.
This tool selects the specified range of fixtures and saves them as a group.
Optionally, a name can be assigned to the group.
Args:
start_fixture: Starting fixture number
end_fixture: Ending fixture number
group_id: Group number to save
group_name: (Optional) Group name, e.g., "Front Wash"
Returns:
str: Operation result message
Examples:
- Save fixtures 1 to 10 as group 1
- Save fixtures 1 to 10 as group 1 with name "Front Wash"
Inputs: start_fixture (required), end_fixture (required), group_id (required), group_name. Returns: result
create_macroA
Create a macro with command lines.
Stores an empty macro, then assigns each command to sequential lines.
Optionally labels the macro.
Args:
macro_id: Macro number to create
commands: List of command strings for each macro line
name: Optional label for the macro
pool: Macro pool number (default: 1)
Returns:
str: Operation result message
Examples:
- Create macro 10 with commands ["Go Sequence 1", "Go Sequence 2"]
- Create macro 10 named "Start Show" with one command
Inputs: macro_id (required), commands (required), name, pool. Returns: result
create_song_objectsA
Create and label a Sequence + Page pair for a song.
Stores a sequence and a page with the same ID and name, which is the
standard pattern for per-song programming in music show workflows.
Args:
song_id: ID for both the sequence and page
song_name: Name to assign to both objects
Returns:
str: Operation result message
Examples:
- Create sequence 101 and page 101 named "Opening+Childhood"
Inputs: song_id (required), song_name (required). Returns: result
create_timecode_poolA
Create a timecode show, optionally naming it and assigning a slot.
Standard SMPTE setup: store the timecode pool object, label it, and bind it
to a timecode slot for cue triggering. Timecode events themselves are
recorded in real time via control_timecode(action="record").
Args:
tc_id: Timecode show ID
name: Optional display name
slot: Optional timecode slot to assign
Returns:
str: Operation result message
Examples:
- Create timecode 1 named "Act 1" on slot 1
Inputs: tc_id (required), name, slot. Returns: result
delete_cueB
Delete a cue from the current sequence.
Args:
cue_id: Cue number to delete
Returns:
str: Operation result message
Examples:
- Delete cue 3
Inputs: cue_id (required). Returns: result
delete_fixtureC
Delete a fixture from the patch (destructive).
Inputs: fixture_id (required). Returns: result
delete_groupC
Delete a fixture group (destructive).
Inputs: group_id (required). Returns: result
delete_macro_toolA
Delete a macro from the macro pool.
WARNING: This is a destructive operation that permanently removes the macro.
Args:
macro_id: Macro number to delete
pool: Macro pool number (default: 1)
Returns:
str: Operation result message with warnings
Inputs: macro_id (required), pool. Returns: result
delete_presetB
Delete a preset (destructive). preset_type e.g. "color", "dimmer".
Inputs: preset_type (required), preset_id (required). Returns: result
delete_showB
Delete a show file from the console drive (destructive).
Inputs: show_name (required). Returns: result
execute_sequenceB
Execute sequence-related operations.
Args:
sequence_id: Sequence number
action: Operation type: "go" (execute), "pause" (pause), or "goto" (jump to cue)
cue_id: (Required for goto) Target cue number
Returns:
str: Operation result message
Examples:
- Execute sequence 1
- Pause sequence 2
- Jump to cue 5 of sequence 1
Inputs: sequence_id (required), action (required), cue_id. Returns: result
fix_selectionC
Fix (lock) the current fixture selection.
Inputs: target. Returns: result
flash_executorA
Flash an executor (momentary intensity bump) — a live busking control.
Args:
executor_id: Executor number
page: Optional page number for page-qualified addressing
mode: "flash" (momentary), "flash_on" (latching), or "flash_go" (flash and go)
Returns:
str: Operation result message
Inputs: executor_id (required), page, mode. Returns: result
get_cue_annotationA
read the user-added annotation text on a cue.
in grandMA2, the Info keyword reads or writes user-added descriptive text
annotations on objects. this tool reads the annotation. if no annotation has
been set on the cue, the response will be empty.
note: this does NOT return cue properties (fade time, values, etc.).
to see cue properties, use list_cues with a specific cue_id instead.
Args:
cue_id: cue ID to read annotation from
sequence_id: sequence containing the cue (optional)
Returns:
str: the user annotation text, or empty response message if none set
Inputs: cue_id (required), sequence_id. Returns: result
get_group_annotationA
read the user-added annotation text on a group.
in grandMA2, the Info keyword reads or writes user-added descriptive text
annotations on objects. this tool reads the annotation. if no annotation has
been set on the group, the response will be empty.
note: this does NOT return group composition or fixture details.
to see group details, use list_groups with a specific group_id instead.
Args:
group_id: group ID to read annotation from
Returns:
str: the user annotation text, or empty response message if none set
Inputs: group_id (required). Returns: result
goto_cue_toolA
Jump to a specific cue.
Targets either an executor or a sequence. If neither is specified,
the command applies to the selected executor.
Args:
cue_id: Target cue number
executor: (Optional) Executor number
sequence: (Optional) Sequence number
Returns:
str: Operation result message
Examples:
- Goto cue 5 on executor 4
- Goto cue 3 in sequence 1
Inputs: cue_id (required), executor, sequence. Returns: result
invert_selectionB
Invert the current fixture selection.
Inputs: no named parameters. Returns: result
label_cue_across_sequencesA
Label a cue across a range of sequences.
Iterates over every sequence in the range and labels the specified cue.
Args:
cue_id: Cue number to label (e.g., 1, 0.5)
sequence_start: First sequence number in the range
sequence_end: Last sequence number in the range (inclusive)
label: Label text to assign
Returns:
dict: Result with commands_sent, count, and summary
Examples:
- Label cue 0.5 across sequences 101-125 as "((LOADING SONG))"
Inputs: cue_id (required), sequence_start (required), sequence_end (required), label (required).
label_macro_toolB
Label a macro in the macro pool.
Args:
macro_id: Macro number to label
name: Label text for the macro
Returns:
str: Operation result message
Examples:
- Label macro 5 as "Blackout All"
Inputs: macro_id (required), name (required). Returns: result
label_objectA
Assign a name label to a grandMA2 object.
Args:
object_type: Object type (e.g., "group", "cue", "sequence", "macro", "preset")
object_id: Object number
name: Name to assign
Returns:
str: Operation result message
Examples:
- Label group 1 as "Front Wash"
- Label cue 5 as "Intro"
Inputs: object_type (required), object_id (required), name (required). Returns: result
label_sequence_cueA
Label a cue within a specific sequence.
This tool addresses cues through the sequence context, which is required
for labeling cues inside named sequences.
Args:
sequence: Sequence ID or name (e.g., "100" or "Set List")
cue_id: Cue number within the sequence
name: Label to assign
end_cue: (Optional) End cue for range labeling
Returns:
str: Operation result message
Examples:
- Label cue 1 in "Set List" as "Opening+Childhood"
- Label cue 1 in sequence 100 as "Opening+Childhood"
- Label cues 1 thru 5 in "Set List" as "Act 1"
Inputs: sequence (required), cue_id (required), name (required), end_cue. Returns: result
list_cuesB
list cues on the grandMA2 console.
lists cues of the selected executor, or a specific sequence if sequence_id is provided.
Args:
cue_id: specific cue ID or start of range (optional)
end_cue_id: end cue ID for range query (optional)
sequence_id: sequence to list cues from (optional)
Returns:
str: raw console response with cue listing
Inputs: cue_id, end_cue_id, sequence_id. Returns: result
list_groupsA
list all defined groups on the grandMA2 console.
returns raw console output from the List Group command.
Args:
group_id: specific group ID or start of range (optional)
end_group_id: end group ID for range query (optional, requires group_id)
Returns:
str: raw console response with group listing
Inputs: group_id, end_group_id. Returns: result
list_macrosA
List macros in the macro pool.
Returns raw console output from the List Macro command.
Returns:
str: Raw console response with macro listing
Inputs: no named parameters. Returns: result
list_presetsA
list presets of a given type on the grandMA2 console.
valid preset types: dimmer, position, gobo, color, beam, focus, control, shapers, video.
Args:
preset_type: type of preset (e.g. "color", "position", "dimmer")
preset_id: specific preset ID (optional)
Returns:
str: raw console response with preset listing
Inputs: preset_type (required), preset_id. Returns: result
list_shows_toolA
list available show files on the grandMA2 console.
Args:
filter: optional filter pattern (e.g. "Mac*" to list shows starting with Mac)
Returns:
str: raw console response with show file listing
Inputs: filter. Returns: result
list_variablesA
list show variables or user variables on the grandMA2 console.
Args:
variable_type: "show" for show variables (ListVar), "user" for user variables (ListUserVar)
filter: optional filter pattern (e.g. "f*" to list variables starting with f)
Returns:
str: raw console response with variable listing
Inputs: variable_type (required), filter. Returns: result
load_show_toolA
load a show file on the grandMA2 console.
WARNING: this is a DESTRUCTIVE operation. any unsaved changes to the current
show will be lost. set save_first=True to save the current show before loading.
Args:
show_name: name of the show file to load
save_first: if True, saves the current show before loading the new one
Returns:
str: confirmation message with warning about unsaved changes
Inputs: show_name (required), save_first. Returns: result
locate_fixturesB
Send the selected fixtures to home/default position (Locate).
Inputs: no named parameters. Returns: result
move_objectA
Move an object (or range) to a new location. WARNING: removes from source.
``source`` and ``target`` accept selection expressions (thru / + / -), so a
whole range moves in one call (e.g. move groups 1 thru 10 to 21).
Args:
object_type: Object type ("cue", "preset", "group", "sequence", "macro", ...)
source: Source selection expression
target: Target selection expression
Returns:
str: Operation result message
Inputs: object_type (required), source (required), target (required). Returns: result
new_show_toolA
create a new empty show on the grandMA2 console.
WARNING: this is a DESTRUCTIVE operation. any unsaved changes to the current
show will be lost. set save_first=True to save the current show before creating a new one.
note: per the grandMA2 manual, NewShow requires a show name. omitting the
name may work on some console versions but this behavior is undocumented.
providing a name is recommended.
Args:
show_name: name for the new show (recommended — required per official manual)
save_first: if True, saves the current show before creating a new one
Returns:
str: confirmation message with warning about unsaved changes
Inputs: show_name, save_first. Returns: result
next_fixtureA
Step to the next fixture in the current selection.
Inputs: no named parameters. Returns: result
park_fixtureA
Park DMX output (lock a value regardless of playback).
Args:
target: What to park (e.g. "fixture 1", "channel 5", "fixture 1 attribute dim").
Omit to park the current selection.
at_value: Optional value to park at (0-100); omit to park at current value.
Returns:
str: Operation result message
Inputs: target, at_value. Returns: result
previous_fixtureB
Step to the previous fixture in the current selection.
Inputs: no named parameters. Returns: result
query_objectA
generic query for any grandMA2 object type.
use this for object types without a dedicated tool (e.g. executors, sequences, effects).
for groups, cues, and presets, prefer the specific tools.
Args:
object_type: MA2 object type (e.g. "executor", "sequence", "effect", "macro")
object_id: object ID to query (optional)
mode: "list" to list objects, "annotation" to read user-added text annotation (default: "list").
note: "annotation" mode reads user-added descriptive text, NOT object properties.
Returns:
str: raw console response
Inputs: object_type (required), object_id, mode. Returns: result
query_timecodeA
Read timecode pool status / configuration.
Args:
tc_id: Specific timecode ID (optional; lists the whole pool if omitted)
Returns:
str: raw console response with timecode listing
Inputs: tc_id. Returns: result
read_cue_infoA
Read cue information for a specific cue in a sequence.
Retrieves and parses cue data including label, fade time, and CMD field.
Args:
sequence_id: Sequence ID containing the cue
cue_id: Cue ID (int or str for decimal cue numbers like "2.5")
Returns:
dict with parsed cue info and raw response
Inputs: sequence_id (required), cue_id (required).
read_macro_linesA
Read macro line content for a given macro.
Retrieves and parses all lines of a macro, returning each line's
number and command string.
Args:
macro_id: Macro ID to read
pool: Macro pool number (default 1)
Returns:
dict with parsed macro lines and raw response
Inputs: macro_id (required), pool.
read_object_labelA
Read the label/name of any grandMA2 show object.
Uses the generic list command to retrieve an object's name field.
Note: For macros, object_id must be pool-qualified (e.g., "1.5" for
Macro 5 in Pool 1) since grandMA2 addresses macros as pool.id.
For most other object types, a plain integer ID is sufficient.
Args:
object_type: Object type (e.g., "group", "sequence", "macro", "page")
object_id: Object ID (int for most types, or "pool.id" string for macros)
Returns:
dict with parsed label and raw response
Inputs: object_type (required), object_id (required).
release_executorC
Release an executor (clean removal from output, respecting tracking).
Args:
executor_id: Executor number
page: Optional page for page-qualified addressing
Returns:
str: Operation result message
Inputs: executor_id (required), page. Returns: result
reset_matricksA
Reset all MAtricks settings to defaults.
Inputs: no named parameters. Returns: result
run_macroA
Execute a macro by ID.
Starts the specified macro using the Go+ command.
Args:
macro_id: Macro number to execute
pool: Macro pool number (default: 1)
Returns:
str: Operation result message
Examples:
- Run macro 5 from default pool
- Run macro 10 from pool 2
Inputs: macro_id (required), pool. Returns: result
save_show_toolA
save the current show file on the grandMA2 console.
if no name is provided, saves under the current show name.
uses /noconfirm to suppress the overwrite confirmation popup
that would otherwise block Telnet when a show with the same name exists.
Args:
show_name: name to save the show as (optional)
Returns:
str: confirmation message
Inputs: show_name. Returns: result
send_midi_controlA
Send a MIDI control-change (CC) message via the MIDI Out port.
Args:
controller: Controller number (0-127)
value: Control value (0-127)
channel: MIDI channel; uses the Setup MSC channel if omitted
Returns:
str: Operation result message
Inputs: controller (required), value (required), channel. Returns: result
send_midi_noteA
Send a MIDI note message via the console's MIDI Out port.
Used to trigger external devices (video servers, audio, pyro, fog).
Args:
note: MIDI note number (0-127)
velocity: Note velocity (0-127); defaults to full (127) if omitted
channel: MIDI channel; uses the Setup MSC channel if omitted
off: If True, send note-off instead of note-on
Returns:
str: Operation result message
Inputs: note (required), velocity, channel, off. Returns: result
send_midi_programA
Send a MIDI program-change message via the MIDI Out port.
Args:
program: Program number (0-127)
channel: MIDI channel; uses the Setup MSC channel if omitted
Returns:
str: Operation result message
Inputs: program (required), channel. Returns: result
send_raw_commandA
Send a raw MA command to grandMA2.
This is a low-level tool that allows sending any grandMA2 command-line instruction.
It is recommended to use other high-level tools first; use this tool only when
special commands are needed.
Args:
command: Raw MA command to send
Returns:
str: Operation result message
Examples:
- blackout
- go+ executor 1.1
- store sequence 1 cue 1
Inputs: command (required). Returns: result
set_cue_cmdA
Assign a command to a cue's CMD field.
When the cue fires, the assigned command will execute automatically.
Common use: trigger a macro when a cue runs.
Args:
cue_id: Cue number
sequence_id: Sequence number
command: Command to execute when cue fires (e.g., "Macro 101")
Returns:
str: Operation result message
Examples:
- Set cue 1 in sequence 100 to trigger "Macro 101"
- Set cue 5 in sequence 200 to run "Go Sequence 10"
Inputs: cue_id (required), sequence_id (required), command (required). Returns: result
set_cue_timingA
Set fade/delay timing on a cue or the current selection.
Provide any subset (at least one required). ``target`` applies the timing to
a specific object (e.g. "cue 5" or "cue 5 sequence 2"); omit to apply to the
current programmer selection.
Args:
fade: Fade time (seconds)
delay: Delay time (seconds)
out_fade: Out-fade time (seconds)
out_delay: Out-delay time (seconds)
target: Optional target object string
Returns:
str: Operation result message
Inputs: fade, delay, out_fade, out_delay, +1 more. Returns: result
set_effect_envelopeB
Set effect envelope parameters (attack, decay, delay, fade) on the selection.
Provide any subset (at least one required).
Returns:
str: Operation result message
Inputs: attack, decay, delay, fade. Returns: result
set_effect_formA
Set the effect waveform for the current selection.
Args:
form: Waveform type — name (e.g., "sin", "ramp", "square") or number
Returns:
str: Operation result message
Examples:
- Set effect form to "sin"
- Set effect form to 6
Inputs: form (required). Returns: result
set_effect_phaseA
Set the effect phase offset for the current selection.
Args:
phase: Phase value in degrees (e.g., 0, 90, 180, 270)
Returns:
str: Operation result message
Inputs: phase (required). Returns: result
set_effect_rangeA
Set effect high and/or low values for the current selection.
At least one of high or low must be provided.
Args:
high: Effect high value (optional)
low: Effect low value (optional)
Returns:
str: Operation result message
Examples:
- Set effect range high=100, low=0
- Set only effect high to 80
Inputs: high, low. Returns: result
set_effect_secondsB
Set effect speed in seconds (alternative to BPM/Hz).
Inputs: value (required). Returns: result
set_effect_speedB
Set the effect speed for the current selection.
Args:
value: Speed value
unit: Speed unit — "bpm" (beats per minute) or "hz" (hertz)
Returns:
str: Operation result message
Examples:
- Set effect speed to 120 BPM
- Set effect speed to 2.5 Hz
Inputs: value (required), unit. Returns: result
set_effect_speed_groupC
Assign the effect to a speed group for synchronized control.
Inputs: group_id (required). Returns: result
set_effect_widthB
Set the effect width for the current selection.
Args:
width: Width value (percentage of cycle)
Returns:
str: Operation result message
Inputs: width (required). Returns: result
set_executor_faderB
Set an executor's fader level.
Args:
executor_id: Executor number
value: Fader value (0-100)
Returns:
str: Operation result message
Examples:
- Set executor 1 fader to 75%
Inputs: executor_id (required), value (required). Returns: result
set_executor_rateB
Control an executor's playback rate (live tempo matching).
Args:
executor_id: Executor number
mode: "set" (rate), "half", "double", or "reset" (1:1)
page: Optional page for page-qualified addressing
Returns:
str: Operation result message
Inputs: executor_id (required), mode, page. Returns: result
set_executor_speedB
Control an executor's playback speed (live tempo matching).
Args:
executor_id: Executor number
mode: "set" (speed), "half", or "double"
page: Optional page for page-qualified addressing
Returns:
str: Operation result message
Inputs: executor_id (required), mode, page. Returns: result
set_fixture_attributeB
Set a specific attribute on fixture(s).
First selects the fixture(s), then applies the attribute value.
Args:
fixture_id: Fixture number (or start of range)
attribute: Attribute name (e.g., "Pan", "Tilt", "Dimmer")
value: Value to set
end_fixture: (Optional) End fixture for range
Returns:
str: Operation result message
Examples:
- Set Pan to 128 on fixture 1
- Set Tilt to 50 on fixtures 1 thru 10
Inputs: fixture_id (required), attribute (required), value (required), end_fixture. Returns: result
set_fixture_valueA
Set fixture(s) to a dimmer value.
Args:
fixture_id: Fixture number (or start of range)
value: Dimmer percentage (0-100)
end_fixture: (Optional) End fixture for range
Returns:
str: Operation result message
Examples:
- Set fixture 1 to 75%
- Set fixtures 1 thru 10 to 50%
Inputs: fixture_id (required), value (required), end_fixture. Returns: result
set_macro_lineA
Set the command for a specific line within a macro.
Args:
macro_id: Macro number
line: Line number within the macro
command: The command string for that line (e.g., "SetVar $song='Opening+Childhood'")
pool: Macro pool number (default: 1)
Returns:
str: Operation result message
Examples:
- Set macro 101 line 1 to "SetVar $song='Opening+Childhood'"
- Set macro 50 line 3 in pool 2 to "Go Sequence 5"
Inputs: macro_id (required), line (required), command (required), pool. Returns: result
set_matricksA
Configure MAtricks for fan effects / selection-pattern manipulation.
Applies to the current fixture selection. Provide any subset of parameters;
they are sent together. At least one parameter is required.
Args:
blocks: Block size grouping
wings: Number of wings (symmetry)
groups: Number of groups
interleave: Interleave step
filter: MAtricks filter value
Returns:
str: Operation result message
Inputs: blocks, wings, groups, interleave, +1 more. Returns: result
set_step_timingB
Set step/chase timing parameters for the current selection.
Provide any subset (at least one required).
Args:
snap_percent: Snap percentage (hard-cut portion)
step_fade: Step fade time
step_in_fade: Step in-fade time
step_out_fade: Step out-fade time
fade_path: Fade path / curve value
Returns:
str: Operation result message
Inputs: snap_percent, step_fade, step_in_fade, step_out_fade, +1 more. Returns: result
setup_song_macroA
Create a macro that sets a user variable to the song name.
Stores a macro, labels it with the song name, and assigns a SetVar
command on line 1. This is used to track the current song in
music show workflows.
Args:
macro_id: Macro number to create
song_name: Song name used for label and variable value
var_name: Variable name for the SetVar command (default: "$song")
Returns:
str: Operation result message
Examples:
- Create macro 101 that sets $song to "Opening+Childhood"
Inputs: macro_id (required), song_name (required), var_name. Returns: result
set_user_variableB
Set a user-profile-specific variable (SetUserVar).
Args:
var_name: Variable name (should start with $)
value: Numeric, text, or None to delete the variable
input_dialog: If True (string values only), prompt with an input dialog
Returns:
str: Operation result message
Inputs: var_name (required), value, input_dialog. Returns: result
set_variableB
Set a global show variable (SetVar).
Args:
var_name: Variable name (should start with $, e.g. "$song")
value: Numeric, text, or None to delete the variable
input_dialog: If True (string values only), prompt the operator with an
input dialog instead of setting a fixed value
Returns:
str: Operation result message
Examples:
- Set $count to 5
- Set $song to "Opening"
- Delete $count (value=None)
Inputs: var_name (required), value, input_dialog. Returns: result
stomp_executorA
Stomp an executor (assertive playback, overrides lower priorities).
Args:
executor_id: Executor number
page: Optional page number for page-qualified addressing
Returns:
str: Operation result message
Inputs: executor_id (required), page. Returns: result
stop_effectsA
Stop all running effects for the current selection.
Removes effect values from the programmer using the Off command.
Returns:
str: Operation result message
Inputs: no named parameters. Returns: result
store_cueB
Store the current programmer state as a cue.
Args:
cue_id: Cue number to store
name: (Optional) Name for the cue
merge: Merge new values into existing cue
overwrite: Overwrite existing cue entirely
noconfirm: Suppress store confirmation pop-up
Returns:
str: Operation result message
Examples:
- Store cue 1
- Store cue 5 with name "Blackout" and merge enabled
Inputs: cue_id (required), name, merge, overwrite, +1 more. Returns: result
store_cue_across_sequencesA
Store a cue across a range of sequences.
Iterates over every sequence in the range and stores the specified cue.
Optionally assigns a name to each stored cue.
Args:
cue_id: Cue number to store (e.g., 1, 0.5)
sequence_start: First sequence number in the range
sequence_end: Last sequence number in the range (inclusive)
cue_name: (Optional) Name for the cue
Returns:
dict: Result with commands_sent, count, and summary
Examples:
- Store cue 0.5 across sequences 101-125 with name "((LOADING SONG))"
- Store cue 1 in sequence 101
Inputs: cue_id (required), sequence_start (required), sequence_end (required), cue_name.
store_presetA
Store current programmer values as a preset.
Use merge to ADD the current selection's values into an existing preset
without disturbing values already stored for other fixture types (the
non-destructive way to extend a global palette to a new fixture group).
Args:
preset_type: Preset type (dimmer, position, gobo, color, beam, focus, control, shapers, video)
preset_id: Preset number
scope: (Optional) Scope: "global", "selective", or "universal"
merge: Merge into the existing preset (keeps other fixtures' stored values)
overwrite: Overwrite the existing preset entirely
Returns:
str: Operation result message
Examples:
- Store color preset 1
- Store global dimmer preset 5
- Extend global color preset 7 to the current selection: merge=True
Inputs: preset_type (required), preset_id (required), scope, merge, +1 more. Returns: result
swop_executorA
Swop an executor (solo with blackout on others) — a live busking control.
Args:
executor_id: Executor number
page: Optional page number for page-qualified addressing
mode: "swop" (momentary), "swop_on" (latching), or "swop_go" (swop and go)
Returns:
str: Operation result message
Inputs: executor_id (required), page, mode. Returns: result
sync_effects_toolA
Synchronize all running effects.
Resets effect timing so all running effects align their phase.
Returns:
str: Operation result message
Inputs: no named parameters. Returns: result
temp_executorC
Temporarily activate an executor (Temp).
Args:
executor_id: Executor number
page: Optional page number for page-qualified addressing
Returns:
str: Operation result message
Inputs: executor_id (required), page. Returns: result
toggle_blackoutB
Toggle the grand blackout state.
Returns:
str: Operation result message
Inputs: no named parameters. Returns: result
toggle_blindA
Toggle blind editing mode (edit cues without affecting stage output).
Args:
executor_id: Optional executor to toggle blind for (global if omitted)
page: Optional page for page-qualified executor addressing
edit_mode: If True, toggle blind-edit mode (global) instead
Returns:
str: Operation result message
Inputs: executor_id, page, edit_mode. Returns: result
toggle_highlightA
Toggle highlight mode for fixture programming.
Returns:
str: Operation result message
Inputs: no named parameters. Returns: result
toggle_previewB
Toggle preview mode (visualize output without affecting DMX).
Args:
executor_id: Optional executor to toggle preview for (global if omitted)
page: Optional page for page-qualified executor addressing
edit_mode: If True, toggle preview-edit mode (global) instead
Returns:
str: Operation result message
Inputs: executor_id, page, edit_mode. Returns: result
top_executorC
Set an executor to top priority (Top).
Args:
executor_id: Executor number
page: Optional page for page-qualified addressing
Returns:
str: Operation result message
Inputs: executor_id (required), page. Returns: result
unpark_fixtureA
Unpark previously parked DMX output.
Args:
target: What to unpark (e.g. "fixture 1"); omit for the current selection.
Returns:
str: Operation result message
Inputs: target. Returns: result
update_cueA
Update an existing cue with current programmer values (Update).
Unlike store, Update merges programmer changes into an existing cue without
re-storing. WARNING: this modifies existing programming.
Args:
cue_id: Cue number to update
sequence_id: Optional sequence the cue belongs to
merge: Add /merge flag
cueonly: Add /cueonly flag (do not track changes forward)
tracking: Add /tracking flag
Returns:
str: Operation result message
Inputs: cue_id (required), sequence_id, merge, cueonly, +1 more. Returns: result
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 101 tools
Most tools target distinct object/action pairs with detailed descriptions, but there are several overlapping boundaries: label_object vs label_macro_tool vs label_sequence_cue, set_effect_speed vs set_effect_seconds, goto_cue_tool vs execute_sequence(goto), and multiple store/update cue variants. An agent would often need to read full descriptions to avoid picking the wrong tool.
A loose verb_noun pattern exists, but it is inconsistently applied: some tools have a random _tool suffix (save_show_tool, delete_macro_tool, sync_effects_tool), some use non-verb forms (temp_executor, next_fixture, appearance_cue_across_sequences), and similar operations use different verbs (list_groups vs list_shows_tool, read_cue_info vs get_cue_annotation). The naming feels ad hoc rather than systematic.
101 tools is far beyond any reasonable scope for a focused MCP server. Even for a broad grandMA2 console integration, this count is excessive and creates high selection and maintenance overhead.
The tool surface covers core workflows comprehensively: cues, presets, macros, effects, executors, variables, timecode, MIDI, show files, and palette building. Notable gaps exist around patch/fixture creation (only delete_fixture is provided) and generic sequence lifecycle, but send_raw_command provides a workaround for these edge cases.
Maintenance
Related MCP Connectors
Nifty's MCP server — exposes tasks, projects, messages, and files as tools for AI agents.
Hosted MCP server connecting AI assistants to 9,000+ apps and 40,000+ actions via Zapier.
Remote MCP server exposing your Node Command fleet (files, shell, processes, browser) to AI hosts.
One MCP server for the services your AI needs: memory, files, Microsoft 365, kanban and more.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceHigh-performance MCP server that enables AI assistants to control TouchDesigner live via WebSocket, providing 37 tools for nodes, parameters, scripting, and more.5MIT
- 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
- FlicenseBqualityDmaintenanceMCP server for controlling Ableton Live, enabling AI assistants to interact with Live sessions through tools for track/clip/scene management, playback control, and device parameter adjustments.48-
- AlicenseAqualityBmaintenanceEnables MCP clients such as Claude Code or Claude Desktop to control grandMA3 onPC by executing command-line commands, running Lua, reading show data like sequences, cues, executors, patch and pools, driving playback and faders, and looking things up in the manual. It works through a Lua bridge plugin inside onPC, falling back to OSC for write-only commands when the bridge is unavailable.754MIT