Filament Docs

AI Agents (MCP)

Let Claude Code, Codex and other MCP clients build and edit Filament projects through a local MCP server.

Filament has a built-in Model Context Protocol server. Turn it on and a coding agent — Claude Code, Codex, Claude Desktop, or any MCP client — can lay out LED strips, address DMX, fill the player grid, arrange a show on the timeline, make looks react to music, write shaders and check the result with live previews, while you watch every change land in the app.

What it does

  • Edits the project you have open. Changes appear live, autosave covers them, and every tool call is one undo step (Cmd+Z undoes it).
  • Covers the whole project: surfaces, LED curves and fixtures, DMX addressing, warps, video outputs and slices, layers, groups, clips, effect chains, palettes, the timeline with its automation lanes, audio and envelope modulation, and user animation and effect shaders.
  • Lets the agent check its work: a PNG of the composite, a layer, a clip or a video output; a picture of the LED layout; LED output values; live audio band levels; shader compile errors; recent logs.
  • Runs long jobs in the background. Timeline exports, diagnostics reports and Resolume imports run as MCP tasks in clients that support them, so the agent can follow their progress or cancel them.

Turn it on

Open Settings → AI Agents (or Help → Connect an AI Agent…) and switch MCP server on. Filament creates an access token the first time.

FieldWhat it does
MCP serverStarts the server. It stays on across launches until you turn it off.
PortDefault 7320. Press Apply after changing it.
Allow remote connectionsOff: only programs on this computer can connect. On: other computers on your network connect at the address shown, with the token.
TokenThe access token clients must send. Copy copies it; Regenerate replaces it; clients added with Add are updated, others need the new one.

A status-bar dot shows the server state (green when listening) and opens the page when clicked. The Activity list shows each tool call with its duration and result.

Connect a client

Under Connect a client, Filament lists Claude Code, Claude Desktop and Codex and whether each is installed on this computer. Press Add next to one and Filament writes its own entry into that client's configuration, then:

ClientTo start using Filament
Claude CodeStart a new session. /mcp lists filament.
Claude DesktopQuit and reopen Claude Desktop.
Codex (CLI and the Codex app)Restart Codex.

Filament keeps a .filament-backup copy of each file it changes and leaves every other setting alone. Update appears when an entry uses an old port or token; regenerating the token or changing the port updates the clients you added this way automatically. Remove takes the entry out again.

Claude Desktop starts Filament's own executable as a small relay, so it needs no Node.js. If you open Filament from a disk image or the Downloads folder on macOS, move it to Applications first.

Manual setup

The settings page shows each configuration below with your real port, token and Filament path, and a copy button in the corner. Here, replace <PORT> and <TOKEN>.

Claude Code

claude mcp add --transport http --scope user \
  filament http://127.0.0.1:<PORT>/mcp \
  --header "Authorization: Bearer <TOKEN>"

--header must come after the name and URL.

Codex — add to ~/.codex/config.toml (Windows: %USERPROFILE%\.codex\config.toml):

[mcp_servers.filament]
url = "http://127.0.0.1:<PORT>/mcp"
http_headers = { Authorization = "Bearer <TOKEN>" }

Claude Desktop — add to claude_desktop_config.json (Settings → Developer → Edit Config in Claude Desktop). command is the Filament executable: /Applications/Filament.app/Contents/MacOS/Filament on macOS, Filament.exe in the install folder on Windows, /usr/bin/filament or the AppImage on Linux.

{
  "mcpServers": {
    "filament": {
      "command": "/Applications/Filament.app/Contents/MacOS/Filament",
      "args": ["--mcp-stdio"],
      "env": { "FILAMENT_MCP_PORT": "<PORT>", "FILAMENT_MCP_TOKEN": "<TOKEN>" }
    }
  }
}

Other clients (Cursor, Windsurf and others that read .mcp.json)

{ "mcpServers": { "filament": { "type": "http", "url": "http://127.0.0.1:<PORT>/mcp",
                                "headers": { "Authorization": "Bearer <TOKEN>" } } } }

To check the server from a terminal:

curl -s -X POST http://127.0.0.1:<PORT>/mcp \
  -H "Authorization: Bearer <TOKEN>" -H "Content-Type: application/json" -H "Accept: application/json" \
  -H "Mcp-Method: server/discover" -H "Mcp-Name: curl" \
  -d '{"jsonrpc":"2.0","id":1,"method":"server/discover"}'

