footage-mcp
Raw-recording preparation — transcribe a take, propose the cuts, validate the edit list, and render a clean asset for either video engine.
This server is the footage workbench's agent door — the step before
either video engine, where a raw recording (a talking-head take, a screen
capture, an explainer) becomes a clean, condensed cut. Its 15 footage_*
tools cover the whole preparation loop: register source clips, transcribe
them, propose cuts, validate and refine the edit list, trim and split,
apply a color grade, inspect the timeline, and render the finished cut. A
thin front over the automation daemon, like its creation-vertical
siblings.
The working object is the edit decision list: footage_propose_cuts
reads the transcript and proposes what to remove — fillers, retakes, dead
silence — and footage_validate_edl checks any edit list before it
renders. That keeps the judgment step (what stays in the take) reviewable
as plain data rather than buried in a render, and it is why the prepared
output — the clean cut plus its transcript and edit list — drops straight
into either engine's brief as an asset.
How your agents use it
- "Tighten this take." —
footage_add_source,footage_transcribe,footage_propose_cuts, review, thenfootage_renderfor the clean cut. - "Show me what the cut looks like before rendering." —
footage_timeline_viewlays out kept and removed segments;footage_trim_clipandfootage_split_cliphandle manual adjustments. - "Match the house look." —
footage_list_gradeslists the available color grades to apply at render.
Prerequisites
The automation daemon must be running (Dashboard ▸ Platform Health); transcription and rendering run locally on your machine. Daemon settings live in the configuration reference.
Tool reference
| Tool | Parameters | What it does |
|---|---|---|
footage_health | — | Footage-prep health: ffmpeg/ffprobe present, Grok-STT availability, render concurrency. No args. |
footage_list_grades | — | List available color-grade presets (subtle, neutral_punch, warm_cinematic, none) plus 'auto' (data-driven). No args. |
footage_transcribe | video_paths*: array, brief_id: string, revision_id: integer, engine: string, provider_name: string, transcript_source: string, language: string, diarize: boolean, keyterms: array, filler_words: boolean | Transcribe source mp4(s) to a word-level transcript.json + captions.json (HF caption shape). Uses Grok STT by default (word-level + diarization); pass transcript_source to ingest an externally-supplied SRT/VTT/word-JSON instead. Async — returns a job_id; poll with footage_get_job. Outputs land in the brief's assets/ (when brief_id given) or a standalone store. |
footage_propose_cuts | transcript_path*: string, source_name*: string, source_path*: string, silence_threshold: number, pad: number, grade: string | Produce a MECHANICAL baseline EDL that removes silences ≥ threshold from a transcript (deterministic, no judgment). Returns an EDL object to refine: drop retakes, pick the best take, tighten timing — that is the agent's editorial work. Single source. |
footage_validate_edl | edl*: object, base_dir: string, check_files: boolean | Validate an EDL object before rendering: sources non-empty, every range.source resolves, end>start, files exist. Returns {valid, errors[], expected_duration_s}. |
footage_render | edl: object, edl_path: string, brief_id: string, revision_id: integer, engine: string, output_dir: string, output_name: string, quality: string, draft: boolean, build_subtitles: boolean, transcript_paths: object, edl_base_dir: string | Render an EDL → cut.mp4 via the full pipeline (per-segment extract with 30ms fades + grade + HDR tonemap → lossless concat → overlay composite → subtitles burned LAST → two-pass loudnorm to -14 LUFS). Async — returns a job_id; poll with footage_get_job. Provide either `edl` (object) or `edl_path`. Output lands in the brief's assets/ (when brief_id given) as cut.mp4 + edl.json. |
footage_get_job | job_id*: string | Poll one footage-prep job (render or transcribe) by job_id. Returns status (queued|running|done|failed), outputs, and any error. |
footage_list_jobs | limit: integer | List recent footage-prep jobs (most recent first). |
footage_list_sources | brief_id*: string, revision_id: integer, engine: string | List a project's raw footage — the videos in the brief's assets/raw/ (+ any transcript/captions sidecars). This IS the project footage both the operator UI and agents share. Requires brief context. |
footage_add_source | brief_id*: string, source_path*: string, revision_id: integer, engine: string | Import a raw video into the project (copies it into the brief's assets/raw/) so the project is self-contained and the footage is accessible to both operator and agents. Returns the registered source. Idempotent. |
footage_remove_source | brief_id*: string, name*: string, revision_id: integer, engine: string | Remove a raw source (+ its transcript/captions sidecars) from a project's assets/raw/. |
footage_pack_transcripts | brief_id*: string, revision_id: integer, engine: string | Layer 1 (the primary reading view) — pack ALL the project's transcribed footage (assets/raw/*.transcript.json) into ONE phrase-level takes_packed.md: `[start-end] S<spk> text` per phrase, ~1/10 the tokens of raw word JSON. Transcribe sources first. Returns {path, markdown, sources}. Read this to reason about cuts efficiently. |
footage_timeline_view | video_path*: string, start*: number, end*: number, n_frames: integer, brief_id: string, revision_id: integer, engine: string | Layer 2 (on-demand visual) — generate a filmstrip + waveform PNG for a time range of a clip, so you can SEE the footage at a decision point (ambiguous pause, cut-point sanity, or self-eval of a rendered output at a cut boundary). Returns {image_path}; then use the Read tool on that PNG to inspect it. Pure ffmpeg. |
footage_trim_clip | brief_id*: string, source_path*: string, start*: number, end: number, out_name: string, revision_id: integer, engine: string | Non-destructively trim a clip to [start,end] → a NEW clip in the project (assets/raw/); the source is untouched. Frame-accurate, resolution preserved (a plain cut — no grade/fades). Returns {path,name,start,end}. |
footage_split_clip | brief_id*: string, source_path*: string, split_points*: array, revision_id: integer, engine: string | Non-destructively split a clip at point(s) → N NEW segment clips in the project (assets/raw/); the source is untouched. e.g. split_points=[12.5] → _part1 (0–12.5) + _part2 (12.5–end). Returns {parts:[{path,name,start,end}]}. |
Where to go next
- Video — the production studio — the footage workbench in the app, and the engines the output feeds
- remotion-mcp · hyperframes-mcp — the two engines a prepared cut lands in