# Grandma2 Mcp

> MCP server for grandMA2 with 218 tools for console control, programming, orchestration, and browser-based operation.

- **Type:** MCP server
- **Install:** `agentstack add mcp-drohi-r-grandma2-mcp`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [drohi-r](https://agentstack.voostack.com/s/drohi-r)
- **Installs:** 0
- **Category:** [Web & Browser](https://agentstack.voostack.com/c/web-and-browser)
- **Latest version:** 0.1.0
- **License:** Apache-2.0
- **Upstream author:** [drohi-r](https://github.com/drohi-r)
- **Source:** https://github.com/drohi-r/grandma2-mcp
- **Website:** https://ecube-entertainment.com/

## Install

```sh
agentstack add mcp-drohi-r-grandma2-mcp
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

---
title: grandMA2 MCP
description: MCP server for grandMA2 lighting consoles — 218 MCP tools via Telnet
version: 1.1.0
created: 2026-04-02T00:00:00Z
last_updated: 2026-04-04T00:00:00Z
---

  

# grandMA2 MCP

  
  
  
  
  

> Forked from [thisis-romar/ma2-onPC-MCP](https://github.com/thisis-romar/ma2-onPC-MCP) (originally built by [chienchuanw](https://github.com/chienchuanw)) — hardened and maintained by [@drohi-r](https://github.com/drohi-r).

**An MCP server for [grandMA2](https://www.malighting.com/grandma2/) lighting consoles.** Exposes 218 grandMA2 operations as [Model Context Protocol](https://modelcontextprotocol.io/) tools so AI assistants (Claude Desktop, VS Code, etc.) can drive a lighting console via Telnet. Includes a built-in orchestrator, task decomposer, and long-term memory for fully autonomous lighting control.

Built for live production. Pairs with [Resolume MCP](https://github.com/drohi-r/resolume-mcp), [MADRIX MCP](https://github.com/drohi-r/madrix-mcp), [Companion MCP](https://github.com/drohi-r/companion-mcp), and [Beyond MCP](https://github.com/drohi-r/beyond-mcp) for full AI-driven show control.

Agent Harness218 MCP tools covering every grandMA2 operation — playback, programming, user management, show files, busking, and more. Connect any MCP-compatible AI assistant and start controlling the console immediately.
Embedded Agent CoreOrchestrator, task decomposer, working + long-term memory, and a skill registry with self-improvement suggestions. Inject a real LLM client and it becomes a fully autonomous lighting agent that plans, executes, remembers, and learns.
Layered safety gateThree risk tiers enforced before any command reaches the console: SAFE_READ (always allowed), SAFE_WRITE (standard mode), DESTRUCTIVE (blocked until confirm_destructive=True). Line-break injection rejected at the transport layer.
A closed learning loopEvery tool call recorded to tool_invocations. SkillImprover surfaces repair suggestions from failure patterns and promotion candidates from high-quality sessions. Skills are versioned playbooks with full lineage tracking.
RAG-powered knowledgeThree indexed sources: this repo, ~1,043 grandMA2 help pages, and the MCP SDK. Semantic search via GitHub Models embeddings; falls back to keyword search without an API token.

[Quick Start](#quick-start) · [Architecture](#architecture) · [218 MCP Tools](#mcp-tools) · [Resources](#mcp-resources) · [Prompts](#mcp-prompts) · [Skills](#agent-skills) · [Safety System](#safety-system) · [RAG Pipeline](#rag-pipeline)

---

## Quick start

```bash
# 1. Install
git clone https://github.com/drohi-r/grandma2-mcp && cd grandma2-mcp
uv sync

# 2. Configure
cp .env.template .env        # then edit with your console IP

# 3. Install git hooks (auto-updates RAG index on every commit)
make install-hooks

# 4. Run
uv run python -m src.server  # starts MCP server (stdio transport)
```

For the local browser UI:

```bash
uv run python -m src.ui
```

Then open `http://127.0.0.1:8092`.

For a live console target, run the UI with the same connection env vars as the MCP server:

```bash
GMA_HOST=192.168.20.179 GMA_PORT=30000 GMA_AUTH_BYPASS=1 uv run python -m src.ui
```

The browser UI is an operator console for:
- dashboard and console session status
- single-slot executor lookup
- direct sequence inspection
- patch browsing grouped by fixture type
- expectation analysis and agent plan/run flows

Important behavior notes:
- executor lookup is intentionally single-slot only; the UI does not bulk-scan executor ranges by default
- direct sequence IDs are more reliable than executor-based sequence resolution
- empty executor slots can produce normal MA2 `NO OBJECTS FOUND FOR LIST` warnings on the console
- fixture grouping on the Patch view is parsed from live `list fixture` output, not inferred from a full executor scan

> [!TIP]
> **Semantic search:** Add `GITHUB_MODELS_TOKEN=ghp_...` to `.env`, then run
> `uv run python scripts/rag_ingest.py --provider github` once to rebuild the index with
> real embeddings. The `search_codebase` MCP tool will automatically use semantic ranking
> when the token is present.

## Architecture

```mermaid
graph TD
    H["🤖 Agent Core Layersrc/server_orchestration_tools.py34 tools (IDs 110–144, excluding 130) · orchestrator · skills"] --> A
    A["🎭 MCP Server Layersrc/server.py184 server tools · safety gate"] --> B
    B["🧭 Navigation Layersrc/navigation.pycd · list · scan · set_property"] --> C
    C["🔧 Command Builderssrc/commands/198 pure functions → strings"] --> D
    D["📡 Telnet Clientsrc/telnet_client.pyasync · auth · injection prevention"]

    E["📖 Prompt Parsersrc/prompt_parser.pyprompt detection · list parsing"] -.-> B
    F["🛡️ Vocabulary & Safetysrc/vocab.py157 keywords · risk tiers"] -.-> A
    G["🔍 RAG Pipelinerag/crawl → chunk → embed → query"] -.-> A
    I["🧠 Memory & Planningsrc/agent_memory.py · src/orchestrator.pyWorkingMemory · LTM · TaskDecomposer"] -.-> H
    J["📊 OpenSpacesrc/telemetry.py · src/skill.py · src/skill_improver.pyinvocation recorder · skill registry · improvement loop"] -.-> H

    style H fill:#1a1a2e,stroke:#e94560,color:#fff
    style A fill:#1a1a2e,stroke:#e94560,color:#fff
    style B fill:#1a1a2e,stroke:#0f3460,color:#fff
    style C fill:#1a1a2e,stroke:#16213e,color:#fff
    style D fill:#1a1a2e,stroke:#533483,color:#fff
    style E fill:#0f3460,stroke:#0f3460,color:#fff
    style F fill:#0f3460,stroke:#0f3460,color:#fff
    style G fill:#0f3460,stroke:#0f3460,color:#fff
    style I fill:#0f3460,stroke:#0f3460,color:#fff
    style J fill:#0f3460,stroke:#0f3460,color:#fff
```

> All network I/O is isolated in `telnet_client.py`. Command builders are pure functions that return strings. The navigation layer orchestrates cd/list workflows with parsed telnet feedback.

### Agent Harness vs. Agent Core

grandMA2 MCP is a **layered hybrid** — the boundary is explicit in the code:

| Layer | What it is | Key files |
|-------|-----------|-----------|
| **Bottom 184 server tools** | **Agent Harness** — exposes the core MCP tool surface to an external AI; the reasoning loop lives in Claude Desktop, VS Code, etc. | `src/server.py` |
| **Top 34 orchestration tools** | **Embedded Agent Core** — orchestrator, task decomposer, long-term memory, skill registry | `src/server_orchestration_tools.py`, `src/orchestrator.py` |

The orchestrator accepts a `sub_agent_fn` injection point. Without it, tool calls run in-process. Wire in a Claude API client and grandMA2 MCP becomes a fully autonomous agent that plans, executes, remembers, and improves itself.

### Module Overview

| Module | Role |
|--------|------|
| `src/server.py` | FastMCP server, 184 interactive tools, safety gate, env config |
| `src/server_orchestration_tools.py` | 34 agentic tools (IDs 110–144, excluding 130) registered onto FastMCP |
| `src/orchestrator.py` | Multi-agent task runner: hydration, risk-tier isolation, LTM; `_showfile_guard()`, `check_showfile()` for dynamic show change detection |
| `src/task_decomposer.py` | Natural-language goal → ordered SubTask plan (rule-based) |
| `src/agent_memory.py` | WorkingMemory (ephemeral) + LongTermMemory (SQLite session log) + showfile baseline tracking (`baseline_showfile`, `showfile_changed()`) |
| `src/console_state.py` | ConsoleStateSnapshot: hydrates 19 show-memory gaps; `parse_showfile_from_listvar()` |
| `src/pool_name_index.py` | In-memory pool name/ID registry — zero-cost object resolution |
| `src/rights.py` | MA2 native rights enforcement + telnet feedback classification |
| `src/auth.py` | OAuth 2.1 scope enforcement (`@require_scope`, `@require_ma2_right`) |
| `src/credentials.py` | OAuth tier → console user credential resolver |
| `src/session_manager.py` | Per-operator Telnet session pool (LRU, keepalive, auto-reconnect) |
| `src/navigation.py` | cd + list + scan orchestration |
| `src/prompt_parser.py` | Parse console prompts and `list` tabular output |
| `src/vocab.py` | 157 keywords, `RiskTier`, `FunctionalDomain`, safety classification |
| `src/commands/` | 198 exported command-builder functions, grouped by keyword type |
| `src/commands/busking.py` | 6 busking/performance builders: effect assign, rate/speed, page release, fader zero |
| `src/categorization/` | ML tool categorization: K-Means clustering + auto-labeling |
| `src/telemetry.py` | Per-tool invocation recorder: `tool_invocations` table, latency, risk tier |
| `src/skill.py` | `Skill` dataclass + `SkillRegistry`: versioned playbooks with lineage + filesystem skill fallback (`_load_filesystem_skill`, `_list_filesystem_skills`) |
| `src/skill_improver.py` | `SkillImprover`: repair suggestions + promotion candidates (read-only) |
| `src/tools.py` | Global GMA2 telnet client accessor — `get_client()` used by all tools |

## Configuration

Create a `.env` file (see `.env.template`):

```env
# grandMA2 Console
GMA_HOST=192.168.1.100     # grandMA2 console IP (required)
GMA_USER=administrator     # default: administrator
GMA_PASSWORD=admin         # default: admin
GMA_PORT=30000             # default: 30000 (30001 = read-only)
GMA_SAFETY_LEVEL=standard  # standard (default), admin, or read-only
LOG_LEVEL=INFO             # default: INFO

# RAG Pipeline (optional)
GITHUB_MODELS_TOKEN=                          # GitHub PAT with models:read scope
RAG_EMBED_MODEL=openai/text-embedding-3-small # embedding model
RAG_EMBED_DIMENSIONS=1536                     # vector dimensions
```

> [!NOTE]
> Get a GitHub PAT with the `models:read` scope at [github.com/settings/tokens](https://github.com/settings/tokens).

| Level | Behavior |
|-------|----------|
| `read-only` | Only `SAFE_READ` commands allowed (`list`, `info`, `cd`) |
| `standard` | `SAFE_READ` + `SAFE_WRITE` allowed; `DESTRUCTIVE` requires `confirm_destructive=True` |
| `admin` | All commands allowed without confirmation |

## MCP Tools

The server exposes **218 tools** to MCP clients, grouped into 15 categories plus an agentic orchestration layer:

🧭 Navigation & Inspection — 4 tools

| Tool | Description |
|------|-------------|
| `navigate_console` | Navigate the console object tree via ChangeDest (cd) |
| `get_console_location` | Query the current console destination without navigating |
| `list_console_destination` | List objects at the current destination with parsed entries |
| `scan_console_indexes` | Batch scan numeric indexes at any tree level |

```
cd /            → go to root
cd ..           → go up one level
cd Group.1      → navigate to Group 1 (dot notation)
cd 5            → navigate by element index
cd "MySeq"      → navigate by name
list            → enumerate objects at current destination
```

**Dot notation:** MA2 uses `[object-type].[object-id]` for object references (e.g., `Group.1`, `Preset.4.1`, `Sequence.3`).

💡 Lighting Control — 7 tools

| Tool | Description |
|------|-------------|
| `set_intensity` | Set dimmer level on fixtures, groups, or channels |
| `set_attribute` | Set attribute values (Pan, Tilt, Zoom, etc.) on fixtures/groups |
| `apply_preset` | Apply a stored preset (color, position, gobo, beam, etc.) |
| `clear_programmer` | Clear programmer state (all, selection, active, or sequential) |
| `park_fixture` | Park a fixture/channel at its current or a specified value |
| `unpark_fixture` | Release a park lock on a fixture/channel |
| `fix_locate_fixture` | Fix (park) or Locate selected/specified fixtures at their defaults |

🎯 Programmer / Selection — 8 tools

| Tool | Description |
|------|-------------|
| `modify_selection` | Select, deselect, or toggle fixtures in the programmer |
| `adjust_value_relative` | Adjust programmer values relatively (+ or –) |
| `manipulate_selection` | Invert or Align the current fixture selection / programmer values |
| `select_fixtures_by_group` | Select all fixtures in a named group |
| `select_executor` | Set the active executor for subsequent operations (single-selection only; use deselect=True to clear) |
| `select_feature` | Set active Feature context (updates `$PRESET`/`$FEATURE`/`$ATTRIBUTE`) |
| `select_preset_type` | Activate a PresetType context (PresetType 1–9 or by name) |
| `if_filter` | Apply an IfOutput / IfActive filter to limit programmer scope |

▶️ Playback & Executor — 9 tools

| Tool | Description |
|------|-------------|
| `execute_sequence` | Legacy sequence playback: go, pause, or goto cue |
| `playback_action` | Full playback: go, go_back, goto, fast_forward, fast_back, def_go, def_go_back, def_pause |
| `control_executor` | Control an executor (go, pause, stop, flash, etc.) |
| `load_cue` | Pre-load the next or previous cue on an executor without firing it |
| `get_executor_status` | Query status of an executor (current cue, level, state) |
| `set_executor_level` | Set the fader level on an executor |
| `navigate_page` | Navigate to a specific page or page +/– |
| `release_executor` | Release (deactivate) an executor |
| `blackout_toggle` | Toggle grandmaster blackout on/off |

playback_action — parameters &amp; response fields

#### Parameters

| Parameter | Type | Description |
|-----------|------|-------------|
| `action` | `str` | One of the actions below |
| `object_type` | `str \| None` | Object type for `go`/`go_back` (e.g. `"executor"`, `"sequence"`) |
| `object_id` | `int \| list[int] \| None` | ID or list of IDs — list produces `N + M + …` syntax |
| `cue_id` | `int \| float \| None` | Required for `"goto"` |
| `end` | `int \| None` | End of range for `go`/`go_back` (builds `thru N`) |
| `cue_mode` | `str \| None` | `"normal"`, `"assert"`, `"xassert"`, or `"release"` |
| `executor` | `int \| list[int] \| None` | Executor ID(s) for `goto`/`fast_forward`/`fast_back` — list produces `N + M + …` |
| `sequence` | `int \| None` | Sequence ID for `goto`/`fast_forward`/`fast_back` |

#### Actions

| Action | Command sent | Notes |
|--------|-------------|-------|
| `"go"` | `go [object_type] [id]` | Fires next cue; `object_id` accepts a list |
| `"go_back"` | `goback [object_type] [id]` | Fires previous cue; `object_id` accepts a list |
| `"goto"` | `goto cue N [executor/sequence]` | Pre-flight validates cue exists; returns `blocked=True` on Error #72 |
| `"fast_forward"` | `>>> [executor N]` | `executor` accepts a list |
| `"fast_back"` | `>> executor 2 + 4

# Go back on the selected executor — response tells you which one fired
playback_action(action="def_go_back")
# → {"command_sent": "defgoback", "selected_executor": "5", "selected_cue_before": "3"}
```

select_executor — parameters &amp; response fields

**Single-selection only.** MA2 telnet `select executor N` accepts exactly one executor number. There is no list syntax — pass a single `executor_id` integer.

#### Parameters

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `executor_id` | `int` | required | Executor number (1–999) |
| `page` | `int \| None` | `None` | Page number — produces `select executor page.id` (e.g. `page=2, executor_id=5` → `select executor 2.5`) |
| `deselect` | `bool` | `False` | If `True`, sends bare `select` to clear the current selection (**unverified on grandMA2 telnet** — inspect `raw_response`) |

#### Response fields

| Field | Always present | Description |
|-------|---------------|-------------|
| `command_sent` | ✓ | The exact command sent |
| `raw_response` | ✓ | Raw telnet reply |
| `confirmed_selected_exec` | ✓ | Value of `$SELECTEDEXEC` read after the command (`null` if unavailable) |
| `risk_tier` | ✓ | `"SAFE_WRITE"` |
| `warning` | if mismatch | Present when `confirmed_selected_exec` doesn't match the requested `executor_id` |
| `note` | if deselect | Present when `deselect=True` — warns that bare `select` behaviour is unverified |

#### Page-qualified addressing

When `page` is supplied, MA2 stores `$SELECTEDEXEC` as the executor number only (not the page-qualified form). The confirmation check compares against `executor_id` alone — no spurious warning.

#### Examples

```python
# S

…

## Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [drohi-r](https://github.com/drohi-r)
- **Source:** [drohi-r/grandma2-mcp](https://github.com/drohi-r/grandma2-mcp)
- **License:** Apache-2.0
- **Homepage:** https://ecube-entertainment.com/

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** yes
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/mcp-drohi-r-grandma2-mcp
- Seller: https://agentstack.voostack.com/s/drohi-r
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