From another computer

Turn on Allow remote connections on the Filament machine, then set up Claude Code, Codex or another HTTP client on the other computer as above, with the address the settings page shows in place of 127.0.0.1. Claude Desktop's relay only reaches Filament on its own computer. The first time, your firewall may ask whether Filament may accept incoming connections.

Permissions

SettingDefaultAllows
Allow destructive operationsOffDeleting projects, fixtures, palettes, shader bundles and media roots — things undo cannot bring back.
Allow playback controlOnStarting and stopping playback, launching clips, switching between session and arrangement playback, moving the timeline playhead, exporting the timeline, and opening output windows.

Everything else — editing the open project — is always allowed while the server is on, and always undoable.

What agents can do

AreaTools
ProjectsCreate, open, save, rename, duplicate, import and export .filament files
DocumentRead the project, find things by name, patch any field, undo and redo, batch many edits into one undo step
MappingSurfaces and their DMX output, fixtures, LED curves (lines, shapes, LED matrices), loose fixtures, warps, DMX validation and channel maps
PlayerColumns, layers, groups, clips (animations, video, images, live sources), effect chains, master, palettes, surface routing
ArrangementTimeline clips (add, move, split, join, fades), clip effects, track mute and solo, markers, the loop region, timecode regions, playback mode and transport
AutomationLanes for opacity, volume, brightness and effect parameters (points, preset shapes or an LFO), clip envelopes
ModulationAudio-band and envelope/LFO modulation of clip, effect, layer, group, master and surface parameters; live audio levels for tuning
OutputsVideo outputs and slices, Resolume Advanced Output export and import, timeline export to a video file or a .dmxshow bundle
MediaMedia folders, files, thumbnails and frames, live external sources
ShadersList, read, validate, create, fork, write, import and export animation and effect bundles; compile diagnostics
CheckingPreview images, a picture of the LED layout, LED output values, runtime status, logs

Agents can also read the shader contracts, the animation, effect and palette catalogues, and the document schema as MCP resources. A client that subscribes to filament://project/current hears about your edits as you make them.

Safety

  • This computer only, unless you allow remote connections. The server listens on 127.0.0.1 by default. With Allow remote connections on, other machines on your network can reach it with the token, which travels unencrypted, so use it on a network you trust. Requests from web pages are always refused.
  • Token required. Any program with the token can edit your projects while the server is on; regenerate it if it leaks.
  • Undo covers edits. Every call is one undo step, and a failed batch rolls itself back. You and the agent share one undo history, so Cmd+Z in the app can undo an agent's step.
  • Off by default. Nothing listens until you enable it, and exports keep their usual license rules.
  • Exports pause live output. A timeline export renders offline and live output stops until it finishes, so the agent is told to ask before exporting during a show.

Guide for agents

This is the guide agents read from the filament://guide/agent resource.

Read this before you edit a project. Read filament://guide/workflows for step-by-step recipes.

1. What Filament is

Filament maps video onto LEDs and projectors and plays it live.

  • Canvas: a 2D pixel space (canvasWidth × canvasHeight) the content is rendered into.
  • Surfaces: DMX outputs (Art-Net or sACN, a controller IP, a first universe). A surface holds slices: each slice samples a canvas rectangle into a fixture (a pixel layout and channel order) at a DMX start channel.
  • Curves: LED strips drawn as bezier paths. A curve owns one slice per LED and regenerates them when it changes; its channels run contiguously from startChannel.
  • Warps: perspective + mesh deformations that move curves and loose slices together.
  • Player grid: columns × layers. A cell holds a clip: an animation (a WGSL shader with parameters), a video, a still image, or a live external source. Layers blend in stack order (0 = bottom); groups composite a contiguous band of layers in isolation.
  • Arrangement: the timeline. Each layer has one track; a track's clips carry the same content a grid cell does and play in arrangement mode, with fades, markers, a loop region and timecode regions.
  • Effect chains run on a clip, a layer, a group, or the master.
  • Palettes colour animations. The project has a master palette; a clip follows it unless it has a palette of its own (clip_update { palette: null } makes it follow again).
  • Video outputs send the composite (or one layer or group) to a projector window, Syphon, Spout, NDI or a file, through slices with their own warp and mask.

