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.

View on GitHub v0.1.0 release notes

Claude driving OpenCut classic via opencut-mcp — creates a project, uploads a video and an audio file, places both on the timeline, splits the video at 5 seconds. All from MCP tool calls.
10-second end-to-end run: project creation → video upload → audio upload → auto-placement on separate tracks → split at 5s. No human clicks, only MCP tool invocations.

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.

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

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

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

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

All products →

← Back to products