ffmpeg-mcp
README.md
# ffmpeg-mcp
[](LICENSE)
[](https://nodejs.org)
[](https://modelcontextprotocol.io)
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 set `FFMPEG_PATH` / `FFPROBE_PATH`).
A full build is recommended (libass, NVENC, whisper). Tested with FFmpeg 8.1.
## Install & build
```bash
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:
```bash
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](https://huggingface.co/ggerganov/whisper.cpp/tree/main).
## Register with Claude
### Claude Code
```bash
claude mcp add ffmpeg -- node /absolute/path/to/ffmpeg-mcp/dist/index.js
```
### Claude Desktop (`claude_desktop_config.json`)
```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
```bash
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](LICENSE) © Sohn EuiJin
This server cannot be deployed
Maintenance
ActivityInactive
ResponsivenessNo issues