Skip to content

MCP Server

sajou includes an MCP (Model Context Protocol) server that lets AI agents interact with the visual choreographer programmatically. Any MCP-compatible client — Claude Code, Claude Desktop, or custom agents — can read scene state, compose choreographies, place entities, write GLSL shaders, and control uniforms in real-time.

Architecture

The MCP server is the source of truth for scene state. It runs as a standalone Node.js process with an in-memory state store. The scene-builder (browser) is a view/edit client that syncs with the server.

                 ┌─────────────────────────────┐
                 │   sajou MCP server           │
                 │   (@sajou/mcp-server)        │
                 │                              │
                 │   In-memory state store      │
                 │   REST API  (/api/*)         │
                 │   SSE streams                │
                 │   MCP stdio / HTTP (/mcp)    │
                 └──────┬──────────┬────────────┘
                        │          │
              ┌─────────┘          └──────────┐
              ▼                               ▼
     Browser (scene-builder)           AI Agent (Claude)
     connects via HTTP + SSE           connects via MCP
     view + edit scenes                compose scenes

The server works standalone — agents can compose scenes without any browser open. When a browser connects, it syncs bidirectionally: manual edits in the browser are pushed to the server, and agent commands from the server appear live in the browser.

Signal relay

The MCP server also acts as a signal relay for Claude Code. When Claude Code hooks fire, the sajou-emit CLI posts signals to the server, which broadcasts them to all connected browsers via SSE:

Claude Code hook → sajou-emit → POST /api/signal → MCP server

                              Browser ← EventSource(/__signals__/stream)

This works in both dev mode (Vite proxies to the server) and production (Tauri/static builds connect directly via __SERVER_URL__). The browser discovers and auto-connects to this endpoint as the local:claude-code signal source.

Installation

The server is published on npm. No need to clone the repo.

bash
npx -y @sajou/mcp-server --http

This starts the server on port 3001 (default). Specify a custom port:

bash
npx -y @sajou/mcp-server --http 3000

Running with a client

The scene-builder (browser client) connects to the server via HTTP. In development:

Terminal 1 — server:

bash
npx -y @sajou/mcp-server --http 3000

Terminal 2 — client:

bash
# From the sajou repo
cd tools/scene-builder && pnpm dev:vite

The Vite dev server proxies /api/* to http://localhost:3000 (configurable via SAJOU_SERVER env var). Open http://localhost:5175 in your browser.

The scene-builder can also run without a server (offline/Tauri mode) — it falls back to local IndexedDB storage.

Startup flow

  1. Browser restores local state from IndexedDB
  2. initServerConnection() probes server via GET /api/state/full (2s timeout)
  3. If server has state → overwrites local stores with server data → starts sync + commands
  4. If server is empty → starts sync (pushes local state on first push) + commands
  5. If server unreachable → enters local mode (IDB only), starts reconnect with exponential backoff
  6. SSE connection established for live state-change notifications

Connection status

The help bar (bottom-right corner) shows a server connection indicator:

DotStatusMeaning
GreenconnectedServer reachable, bidirectional sync active
Gray + "local"localServer not found, IndexedDB only
Amber pulsingreconnectingWas connected, retrying with backoff (5s → 60s cap)

Click the dot to open a popover with:

  • Status line and last contact timestamp
  • Editable server URL — change the target server at runtime (persisted in localStorage). Empty = Vite proxy (default). Useful when the default port is taken.
  • Connection log — timestamped events (connected, lost, retrying, reconnected…)

State sync

Bidirectional sync between browser and server:

  • Push (browser → server): state-sync.ts pushes full state snapshot via POST /api/state/push (debounced 300ms)
  • Pull (server → browser): command-consumer.ts listens on /__commands__/stream SSE for state-change events, then re-fetches /api/state/full
  • Feedback prevention: isApplyingServerState flag suppresses pushes while applying server state

MCP client configuration

Claude Code / Claude Desktop

Add to your MCP config (~/.claude/claude_desktop_config.json or project .mcp.json):

json
{
  "mcpServers": {
    "sajou": {
      "command": "npx",
      "args": ["-y", "@sajou/mcp-server"]
    }
  }
}

This starts the server in stdio mode (MCP protocol over stdin/stdout). The server also accepts --http to run in HTTP mode with REST API and SSE.

Development (from the repo)

json
{
  "mcpServers": {
    "sajou": {
      "command": "pnpm",
      "args": ["--filter", "@sajou/mcp-server", "start"]
    }
  }
}

Entry points

CommandModeUse case
npx -y @sajou/mcp-serverstdioClaude Code / Claude Desktop MCP integration
npx -y @sajou/mcp-server --httpHTTP (port 3001)Standalone server with REST API + SSE + MCP HTTP
npx -y @sajou/mcp-server --http 8080HTTP (custom port)Same, custom port

Tools

The MCP server exposes 20+ tools organized into five categories.

Read tools — scene inspection

These tools let the agent understand what's currently on stage.

ToolDescription
describe_sceneComprehensive human-readable summary of the entire scene — entities, choreographies, signal sources, bindings, wiring. The primary entry point for understanding scene state.
get_scene_stateRaw scene state — all placed entities with positions, visibility, layers, routes, dimensions, and editor mode.
get_choreographiesList all choreographies with trigger signal types, conditions, step types, and wiring info.
get_shadersAll GLSL shaders with full source code, uniforms, object groups, and pass count.
get_sketchesAll sketches (p5.js / Three.js) with source code and parameters.
map_signalsView current signal-to-choreography wiring (read-only).

Write tools — scene composition

These tools let the agent build and modify scenes.

ToolDescription
place_entityPlace an entity on the scene at a given position. Supports scale, rotation, layer, z-index, animation state, and semantic ID (Actor ID) for choreography targeting.
create_choreographyCreate a choreography — a sequence of animation steps triggered by a signal. Supports all actions: move, fly, flash, spawn, destroy, wait, playSound, setAnimation, parallel, onArrive, onInterrupt.
create_bindingBind a choreography to an entity property (position, rotation, opacity, animation state) with optional mapping and transitions.
create_wireWire connections in the patch bay across three layers: signal→signal-type, signal-type→choreographer, choreographer→theme/shader.
remove_itemRemove entities, choreographies, bindings, wires, or signal sources. Cleans up dependent connections.

Entity management tools — inspect and control actors

These tools let the agent discover, inspect, and control individual entities. Use them to pilot actors at runtime — move characters, change states, adjust visibility — without creating a full choreography.

ToolDescription
list_entitiesRoster of all placed entities with their semanticId, position, animation state, and key properties. Filter by actors (with semanticId), decoration (without), or all. This is the starting point — call it to learn what you can target.
get_entityFull state of a single entity by semanticId or instance id. Returns position, visual state, topology, speech bubble config, and all active bindings targeting this entity.
update_entityPartial update of entity properties — position (x, y), scale, rotation, opacity, visibility, layer, z-order, flip. Only provided fields change. Target by semanticId (preferred) or id.
set_entity_stateShortcut to change an entity's animation state. The simplest way to "activate" something: set_entity_state('door-kitchen', 'open'), set_entity_state('agent-1', 'walk').

Actor vs decoration: entities with a semanticId are actors — they have a name that choreographies and agents can target. Entities without a semanticId are passive decoration. Use list_entities(filter: 'actors') to see only targetable entities.

When to use update_entity vs choreography: update_entity applies changes immediately (teleport, snap). Choreographies animate changes over time (walk, fade). Use update_entity for setup and instant adjustments; use choreographies for narrative animations.

Shader tools — GPU effects

These tools let the agent create and control GLSL shaders.

ToolDescription
create_shaderCreate a fragment/vertex shader with uniforms. Supports @ui controls (slider, color, toggle, xy), virtual object grouping (@object), and multi-pass feedback.
update_shaderUpdate an existing shader's code, uniforms, name, or pass count. Partial updates — only provided fields change.
set_uniformSet a uniform value in real-time. Supports float, int, bool, vec2, vec3, vec4.
get_shadersRead all shader definitions (also listed under read tools).

Sketch tools — p5.js + Three.js

These tools let the agent create and control live-coded sketches.

ToolDescription
create_sketchCreate a sketch (p5.js or Three.js mode) with source code and param annotations.
update_sketchUpdate a sketch's source, name, mode, or params.
set_sketch_paramSet a sketch param value in real-time (e.g. speed: 2.5).

Runtime tools — signals

ToolDescription
emit_signalEmit a signal to the scene. Triggers any choreographies wired to that signal type.

Resources — agent guides

The MCP server exposes resources that agents can read on demand via the MCP resource protocol (list_resources / read_resource). These are static reference guides that teach the agent how to work with sajou.

ResourceURIDescription
Entity Naming Guidesajou://guide/entity-namingNaming conventions for semantic IDs, positions, routes, zones. Read before placing entities.
Choreography Patternssajou://guide/choreography-patterns7 common animation patterns (arrive-work-leave, flash, state toggle, parallel, etc.) with tool call structure.
Signal Protocolsajou://guide/signal-protocolWell-known signal types with payloads, custom types, MIDI, conditional triggers.

Usage: agents call list_resources to discover available guides, then read_resource(uri: "sajou://guide/entity-naming") to read one. This is optional context — agents can work without reading guides, but the guides significantly improve naming consistency and choreography quality.

State sync

The server maintains bidirectional state sync between the browser and external tools:

  • Client push: the browser pushes scene state to the server on every change (debounced 300ms)
  • Server push: external tools (MCP agents, REST API) mutate state on the server; changes are broadcast to the browser via SSE (/__commands__/stream)
  • SSE fallback: if the SSE stream disconnects, the browser falls back to polling every 500ms

Command delivery flow

MCP tool call ──┐
REST API POST ──┤──> Server mutates state
                │         │
                │         ▼
                │    /__commands__/stream (SSE)
                │         │
                │         ▼
                │    Browser applies command
                │         │
                │         ▼
                │    POST /api/commands/ack
                └──> Server prunes queue

REST API endpoints

Read (query state)

EndpointMethodDescription
/api/scene/stateGETFull scene state (entities, positions, layers, routes, lighting, particles)
/api/choreographiesGETAll choreographies with wiring metadata
/api/bindingsGETAll entity property bindings
/api/wiringGETFull wiring graph (signal → signal-type → choreographer → shader)
/api/signals/sourcesGETConnected signal sources (local + remote)
/api/shadersGETAll shaders with source code and uniforms
/api/p5GETAll sketches with source and params
/api/discover/localGETProbe local services (Claude Code, OpenClaw, LM Studio, Ollama)

Write (mutate scene)

EndpointMethodDescription
/api/scene/entitiesPOSTAdd, remove, or update entities
/api/choreographiesPOSTAdd, remove, or update choreographies
/api/bindingsPOSTAdd or remove bindings
/api/wiringPOSTAdd or remove wire connections
/api/signals/sourcesPOSTAdd or remove signal sources
/api/shadersPOSTCreate a shader
/api/shaders/:idPUTUpdate an existing shader
/api/shaders/:idDELETERemove a shader
/api/shaders/:id/uniformsPOSTSet a uniform value in real-time
/api/p5POSTCreate a sketch
/api/p5/:idPUTUpdate an existing sketch
/api/p5/:idDELETERemove a sketch
/api/p5/:id/paramsPOSTSet a sketch param value in real-time
/api/signalPOSTEmit a signal (triggers wired choreographies)

Example workflow

Here's a complete example of an AI agent building a scene from scratch.

Step 1: Understand the scene

Tool: describe_scene
→ "Empty scene. No entities, no choreographies, no wiring."

Step 2: Place entities

Tool: place_entity
  entityId: "peon", x: 200, y: 300, semanticId: "worker"

Tool: place_entity
  entityId: "forge", x: 500, y: 300, semanticId: "forge"

Step 3: Create a choreography

Tool: create_choreography
  on: "task_dispatch"
  steps: [
    { "action": "move", "entity": "worker", "target": "forge", "duration": 1200 },
    { "action": "onArrive", "steps": [
      { "action": "flash", "entity": "forge", "params": { "color": "gold" } }
    ]}
  ]

Step 4: Wire and trigger

Tool: create_wire
  fromZone: "signal-type", fromId: "task_dispatch"
  toZone: "choreographer", toId: "<choreography-id>"

Tool: emit_signal
  type: "task_dispatch"
  payload: { "task": "gather_resources" }

The worker moves to the forge and a flash fires on arrival — composed entirely by the AI agent.

Step 5: Inspect and control actors

Tool: list_entities
  filter: "actors"
→ [{ semanticId: "worker", activeState: "idle", position: {x: 200, y: 300} },
   { semanticId: "forge",  activeState: "idle", position: {x: 500, y: 300} }]

Tool: get_entity
  semanticId: "worker"
→ Full entity state + active bindings

Tool: set_entity_state
  semanticId: "worker", state: "work"
→ Worker switches to 'work' animation

Tool: update_entity
  semanticId: "worker", opacity: 0.5, scale: 1.2
→ Worker becomes semi-transparent and slightly larger

Entity management tools give the agent direct control over actors for setup, debugging, and instant adjustments outside of choreographies.

For naming conventions (semantic IDs, positions, routes), see the entity naming guide. For common choreography recipes, see the choreography patterns guide.