Unilighter Desktop features a built-in **Model Context Protocol (MCP)** server, allowing external AI coding assistants and autonomous agents (such as Cursor, Claude Desktop, Google Antigravity, and custom LLM workflows) to directly connect to, inspect, author, and busk live lighting shows inside the running application.

> [!IMPORTANT]
> **Pro Subscription & Desktop App Requirement**:
> - **Pro Plan**: The built-in MCP server is available exclusively for **Unilighter Pro** subscribers.
> - **Unilighter Desktop Exclusive**: Due to web browser sandbox limitations (browsers cannot open raw local listening HTTP sockets on the host OS), the MCP server operates exclusively inside the **Unilighter Desktop** application.

> [!TIP]
> **Use AI Capabilities Without the AI Add-on**:
> Connecting external coding assistants and AI agents (Cursor, Claude Desktop, Antigravity, or your own local/cloud LLMs) via MCP is an outstanding way to leverage full AI lighting design, patching, and cue authoring using your existing AI subscriptions or API keys — **without needing to purchase the Unilighter cloud AI Add-on**.

---

## 🧠 What is Unilighter MCP?

The Model Context Protocol (MCP) is an open standard that connects AI agents to external applications and tool ecosystems. 

Unilighter Desktop implements a local **Streamable HTTP** MCP server on loopback (`127.0.0.1`). When enabled, an external AI agent can:
- **Patch Fixtures**: Read fixture profiles, compute DMX footprints, and patch multi-fixture arrays across universes with semantic tags (`#Beams`, `#Washes`).
- **Compose Lighting Scenes**: Dial in dimmers, RGB/CMY color palettes, and moving head positions, or capture live looks into stored scenes.
- **Program Complex Animations**: Build step chases with tempo-locked beats and author multi-track keyframe timelines with easing curves.
- **Wire Node Graphs**: Instantiate audio FFT analyzers, LFO generators, and math routing nodes, connecting wires directly into fixture channels.
- **Live Busking & Inspection**: Read real-time 512-channel DMX output per universe with winning priority sources, and adjust manual override faders at priority `100`.

---

## 🔒 Security & Architecture Split

The MCP integration is architected with strict security boundaries and human-in-the-loop safety:

1. **Loopback & Bearer Token Authentication**:
   - The server binds exclusively to IPv4 loopback (`127.0.0.1`, default port `3847`). It never exposes ports to external network interfaces.
   - Every request requires a cryptographically secure Bearer token generated per installation and persisted in local application data (`mcp-auth.json`).
   - Cross-origin browser requests are strictly filtered by origin headers.

2. **Host / Client Separation**:
   - **Desktop Shell (Bun runtime)**: Acts as a lightweight transport host handling HTTP sessions, JSON-RPC envelopes, and request timeouts (60s).
   - **Client App (Vue/Pinia)**: Owns the business logic, parameter validation, show databases, and live DMX state. Tool calls run through the exact same code paths as physical user clicks.

3. **Human-in-the-Loop Confirmation**:
   - Screen navigation operations (`context.navigate` or `*.open`) prompt an interactive confirmation modal in the app before switching views.
   - If the operator clicks **Cancel**, the agent receives a `user_declined` status code and gracefully stops without retrying in a loop.

---

## 🛠️ The 4 Core MCP Tools

Rather than registering hundreds of individual operations that overwhelm an agent's context window, Unilighter provides a clean, hierarchical CLI-style meta-tool interface:

### 1. `unilighter_help`
Discovers available modules and operations dynamically.
- Call with no arguments to get the list of all available show modules.
- Call with a specific module path (e.g. `{"path": "scenes"}`) to list operations.
- Call with a specific operation path (e.g. `{"path": "scenes.create"}`) to retrieve full argument schemas and typing requirements.

### 2. `unilighter_invoke`
Executes an operation by path with structured JSON arguments.
```json
{
  "path": "scenes.create",
  "args": {
    "name": "Warm Sunset Wash",
    "capture": true,
    "priority": 10,
    "fadeTime": 1500
  }
}
```

### 3. `unilighter_troubleshoot`
Provides instant diagnostic guidance and recommended repair workflows when an operation encounters an error or state conflict.

### 4. `unilighter_feedback`
Allows agents to log documentation gaps or missing API features directly to `userData/mcp-feedback.jsonl` for ongoing console improvements.

---

## 📚 Module Operations Catalog