2. How this server behaves

  • You edit the live document. The operator sees every change in the app as it lands, and autosave covers it. Nothing here writes files behind the app's back.
  • One tool call is one undo step. undo and redo act like Cmd+Z / Cmd+Shift+Z. batch runs many calls as one step and rolls them all back if one fails — use it for multi-step builds.
  • The undo history is shared with the operator. An edit made in the app between your edit and your undo is the one that gets undone. Pass the revision your edit returned as undo { expectedRevision } to undo only your own step; the reply's byAgent says whose step it reverted.
  • Revisions. Every editing tool returns revision. Pass it back as expectedRevision on the next edit: if the operator changed the document in between, you get revision_conflict and nothing is applied; re-read (project_get_current, document_get) and retry. Revisions reset when the app reloads.
  • Watch instead of polling. Subscribe to filament://project/current (any change, a project switch included) or filament://project/current/timeline (arrangement changes) to hear about the operator's edits; notifications come at most every 250 ms. Your own edits notify too: compare the resource's revision with the one your call returned. A client that cannot subscribe can compare server_info's revision instead.
  • Names or ids. Every reference (surface, layer, curve, fixture, …) takes an id or a name: exact id, then exact name, then case-insensitive name. Several matches give ambiguous_name with the candidates. A grid clip is { layer, column }; an arrangement clip is { track, clip }, where track is its layer. An effect target is "master", { layer }, { group }, { layer, column } or { track, clip }.
  • Permission gates. Tools that delete library items (projects, fixtures, palettes, shader bundles, media roots) need "Allow destructive operations" (destructive_disabled otherwise). Playback tools (transport_set, clip_launch, column_launch, layer_stop, stop_all, tempo_tap, playback_mode_set, timeline_transport, timeline_export, output windows) need "Allow playback control" (audition_disabled). server_info says which are on.
  • Not undoable: library and file tools (fixtures, palettes, shader bundles, media roots, exports, project create/open/delete) and playback state. Removing a surface or a layer from the open document is undoable.
  • Read-only projects. A project that loaded with unreadable data refuses edits with read_only_project. project_clear_read_only lifts it; the next save overwrites the bytes that could not be read.
  • The app must be open. Without the main window, editing tools fail with app_window_unavailable; retry once the window is back.
  • Errors carry code, message and details. validation messages name the field and the allowed values; fix the argument rather than retrying.

3. Recipes

The full sequences are in filament://guide/workflows. In short:

  • Start a project: project_create → fixture_presets_list / fixture_list → surface_create → curve_add_line / curve_add_grid / curve_add_shape → dmx_validate → canvas_render_layout.
  • Build a grid of looks: column_add → layer_add → animation_list → clip_assign_animation → effect_add → palette_set_project → clip_launch → preview_render.
  • Arrange a show: timeline_marker_add → timeline_clip_add { source: { cell } } → timeline_clip_update (fades) → playback_mode_set { mode: "arrangement" } → timeline_transport → preview_render.
  • Write a shader: read filament://docs/animation-contract → shader_template_get → animation_validate → animation_create → animation_write_source → clip_assign_animation → preview_render → shader_diagnostics.
  • Route outputs: surface_routing_set, video_output_create, video_slice_add, preview_render with { videoOutput }.
  • Hand off: project_save, project_export_file, export_resolume.

4. Pitfalls

  • Decoded vs stored shapes. Tools speak the decoded document the app edits (filament://schema/document): surfaces carry ipAddress, startingUniverse and outputDevice; curves live in document.curves, not inside surfaces. filament://schema/project is the stored/archive shape — read it for leaf types, not for editing.
  • Curves belong to a surface. A curve's LEDs are slices on one surface. Create curves with the curve tools (they pick the surface's next free channel unless you give startChannel); do not add slices for curve LEDs yourself.
  • Curve LEDs are derived. Change a strip with curve_update / curve_transform; a curve LED's slice only takes name, enabled, flip and output offsets.
  • Effect instance ids are minted by the app. effect_add returns the new instance; use its id with effect_update, effect_move, effect_remove.
  • Parameters are checked. clip_assign_animation refuses unknown parameter ids (listing the valid ones) and clamps numbers to their declared range, reporting what it clamped.
  • Player edits need the player. Right after opening a project the runtime is still loading it; player tools return app_window_unavailable for that moment — retry.
  • preview_render needs the runtime ticking. If it times out, ask the operator to open the Player page or a preview window.
  • Launches crossfade. clip_launch and column_launch return crossfadeMs; a preview rendered before that has passed still shows part of the previous clip.
  • Exports need a paid license (license_required_for_export on trial installs).
  • Thumbnails and slices are left out by default (document_get includeThumbnails, includeSlices; curve_list includeSliceIds) to keep replies small.
  • Removing library items checks the open project only; other projects in the library may still use them.
  • New video outputs start off. Turning on a display output opens a window on a projector; ask before doing that in front of an audience.

