MCP server
Expose mcut project state, editor operators, and command tools to MCP clients.
@mcut/mcp-server exposes mcut editing to any MCP client. It can target a local
project JSON file or the editor running in mcut Studio.
Live bridge in Studio
The desktop app hosts the live bridge. Open Studio, then connect a client to the
MCP URL from the app's MCP menu, http://127.0.0.1:44737/mcp?token=<token>.
Connect Cursor covers the menu, the mcp.json
entry, and the fixed port. Every tool below marked live bridge only works
through this URL. A browser tab connected to a standalone
bridge process serves the same tools for developers
working on Studio itself.
Stdio project server
bunx @mcut/mcp-server project.mcut.jsonThe project file defaults to project.mcut.json or $MCUT_PROJECT. The server
creates the file when missing and writes it after successful edits.
Static tools
The published server registers twenty-three static tools. The live bridge handles
three more in the editor, list_commands, apply_commands, and
run_operator, which together with the twenty-three form the twenty-six-tool agent
profile. Studio serves the profiles inside the desktop app, with a catalog at
app://studio/tools, at app://studio/tools.json and
app://studio/tools.agent.json. The full profile
is at app://studio/tools.full.json and the raw command profile at
app://studio/tools.commands.json.
| Tool | Purpose |
|---|---|
get_summary | Compact project summary. Read this before editing. |
get_project | Full serializable project JSON. |
get_media_context | Project, playback, selection, asset, track, element, marker, and transcript metadata. |
get_frame | Live bridge only. PNG of one timeline frame. Call it before placing a zoom or a crop. |
find_scene_changes | Live bridge only. Timeline times where the picture of one video clip or multicam source changes, refined to the frame, and the stable segments between them. sensitivity from 0 to 1, default 0.5. A multicam reads its screen source by default. |
get_contact_sheet | Live bridge only. One PNG grid of thumbnails of one video clip or multicam source, each labelled with its timeline time. Pass timesMs or count. |
get_audio_activity | Live bridge only. Sound and silence windows for one clip with source audio, in audio-asset time. A multicam uses its audio source. A selected multicam with none fails until setMulticamAudio instead of falling through to another clip. |
get_transcript | Caption-derived transcript. Never starts transcription. |
search_transcript | Find spoken words or phrases with timeline times, { query, queries? }. Matches ignore case and punctuation and cross caption boundaries. Each match carries the words around it and the pause before and after it. The reply has one entry in results per phrase. |
find_retakes | Retake candidates from the word-timed transcript, last to first, each a timeline range that keeps the last take. With elementId, a multicam is included. It stores that audio's word-timed transcript. The retake flow is find_retakes, then remove_ranges with the kept candidates, then apply_captions with elementId, replace: true, and no transcript. |
remove_ranges | Remove a list of time ranges from every unlocked track as one undo step and close the gaps, so video, multicam, audio, and captions stay in sync. Ranges come in any order. Timeline ms by default, so find_retakes candidates pass as they are. With time: "source" and elementId, ranges are source-media ms of that clip's audio, mapped through every piece that plays it. It is already one undo step, so it needs no transact. |
ensure_transcript | Live bridge only. Transcribe the target clip in the editor and apply word-timed captions. After cuts, captions over any piece on that track that plays the same audio count as its transcript and come back unchanged. With no captions left, the transcript the server stored for that audio is placed over every piece. replace: true transcribes again. |
list_commands | Live bridge only. Every raw timeline command schema. |
apply_commands | Live bridge only. Apply several commands in one undoable transaction. A failed command leaves the project unchanged. |
apply_captions | Turn a source-time transcript into caption elements as one undoable edit. With elementId, it captions every piece on that track that plays the same audio and replaces their old captions. scope: "clip" captions that clip alone. A multicam uses its audio source. Omit transcript with elementId to reuse the one the server stored for that audio from ensure_transcript, find_retakes, or an earlier apply_captions. The MCP server, or the live bridge in Studio, keeps it in memory until it restarts. The same transcript still matches after cuts remove words, and a different transcript warns. |
correct_transcript | Replace a misheard name or term, { find, replace } or a corrections list of those pairs, in every caption and in the stored transcript as one undo step. Matches whole words and ignores case. Word timings stay, a multi-word find merged into one word spans the words it replaces, and a multi-word replace splits their timing by character share. A match split across two captions moves into the first one. A caption retyped in Studio with its word timings in sync also reaches the stored transcript. |
apply_silence_cuts | Cut transcript silence out of one clip as one undoable edit. |
lint_project | Cross-entity problems parseProject cannot reject, each with a severity and code. |
list_zooms | Every zoom region with its element, timing, target, easing, and motion blur. |
edit_zooms | Add, update, or remove zoom regions as one undoable edit. A rejected edit leaves the project unchanged. |
center_person | Live bridge only. Find the face on device and keep the person in frame as one undoable edit, on a video crop or a multicam camera source. A video crop at the project aspect also scales the clip to fill the frame, and fill overrides that. |
list_presets | Platform delivery presets with dimensions, fps, and safe areas. |
list_operators | List available UI-level editor operators. |
run_operator | Live bridge only. Run an operator by id. |
list_actions | Live bridge only. List editor actions. |
run_action | Live bridge only. Run an editor action by id. Human-only actions are rejected. |
import_media | Live bridge only. Import local media by absolute path. Studio probes each file, registers the asset, and stores the bytes. |
transact | Apply 1 to 100 command, operator, run_operator, run_action, apply_commands, or remove_ranges calls as one undo step. remove_ranges inside it takes timeline ranges only. A failed call leaves the project and the undo stack unchanged. Undo and redo are rejected before any call runs. |
undo | Undo the most recent edit. One undo step is one tool call or one whole transact. |
redo | Redo the most recently undone edit. |
export_video | Live bridge only. Start rendering the whole timeline to a video file and return its jobId. |
get_export | Live bridge only. State, percent, and ETA of an export job. waitMs waits for it to finish. |
cancel_export | Live bridge only. Stop a running export. |
Export jobs
A long timeline renders for minutes, so export runs as a job. export_video
starts the render in Studio and returns the jobId, the format, the
outputPath, and the timeline duration. Call get_export with the jobId and
waitMs set to 20000 until state is done, then read outputPath and
bytes. While the job renders, get_export reports the phase, the percent,
and etaMs.
Studio uploads the finished file to the bridge, and the bridge writes it. No
download starts and no save dialog opens. The file goes to outputPath when
the call passes an absolute path. Otherwise it takes the project name in the
export folder, with (2) added when that name is taken. The desktop app
exports to the Downloads folder. A standalone bridge uses
LiveBridgeOptions.exportDir, which defaults to ~/Downloads, or to the
system temp folder when ~/Downloads is missing.
One export runs at a time. A second export_video fails with export-busy
until the first finishes or cancel_export stops it. The bridge keeps the last
ten jobs.
If the Studio tab that owns the job disconnects while the export is starting or
rendering, the job fails with Studio disconnected during export. A tab that
was replaced can close without failing the export that belongs to the new tab.
cancel_export while the bridge is still writing the file removes that file
and leaves the job cancelled. After the file is in place the job is done, and
cancel_export answers that the export is already done.
Generated operator tools
Every operator in the @mcut/editor operator table becomes an MCP tool named:
operator_<operator-id-with-non-tool-characters-replaced>For example, edit.splitSelectionAtPlayhead becomes
operator_edit_splitSelectionAtPlayhead.
Prefer operator tools for UI-parity edits because they understand playback, selection, and editor context.
In live bridge mode, prefer high-level actions when they exist:
- Remove spoken-word silence with
run_actionandactionId: "transcript.remove-silence"afterensure_transcripthas produced word-timed captions. - Open from black and close to black with
run_actionandactionId: "effects.fade-open-close"so the built-in animation presets are used.
Do not fall back to ffmpeg or shell audio analysis for agent edits that mcut
tools can perform.
Generated command tools
Every command in the @mcut/timeline command table also becomes an MCP tool.
The command description becomes the tool description and the zod payload schema
becomes the MCP input schema.
Use command tools for exact project mutations when you already know the target ids and payload.
Import local media
import_media takes paths, from 1 to 50 absolute file paths. A leading ~/ expands to the home folder. The bridge
checks that each path exists, is a non-empty regular file, and has a known
media extension. Studio fetches each accepted file from a one-call bridge URL,
then probes it, registers the asset, and stores the bytes the same way the
Import button does. The result lists imported assets and per-file failures.
When nothing imports, the tool result is an error. Place an imported asset
with addElement or an operator.
list_actions marks dialog and save actions with humanOnly. run_action
rejects those actions and rejects a non-empty input on an action that has
no input schema. addAsset rejects a file: URL and probes every other
source before the command is applied. Missing metadata is filled from that
probe.