mcut

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.json

The 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.

ToolPurpose
get_summaryCompact project summary. Read this before editing.
get_projectFull serializable project JSON.
get_media_contextProject, playback, selection, asset, track, element, marker, and transcript metadata.
get_frameLive bridge only. PNG of one timeline frame. Call it before placing a zoom or a crop.
find_scene_changesLive 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_sheetLive 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_activityLive 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_transcriptCaption-derived transcript. Never starts transcription.
search_transcriptFind 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_retakesRetake 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_rangesRemove 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_transcriptLive 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_commandsLive bridge only. Every raw timeline command schema.
apply_commandsLive bridge only. Apply several commands in one undoable transaction. A failed command leaves the project unchanged.
apply_captionsTurn 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_transcriptReplace 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_cutsCut transcript silence out of one clip as one undoable edit.
lint_projectCross-entity problems parseProject cannot reject, each with a severity and code.
list_zoomsEvery zoom region with its element, timing, target, easing, and motion blur.
edit_zoomsAdd, update, or remove zoom regions as one undoable edit. A rejected edit leaves the project unchanged.
center_personLive 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_presetsPlatform delivery presets with dimensions, fps, and safe areas.
list_operatorsList available UI-level editor operators.
run_operatorLive bridge only. Run an operator by id.
list_actionsLive bridge only. List editor actions.
run_actionLive bridge only. Run an editor action by id. Human-only actions are rejected.
import_mediaLive bridge only. Import local media by absolute path. Studio probes each file, registers the asset, and stores the bytes.
transactApply 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.
undoUndo the most recent edit. One undo step is one tool call or one whole transact.
redoRedo the most recently undone edit.
export_videoLive bridge only. Start rendering the whole timeline to a video file and return its jobId.
get_exportLive bridge only. State, percent, and ETA of an export job. waitMs waits for it to finish.
cancel_exportLive 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_action and actionId: "transcript.remove-silence" after ensure_transcript has produced word-timed captions.
  • Open from black and close to black with run_action and actionId: "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.

On this page