| Module | Purpose | Key Operations |
| :--- | :--- | :--- |
| **`context`** | App & Navigation State | `context.get` (current route, open project), `context.navigate` (switch screen with user confirm) |
| **`project`** | Project Management | `project.list`, `project.open`, `project.create`, `project.save`, `project.update` (BPM, venue metadata) |
| **`fixtures`** | Profile Library Editor | `fixtures.list`, `fixtures.get`, `fixtures.create`, `fixtures.addMode`, `fixtures.addChannel`, `fixtures.setChannels` |
| **`devices`** | DMX Patching | `devices.list`, `devices.get`, `devices.create` (multi-patch with auto-addressing), `devices.update` (tags, address) |
| **`scenes`** | Static Cues | `scenes.list`, `scenes.get`, `scenes.create` (with live look capture), `scenes.apply`, `scenes.unset` |
| **`animations`** | Step & Keyframe Cues | `animations.create` (`step` or `keyframe`), `animations.addStep`, `animations.addTrack`, `animations.addKeyframe`, `animations.play`, `animations.stop` |
| **`graphs`** | Visual Node Graphs | `graphs.create`, `graphs.addNode`, `graphs.connect`, `graphs.setEnabled`, `graphs.get` (topology & wires) |
| **`universes`** | Output Routing | `universes.list`, `universes.read` (512 raw channel values + winning priority sources), `universes.create` |
| **`device-control`** | Live Manual Busking | `device-control.get`, `device-control.set` (Priority 100 manual look), `device-control.release` |
| **`controls`** | Priority Stack Inspector | `controls.list` (active property stacks), `controls.release` (clear specific priority overrides) |

---

## 🚀 Quick Start: Connecting Your AI Agent

Connecting Cursor, Claude Desktop, or custom agent frameworks to Unilighter Desktop takes just a few clicks:

### Prerequisites
1. **Unilighter Pro Plan**: An active Pro subscription is required to unlock the MCP server toggle.
2. **Unilighter Desktop App**: Download and run the native desktop version on Linux, macOS, or Windows.

### 1. Enable the MCP Server in Settings
1. Open **Unilighter Desktop**.
2. Click the **Settings** icon (`⚙️`) in the top navigation bar.
3. Locate the **MCP** section.
4. Toggle **Enable local MCP server**.
5. Once running, Unilighter displays the active endpoint URL, the Bearer token, and the pre-generated agent prompt.

---

### 2. Connect Your Agent

#### Method A: One-Click Prompt (Zero Manual Config — Recommended)
You don't need to manually write or edit configuration files:
1. In the MCP settings card, click **Copy agent prompt** (or copy the text directly from the prompt textarea).
2. Paste the prompt directly into your AI assistant's chat (Cursor Agent, Claude Desktop, Antigravity, etc.).
3. The prompt automatically instructs the agent:
   - How to connect to the Streamable HTTP endpoint (`http://127.0.0.1:3847/mcp`).
   - The private Bearer authentication token.
   - The hierarchical `unilighter_help` discovery workflow and parameter rules.
4. The AI agent configures its connection automatically and starts working immediately!

#### Method B: Manual Configuration (Optional)
If your environment requires static configuration files or command-line setup, use the verified configurations below:

**1. Cursor (`.cursor/mcp.json`):**
```json
{
  "mcpServers": {
    "unilighter": {
      "url": "http://127.0.0.1:3847/mcp",
      "headers": {
        "Authorization": "Bearer YOUR_TOKEN_HERE"
      }
    }
  }
}
```

**2. OpenAI Codex CLI & Operator:**
Codex natively supports Streamable HTTP MCP servers via the built-in `codex mcp` command:
```bash
# Add server via CLI
export UNILIGHTER_MCP_TOKEN="YOUR_TOKEN_HERE"
codex mcp add unilighter --url "http://127.0.0.1:3847/mcp" --bearer-token-env-var UNILIGHTER_MCP_TOKEN

# Verify connection
codex mcp list
```
Or define it directly in your global `~/.codex/config.toml` (or project `.codex/config.toml`):
```toml
[mcp_servers.unilighter]
url = "http://127.0.0.1:3847/mcp"
bearer_token_env_var = "UNILIGHTER_MCP_TOKEN"
```

**3. Google Antigravity (IDE & SDK):**
For Antigravity sessions, add to `~/.gemini/config/mcp_config.json`:
```json
{
  "mcpServers": {
    "unilighter": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-remote",
        "http://127.0.0.1:3847/mcp"
      ]
    }
  }
}
```
Or in autonomous Python agent workflows using `google-antigravity-sdk`:
```python
from google.antigravity import Agent, LocalAgentConfig, types

mcp_servers = [
    types.McpStreamableHttpServer(
        name="unilighter",
        url="http://127.0.0.1:3847/mcp",
        headers={"Authorization": "Bearer YOUR_TOKEN_HERE"},
    )
]

config = LocalAgentConfig(mcp_servers=mcp_servers)
async with Agent(config) as agent:
    response = await agent.chat("Turn on all warm wash fixtures at 70% dimmer.")
```

**4. Claude Desktop (`claude_desktop_config.json`):**
```json
{
  "mcpServers": {
    "unilighter": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-remote",
        "http://127.0.0.1:3847/mcp",
        "--header",
        "Authorization:Bearer YOUR_TOKEN_HERE"
      ]
    }
  }
}
```

### 3. Start Conversational Lighting Design
Once connected, prompt your agent with natural requests:
- *"Patch 4 Chauvet Rogue R2 Beams starting at address 1 on Universe 1, and tag them #Beams."*
- *"Create a static scene called 'Cyan Focus' with all wash lights in cyan at 80% dimmer, and capture current pan/tilt positions."*
- *"Build a 4-step chase that alternates odd and even beam fixtures in white and amber locked to the master BPM."*
- *"Inspect Universe 1 to see which cues are currently holding dimmer output on channel 17."*

