MCP server by none-stack-developer
ffmpeg-mcp
An MCP (Model Context Protocol) server for AI-agent-driven video editing, powered by FFmpeg.
It exposes FFmpeg as a set of safe, structured tools that an AI agent (Claude Desktop, Claude Code, or any MCP client) can call in natural language — "trim the first 10 seconds", "burn these subtitles in", "transcribe the speech to an SRT", "cut the silent parts".
The server shells out to the installed ffmpeg/ffprobe binaries; there is no FFmpeg source build required.
Requirements
- Node.js ≥ 18
- FFmpeg + ffprobe on your
PATH(or setFFMPEG_PATH/FFPROBE_PATH). A full build is recommended (libass, NVENC, whisper). Tested with FFmpeg 8.1.
Install & build
npm install
npm run build
Tools
| Tool | What it does |
|------|--------------|
| probe | Inspect a file: duration, format, bitrate, streams (codec/resolution/fps/channels). |
| trim | Cut a segment by start + end/duration. Stream-copy (fast) or re-encode (frame-accurate). |
| concat | Join clips. copy (same codecs) or reencode (normalize). |
| convert | Transcode: format/codec/resolution/fps/bitrate. Supports NVENC (h264-nvenc, …). |
| extract_audio | Pull the audio track out (mp3/aac/wav/flac/opus). |
| thumbnail | Single frame at a time, or frames every N seconds. |
| burn_subtitles | Hard-burn an .srt/.ass file onto the video. |
| overlay | Watermark image / picture-in-picture, with position, scale, opacity. |
| auto_subtitle | Speech → subtitles via FFmpeg's whisper filter (needs a model — see below). |
| cut_silence | Detect silent spans and remove them. |
All tools resolve relative paths against the working directory (or FFMPEG_MCP_WORKDIR), validate that inputs exist, and refuse to overwrite outputs unless you pass overwrite: true.
Configuration (environment variables)
| Var | Purpose |
|-----|---------|
| FFMPEG_PATH / FFPROBE_PATH | Full path to the binaries if not on PATH. |
| FFMPEG_MCP_WORKDIR | Base directory for resolving relative paths. |
| WHISPER_MODEL_PATH | Default whisper.cpp model file for auto_subtitle. |
Whisper model (for auto_subtitle)
The whisper filter needs a ggml-*.bin model (not bundled — it's large). Fetch one with the helper script:
npm run download-model # downloads ggml-base.bin into ./models
npm run download-model -- small # or another size: tiny | base | small | medium | large
Then point the server at it via WHISPER_MODEL_PATH (see registration below), or pass model per call.
You can also download manually from
huggingface.co/ggerganov/whisper.cpp.
Register with Claude
Claude Code
claude mcp add ffmpeg -- node /absolute/path/to/ffmpeg-mcp/dist/index.js
Claude Desktop (claude_desktop_config.json)
{
"mcpServers": {
"ffmpeg": {
"command": "node",
"args": ["C:\\absolute\\path\\to\\ffmpeg-mcp\\dist\\index.js"],
"env": {
"WHISPER_MODEL_PATH": "C:\\models\\ggml-base.bin"
}
}
}
}
Develop & verify
npm test # unit + real-ffmpeg E2E tests (fixtures generated by ffmpeg)
npm run inspect # launch the MCP Inspector against the server
The Inspector lets you call each tool interactively and see the JSON results.
Project structure
src/
index.ts # MCP server bootstrap (stdio), tool registration
ffmpeg/
locate.ts # resolve ffmpeg/ffprobe (PATH or env override)
runner.ts # spawn wrapper: args-array (no shell), progress, errors
probe.ts # ffprobe -> structured metadata
lib/
paths.ts # input/output path validation & overwrite policy
schema.ts # shared zod fragments (timecode, resolution)
tools/ # one file per MCP tool + registry (index.ts)
test/ # unit tests + real-ffmpeg E2E (fixtures via lavfi)
scripts/
download-model.mjs # fetch a whisper ggml model into ./models
Design notes
- No shell interpolation — ffmpeg is always invoked with an argument array, so user-supplied paths cannot inject commands.
- Path safety — inputs must exist; outputs never overwrite unless
overwrite: true. - No FFmpeg build — the server calls the installed binaries; nothing is compiled.
Contributing
Issues and PRs are welcome. Please run npm run build and npm test before opening a PR.
License
MIT © Sohn EuiJin