OSS · MCP サーバー · TypeScript

opencut-mcp

動画エディタには自動化の口がない。作った。

OpenCut classic を Claude Code / Cline などの MCP クライアントから操作する Model Context Protocol サーバー。Playwright がエディタセッションを保持し、12 個のツールがタイムライン・メディアアセット・エクスポートパイプラインを公開する。

GitHub で見る v0.1.0 リリースノート

Claude が opencut-mcp 経由で OpenCut classic を操作している様子。プロジェクト作成 → 動画アップロード → 音声アップロード → タイムラインへの自動配置 → 5 秒地点で動画を split。すべて MCP のツール呼び出し経由。
10 秒の end-to-end 実行: プロジェクト作成 → 動画アップロード → 音声アップロード → 別トラックへ自動配置 → 5 秒地点で split。手動クリック 0 回、すべて MCP ツール呼び出し。

12 個の MCP ツール

ブラウザ側の TimelineManager / MediaManager / RendererManager を 1 対 1 でラップ。タイムラインへの変更はすべて CommandManager 経由なので undo/redo がそのまま効きます。

ツール 内容
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).

ローカルで動かす

シェル 2 枚並べて使います。fork の classic がエディタ本体を配信し、opencut-mcp が 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

ドキュメントに書かれていない 4 つの罠

実装しながら 1 つずつ潰した挙動です。次に触る人は素通りできるように残しておきます。

  1. 空トラックは毎コマンドで prune される

    core/index.ts の CommandManager reactor が、要素 0 のオーバーレイ/音声トラックを毎コマンド後に filter で落とします。addTrack → insertElement の 2 段構えは間の reactor でトラックが消えて 2 段目が失敗します。placement { mode: "auto", trackType } で 1 コマンドで挿入すれば、コマンド自身がトラックを作りつつ要素も入れるため survive します。

  2. MediaTime は秒ではなく整数ティック

    TimelineElement の時刻フィールド (startTime, duration, trimStart, trimEnd, sourceDuration) は整数ティックのブランド型で、TICKS_PER_SECOND は 120000。15.008 をそのまま渡すと requireMediaTime() が throw します。ブラウザ境界で window.__opencut.mediaTimeFromSeconds({ seconds }) を挟むこと。

  3. AudioElement は discriminated union

    アップロード音声は mediaId に加えて sourceType: "upload" を伴う必要があります。無いと InsertElementCommand.validateElementBasics が console.error だけ吐いて silent reject します。CommandManager 側は throw しないので、console を hook しないと気づけません。

  4. Import の file input は display:none で常時 DOM に居る

    useFileUpload が hidden な <input type="file"> を常時レンダリングしています。Playwright は setInputFiles で直接触れるので、Import ボタンを踏む必要はありません。drag&drop 経路を丸ごとスキップできて、UI が最終的に呼ぶ経路と同じところに着地します。

関連する開発ツール

プロダクト一覧 →

← プロダクト一覧へ