Skip to main content
Glama
README.md
# ffmpeg-mcp

[![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
[![Node](https://img.shields.io/badge/node-%3E%3D18-blue.svg)](https://nodejs.org)
[![MCP](https://img.shields.io/badge/MCP-server-purple.svg)](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

Maintenance

ActivityInactive
ResponsivenessNo issues