5. Arranging a show

  • Time arguments are seconds from the start, { bar, beat? } (1-based, 4/4 at the master BPM; { bar: 1 } is 0 s) or { marker, offset? }. Lengths are seconds, { beats } or { bars }. Replies give seconds, with bar ("9.1") when the time lands on a beat. Set the BPM (master_update) before placing by bars.
  • Tracks follow layers. Add or remove a layer with layer_add / layer_remove; its track comes and goes with it.
  • Overlaps. A track plays at most two clips at once, and only as a crossfade: the later clip starts and ends after the earlier one. Anything else is refused with the clip in the way named; nothing is shifted for you.
  • Arrangement clips are copies. timeline_clip_add { source: { cell } } copies the cell; editing the cell later does not change the clip. Edit the clip with timeline_clip_update and its chain with the effect tools and target: { track, clip }.
  • Ids from the app. timeline_clip_split returns both halves with new ids, and effect_add returns an arrangement clip's new instance; use those ids next.
  • Automation. A lane belongs to a track, to "master" or to { group } and drives one target: "opacity", "volume", "brightness", "masterVolume", { effect, parameter } or { effect, mix: true }. Read ranges with timeline_lane_targets; values are in the target's own units and clamped. A lane is points (timeline_lane_set, timeline_lane_shape with a shape from filament://registry/enums) or an LFO (timeline_lane_generator_set), never both. Rate knobs take only linear / hold points. Envelopes that travel with a clip are timeline_clip_envelope_set.
  • Exporting pauses the show. timeline_export renders a video file and/or a .dmxshow bundle offline (paid license, playback control allowed), and live output stops until it finishes. Ask before exporting during a show. Clients with MCP Tasks get a task to poll; others get the result inline only for short ranges, else task_required: export the loop region or a span between markers instead. One export runs at a time (conflict).
  • Arrangement mode. Clips play only in arrangement mode (playback_mode_set), and timeline_transport refuses in session mode or while timecode chase is armed.

6. Making it react

  • Two sources. modulation_audio_set makes a parameter follow an audio band; modulation_envelope_set drives it with an envelope/LFO in beats or seconds. A target is a cell parameter { layer, column, parameter }, an effect { effect: { target, instance }, parameter } or its mix: true, { layer, field }, { group, field }, { master } or { surface, field }. One modulation per target: setting it again replaces the source.
  • Cell targets stay on the grid. A cell parameter modulation drives that grid cell only, never an arrangement clip copied from it. In the arrangement, modulate the layer, group, master or an effect, and give clips timeline_clip_envelope_set.
  • Pick the band by ear. Start from a preset (audio_presets_list: kick, bass-pump, snare-clap, hat-shimmer, mid-vocal), then call audio_levels_get with music playing. Set threshold near the band's floor and gain so its p95 lands near 0.8. gain stops at 4: a quiet input (a laptop microphone) needs a curve below 1 as well. Afterwards audio_levels_get { modulations: [id] } shows the values the parameter really takes. A hint says when the input is off or silent; turning input on is the operator's job (Settings → Audio).
  • Prefer envelopes for anything that must repeat. Audio and MIDI modulation render at their base values in exports; an envelope synced in beats plays the same every time.
  • Lanes win in arrangement mode. While the arrangement plays, a target with an automation lane follows the lane and its modulation pauses (shadowedByLane in modulation_list).

7. Limits

LimitValue
Layers per grid32
Effects per chain16
Slices per video output64
LEDs per curve4096
Canvas size16–16384 px per side
WGSL source256 KB
Bundle manifest64 KB
Calls per batch500

On this page