Skip to main content
Glama
README.md
# millumin-mcp

An MCP server that lets Claude Code, or any MCP client, control [Millumin](https://www.millumin.com) on macOS through its [OSC API](https://github.com/anome/millumin-dev-kit/wiki/OSC-documentation).

It runs locally over stdio, started by the client. It sends OSC to Millumin and can listen for Millumin's feedback. Tested with Millumin 5.14.

## Tools

| Tool | Purpose |
|---|---|
| `millumin_action` | Run `/action/<name>` with optional args, e.g. `launchColumn [2]` |
| `millumin_set` | Set a property on a target (default `selectedLayer`), e.g. `position/xy [0, 80]` |
| `millumin_master` | Set the `video`, `audio` or `dmx` master, 0 to 1 |
| `millumin_send_raw` | Send any OSC address |
| `millumin_query` | Send `<address>/?` and return the replies (needs feedback) |
| `millumin_ping` | Send `/ping` and return the state of every layer (needs feedback) |
| `millumin_feedback` | Read recent feedback, optionally filtered |

## Setup

In Millumin's Device manager (⌘K), OSC tab:

- **OSC listener** on input port 5678.
- For feedback: an **OSC sender** to `127.0.0.1` port 5679, with feedback on.

Build the server (Node 20 or later):

```bash
git clone https://github.com/jpkelly/millumin-mcp.git
cd millumin-mcp
npm install
npm run build
```

Add it to your MCP client:

```json
{
  "mcpServers": {
    "millumin": {
      "command": "node",
      "args": ["/path/to/millumin-mcp/dist/server.js"],
      "env": { "MILLUMIN_FEEDBACK_PORT": "5679" }
    }
  }
}
```

| Variable | Default | |
|---|---|---|
| `MILLUMIN_HOST` | `127.0.0.1` | Where Millumin runs |
| `MILLUMIN_PORT` | `5678` | Millumin's OSC listener port |
| `MILLUMIN_FEEDBACK_PORT` | unset | Port to receive feedback on; unset turns feedback off |
| `MILLUMIN_ALLOW_DESTRUCTIVE` | unset | `1` allows `/action/quit` and `/action/saveProject`, which are refused otherwise |

## Notes

- Millumin's OSC API can't create layers, canvases, outputs or routings. Make those in Millumin.
- `selectedLayer` follows the selection in Millumin's interface. Target `index:N` when the selection may change.
- Launching a column that is already playing doesn't restart it. `goToTime [0]` restarts all media together.
- Feedback gives layer names in lowercase.

## Tests

```bash
npm test
```

Runs against a fake Millumin on a loopback port, never a real one.

## License

[MIT](LICENSE)

TDQS

A3.5/5.0

Scored across 7 tools

Disambiguation4/5

The typed tools separate command execution (millumin_action), property setting (millumin_set), and master-level setting (millumin_master) clearly. millumin_query, millumin_feedback, and millumin_ping all expose feedback/state but with distinguishable purposes, while millumin_send_raw overlaps everything as a fallback, keeping this from a perfect score.

Naming Consistency3/5

All names share the millumin_ prefix and snake_case, which aids readability. However, suffixes mix nouns and verbs (action, master, feedback, ping, query vs set, send_raw) rather than following a single predictable verb_noun convention.

Tool Count5/5

Seven tools is well within the appropriate range for an OSC control bridge. Each tool has a distinct role: typed control, master control, raw fallback, and introspection.

Completeness4/5

The surface covers core control and introspection: actions, property setting, master levels, targeted queries, recent feedback, ping state, and raw OSC as an escape hatch. Typed discovery/listing of layers, columns, media, or available properties is not provided, though raw OSC can fill those gaps.

Maintenance

ActivityMaintained
ResponsivenessNo issues