OSS · MCP Server · TypeScript
opencut-mcp
Video editors ship without an automation seam. Add one.
A Model Context Protocol server that drives OpenCut classic from Claude Code, Cline, or any MCP client. Playwright holds the editor session; twelve tools expose the timeline, media assets, and export pipeline.
Twelve MCP tools
One-to-one wrappers over TimelineManager / MediaManager / RendererManager on the browser side. All timeline mutations flow through CommandManager, so undo/redo just works.
| Tool | What it does |
|---|---|
opencut_get_state | Timeline snapshot (tracks, elements, media assets, total duration). |
opencut_add_media | Upload a local file as a MediaAsset via the hidden file input. |
opencut_insert_clip | Place an element on a track. Auto-placement creates the track on demand. |
opencut_split_at | Split element(s) at a time (seconds). Undoable via opencut_undo. |
opencut_move | Move an element to a new start time or a different track. |
opencut_trim | Update trim/duration on an element. |
opencut_delete | Delete element(s). |
opencut_add_track | Add a track explicitly (rarely needed — prefer auto placement). |
opencut_undo / opencut_redo | CommandManager history navigation. |
opencut_export | RendererManager.exportProject, awaited to completion. |
opencut_screenshot | Screenshot the editor viewport (debugging). |
Running it locally
Two shells side by side: the fork of classic serves the editor, opencut-mcp attaches to it over the stdio MCP transport.
# 1. Fork of OpenCut classic (editor host, port 3000)
git clone https://github.com/kenimo49/opencut-classic
cd opencut-classic
docker compose up -d db redis serverless-redis-http
bun install
bun run dev:web
# 2. opencut-mcp (in another shell)
git clone https://github.com/kenimo49/opencut-mcp
cd opencut-mcp
bun install
bunx tsx src/index.ts # stdio transport, ready for MCP client
# ...or run the demo:
bunx tsx scripts/demo.ts Four things that were not in the docs
Each of these took a debugging round to surface. Documented so the next reader skips them.
-
Empty tracks are pruned every command
A CommandManager reactor in core/index.ts filters out overlay/audio tracks with zero elements after every command. A two-step "addTrack then insertElement" loses the track before the second call lands. The fix is to insert with placement { mode: "auto", trackType } — the insert command creates the track on demand and it survives because it has an element.
-
MediaTime is integer ticks, not seconds
TIME fields on TimelineElement (startTime, duration, trimStart, trimEnd, sourceDuration) are branded integer tick counts at runtime — TICKS_PER_SECOND is 120,000. Passing 15.008 straight through throws inside requireMediaTime(). Convert with window.__opencut.mediaTimeFromSeconds({ seconds }) at the browser boundary.
-
AudioElement is a discriminated union
Uploaded audio must carry sourceType: "upload" alongside mediaId. Without it, InsertElementCommand.validateElementBasics silently rejects the element via console.error and moves on. Catch the console channel to see the message — the CommandManager itself does not throw.
-
The Import file input is always mounted, just display:none
useFileUpload renders a hidden <input type="file"> at all times. Playwright can setInputFiles on it directly — no need to click the Import button first. This bypasses the drag-and-drop path entirely and matches what the UI would eventually call.
Related developer tools
- hook-chain-lens A read-only CLI that reads every Claude Code hook scope (user, project, local, plugin) and prints what will actually fire in this cwd, in what order, from where.
- private-lint Git-hook gate that blocks personal and private names (family names, personal emails, client domains) before commit and push. Pure Bash; detection patterns stay machine-local, never in any repo, and a full-history audit covers the moment before you flip a repository public.
- quake-lens Earthquake statistics CLI + MCP server in pure-stdlib Python: Gutenberg-Richter b-value (Aki MLE) and Omori-Utsu aftershock decay (Ogata MLE) from public catalogs.
- rhythm-lens Measures the rhythm of Japanese, English and Portuguese Markdown (sentence-length burstiness, paragraph structure) against measured human/AI distributions from two published papers. A writing feedback instrument, not an AI detector.