singular-mcp-server
# singular-mcp-server
A comprehensive [Model Context Protocol](https://modelcontextprotocol.io) server
for **reading, controlling, and orchestrating [Singular.live](https://singular.live)
live broadcast graphics compositions** from Claude Desktop or any MCP client.
It lets an agent discover a control app's structure, fill its control nodes
(text, images, colors…), animate sub-compositions in and out, push low-latency
data, and run a newsroom **rundown → graphics** workflow over templates you build
once in Composer.
> ### What this is (and isn't)
> Singular's public API **controls** compositions; it does **not author** them.
> You build the graphics (lower-thirds, full-frames, tickers, bugs) once in the
> browser **Composer**, and this server lets agents fill and sequence that kit of
> parts in real time. Authoring composition structure, account listing, token
> minting, media upload, and webhooks are not exposed by any public Singular API.
> See [docs/SINGULAR_API.md](docs/SINGULAR_API.md) for the API reference.
## Installation
**Prerequisites:** Node.js ≥ 18 (developed on Node 22) and npm.
```bash
# 1. Clone
git clone https://github.com/dqbuilds/singular-mcp-server.git
cd singular-mcp-server
# 2. Install dependencies
npm install
# 3. Build (compiles TypeScript to dist/)
npm run build
# 4. (optional) Verify — runs the mock-API integration test; no Singular account needed
npm test
```
This produces the runnable server at `dist/index.js`. Next, configure a Singular
app token and point your MCP client at it (below).
> **Install globally (optional).** From the repo, `npm link` puts a
> `singular-mcp-server` command on your PATH; then your MCP client can use
> `"command": "singular-mcp-server"` instead of an absolute `node dist/index.js` path.
## Configuration
Secrets come **only** from the environment. Copy `.env.example` → `.env` (the
server itself reads real environment variables; use your process manager or the
MCP client config to set them).
| Variable | Required | Default | Purpose |
|---|---|---|---|
| `SINGULAR_APP_TOKEN` | no | — | Default control-app token when a tool omits `app`/`appToken`. |
| `SINGULAR_API_BASE` | no | `https://app.singular.live/apiv2/controlapps` | Control REST base. |
| `SINGULAR_DATASTREAM_BASE` | no | `https://datastream.singular.live/datastreams` | Data Stream base. |
| `SINGULAR_DEFAULT_SUBCOMPOSITION` | no | — | Optional default sub-composition name. |
| `SINGULAR_REGISTRY_PATH` | no | `~/.singular-mcp/registry.json` | On-disk alias→token registry (owner-only perms). |
| `SINGULAR_HTTP_TIMEOUT_MS` | no | `30000` | Per-request timeout. |
| `LOG_LEVEL` | no | `info` | `debug`\|`info`\|`warn`\|`error` (logs go to **stderr**). |
Where do tokens come from? Copy each app token from the Singular **Dashboard**
(inspector "i" → *URLs and Token*; UNO `</>`; or Studio → *Manage Access → App
Token*). The API cannot mint them.
### Claude Desktop
Add to `claude_desktop_config.json`:
```json
{
"mcpServers": {
"singular": {
"command": "node",
"args": ["/absolute/path/to/singular-mcp-server/dist/index.js"],
"env": { "SINGULAR_APP_TOKEN": "your-token-here" }
}
}
}
```
You can omit `SINGULAR_APP_TOKEN` and instead register apps by alias at runtime
with `singular_register_app`.
## Tools (25)
Every tool takes `response_format` (`markdown` default, or `json`) and returns
both human text and `structuredContent`. App-targeting tools accept an `app`
alias (from the registry) or a raw `appToken`, falling back to the env default.
**Discovery & read**
- `singular_get_app_metadata` — ids, name, output/preview URLs.
- `singular_get_model` — structural model: sub-compositions + typed control nodes.
- `singular_get_control_state` — current live state + values.
- `singular_list_subcompositions` — model + live values joined (best overview).
- `singular_find_nodes` — filter nodes by `type` (e.g. `image`) / title.
**Content control**
- `singular_update_content` — fill nodes across one or more sub-comps in one PATCH.
- `singular_set_image` — set an image node by URL (validates it's an image node + URL reachability).
- `singular_reset_nodes` — reset nodes to their reset values (clear a template).
**Animation & playout**
- `singular_animate_state` — take sub-comps In/Out (multiple targets per call).
- `singular_update_and_animate` — fill + take to air atomically (no stale flash).
- `singular_take_out_all` — clear the whole app (`TakeOutAllOutput`).
**Data streams**
- `singular_register_data_stream` — store a stream's private token by alias.
- `singular_list_data_streams` — list registered stream aliases.
- `singular_push_datastream` — PUT low-latency JSON (≤ 60 KB) to a stream.
**Media & output**
- `singular_get_output_urls` — live output / broadcast / thumbnail URLs.
- `singular_check_image_url` — pre-flight an image URL.
**Orchestration & rundown**
- `singular_register_app` / `singular_list_apps` / `singular_remove_app` — the alias registry.
- `singular_map_rundown_template` — bind an item type → sub-comp + field map.
- `singular_list_rundown_templates` — list mappings.
- `singular_prepare_item` — dry-run: resolve a story item to a payload, no air.
- `singular_play_rundown_item` — take an item to air (optional server-side auto-out).
- `singular_poll_onair_state` — poll what's on air (+ diff since last poll).
- `singular_server_info` — server config/health (no secrets).
## For agents
The server sends usage guidance to clients as its MCP `instructions` at connect
time, and every tool has a self-contained description with its args and return
shape. The full playbook — the discover-before-write rule, the canonical flow,
value formats, and gotchas — is in [AGENTS.md](AGENTS.md).
## Newsroom workflow example
```text
1. singular_register_app { alias: "evening-news", token: "…" }
2. singular_find_nodes { app: "evening-news", type: "image" } # discover the kit
3. singular_map_rundown_template {
name: "lower-third", appAlias: "evening-news",
subCompositionName: "LowerThird",
fieldMap: { headline: "titleNode", photo: "bannerImage" } }
4. singular_prepare_item { template: "lower-third",
fields: { headline: "Markets rally", photo: "https://cdn/…jpg" } } # verify
5. singular_play_rundown_item { template: "lower-third",
fields: { headline: "Markets rally", photo: "https://cdn/…jpg" },
auto_out_ms: 8000 } # to air
6. singular_poll_onair_state { app: "evening-news" }
```
An agent can drive this from a rundown/PDF: extract stories + image URLs, map them
to templates, and play them to air.
## Security
- App tokens are **bearer-equivalent secrets**. They are stored server-side in the
registry (file mode `0600`, dir `0700`), **never returned to the model**, and
**redacted from logs** (including inside request URLs).
- Host images on your own reachable URL; there is no upload API.
- stdio logging is on **stderr** only (stdout is the JSON-RPC channel).
## Limitations (from Singular's API, not this server)
Authoring compositions, listing an account's assets, minting tokens, uploading
media, server-side rendering, and webhooks are all unavailable via public API.
On-air awareness is by polling. Auto-out scheduling is in-memory (not restart-safe).
See [docs/SINGULAR_API.md](docs/SINGULAR_API.md).
## Roadmap
- Optional Streamable HTTP transport.
- Data Node tools over the `apiv1` Data Node API.
- Batch rundown ingestion helpers (PDF/rundown → items).
- In-memory control-model cache with TTL.
## Development
```bash
npm run dev # tsx watch
npm run typecheck # tsc --noEmit
npm run inspector # MCP Inspector against the built server
```
TDQS
Scored across 25 tools
Every tool has a clearly distinct purpose—from registration and discovery to content updates, animation, and rundown management. Even similar tools like update_content, update_and_animate, set_image, and reset_nodes are clearly differentiated by their descriptions and use cases.
All 25 tools follow a consistent singular_verb_noun pattern. Verbs like 'list', 'get', 'register', 'update' are used uniformly, and compound nouns (e.g., 'onair_state', 'output_urls') maintain readability without mixing conventions.
At 25 tools, the count is slightly above the ideal range (3–15), but each tool serves a necessary function within the complex domain of broadcast graphics control. The set feels comprehensive without being bloated.
The tool surface covers registration, discovery, content manipulation, animation, rundown workflow, and server introspection. Minor gaps exist—no tool to remove data streams or delete rundown templates—but these are secondary and do not critically impede core workflows.