Skip to main content
Glama

ffmpeg-mcp

ffmpeg-mcp 🎬⚡

Edit video and audio by just talking to your AI assistant.

ffmpeg-mcp is a Model Context Protocol server that puts the full power of FFmpeg behind a clean set of tools your LLM can call — clip, crop, scale, overlay, concatenate with transitions, extract frames/audio, make GIFs, and more. No command-line flags to memorize.

Python FastMCP FFmpeg PRs Welcome Stars


✨ Why ffmpeg-mcp?

FFmpeg is incredibly powerful and incredibly hard to remember. ffmpeg-mcp hands that power to your AI assistant so you can say what you want in plain English:

"Grab the first 10 seconds of demo.mov, scale it to 1080p, slap my logo in the top-right corner, and turn it into a GIF."

…and the model orchestrates the right tools for you. Each tool is a small, validated Python function — easy to read, reuse, and extend.

  • 🗣️ Natural-language video editing — works in any MCP client (Claude Desktop, Cursor, Cline, …)

  • 🧱 12 focused tools — composable building blocks instead of one giant black box

  • ✅ Input validation built in — paths are checked for existence, emptiness, and validity before FFmpeg runs

  • 🧩 Hackable — add a new tool by writing one function and registering it


Related MCP server: ff-toolkit

🛠️ Available Tools

Tool

What it does

Key parameters

get_video_metadata

Probe a file for streams, codecs, duration, etc.

input_video_path

extract_frames

Save frames as images (evenly, by interval, or 1/sec)

input_video_path, number_of_frames?, timestamp_offset?

extract_audio

Pull audio out to a .wav file

input_video_path

scale_video

Upscale to 1080p / 2k / 4k, aspect-preserving

input_video_path, resolution="1080p"

crop_video

Crop to a region

input_video_path, width, height, x_offset, y_offset, safe_crop

clip_video

Cut a sub-clip by start + duration

input_video_path, start_timestamp, duration

make_gif

Turn a segment into an optimized GIF

input_video_path, start_timestamp, duration

overlay_image

Composite an image (logo/watermark) with timing & opacity

input_video_path, overlay_image_path, positioning, opacity, start_time, duration

overlays_video

Overlay a (looping) video onto another

input_video_path, overlay_video_path, positioning, scale

trim_and_concat_operation

Trim multiple clips and stitch them together

inputs: [{path, start_time?, end_time?}], width, height

get_normalized_clips

Normalize clips to a common res/fps/codec (in parallel)

input_video_clips, resolution, frame_rate, crf

concat_clips_with_transition

Concatenate clips with an xfade transition

input_video_clips, transition_type="fade", transition_duration

? marks optional parameters. concat_clips_with_transition supports many transitions — fade, wipeleft, slideup, circlecrop, dissolve, pixelize, radial, and dozens more.


📦 Requirements

  • Python 3.12+

  • FFmpeg installed and on your PATH (provides ffmpeg + ffprobe)

  • uv package manager

Verify FFmpeg is available:

ffmpeg -version

🚀 Quick Start

1. Clone & install

git clone https://github.com/yubraaj11/ffmpeg-mcp.git
cd ffmpeg-mcp
uv sync --frozen

2. Connect it to your MCP client

Point your client at the server using the snippets below. Replace /path/to/ffmpeg-mcp with the absolute path to your clone.

{
  "mcpServers": {
    "ffmpeg-mcp": {
      "command": "uv",
      "args": ["--directory", "/path/to/ffmpeg-mcp/ffmpeg_mcp", "run", "main.py"],
      "env": { "PYTHONPATH": "/path/to/ffmpeg-mcp" }
    }
  }
}
{
  "mcpServers": {
    "ffmpeg-mcp": {
      "autoApprove": [],
      "disabled": false,
      "timeout": 60,
      "command": "uv",
      "args": ["--directory", "/path/to/ffmpeg-mcp/ffmpeg_mcp", "run", "main.py"],
      "env": { "PYTHONPATH": "/path/to/ffmpeg-mcp" },
      "transportType": "stdio"
    }
  }
}

3. Restart your client and start editing

"Extract 5 evenly-spaced frames from intro.mp4."

"Make a 3-second GIF from clip.mov starting at 12s."

"Concatenate a.mp4, b.mp4, and c.mp4 with a 1-second wipeleft transition between them."

Processed files are written under ffmpeg_mcp/processed_elements/.


🧰 Project Layout

ffmpeg_mcp/
├── main.py              # MCP server entry point — registers all tools
├── services/            # one module per tool
├── configs/             # colored logging setup
└── exceptions/          # structured error messages
utils/                   # validation decorators & helpers

Every tool returns either the output file path or a structured JSON error (status, error_type, message, time), so failures are easy for the model to read and recover from.


🤝 Contributing

Contributions are very welcome! Adding a tool is roughly:

  1. Write a function in ffmpeg_mcp/services/your_tool.py.

  2. Export it from ffmpeg_mcp/services/__init__.py.

  3. Register it in main.py with mcp.tool(name_or_fn=your_tool).

Please run the linter before opening a PR:

uv run ruff check .

Found a bug or have an idea? Open an issue — and if this project saves you from another ffmpeg man-page dive, consider leaving a ⭐.


📚 Built With

Available Tools

12 tools
clip_videoA

Generate a video clip from the given video file using ffmpeg-python.

Args: input_video_path (str): Path to the source video file. start_timestamp (float, optional): Start time in seconds. Defaults to 0.0. duration (float, optional): Clip length in seconds. Defaults to 5.0.

Returns: str: Path to the generated clip, or an exception message string on failure.

Inputs: input_video_path (required), start_timestamp, duration.

concat_clips_with_transitionA

Concatenate multiple video clips with transitions.

Args: input_video_clips (List[str]): A list of file paths (strings) to the video clips that will be concatenated. transition_type (str, optional): The type of transition to apply between clips. Supported transitions include: - fade (default), fadeblack, fadewhite, distance - wipeleft, wiperight, wipeup, wipedown - slideleft, slideright, slideup, slidedown - smoothleft, smoothright, smoothup, smoothdown - circlecrop, rectcrop, circleclose, circleopen - horzclose, horzopen, vertclose, vertopen - diagbl, diagbr, diagtl, diagtr - hlslice, hrslice, vuslice, vdslice - dissolve, pixelize, radial, hblur - wipetl, wipetr, wipebl, wipebr - zoomin, fadegrays, squeezev, squeezeh - hlwind, hrwind, vuwind, vdwind - coverleft, coverright, coverup, coverdown transition_duration (float, optional): Duration of the transition effect in seconds.

Returns: str: The absolute path to the final concatenated video with transitions applied.

Inputs: input_video_clips (required), transition_type, transition_duration. Returns: result

crop_videoB

Crop a video using ffmpeg-python.

Params: input_video_path: Path to input video (required) safe_crop: If True, allows exact cropping (ignores mod-2 restrictions). Default: False height: Output height (default: 480) width: Output width (default: 640) x_offset: Top-left X coordinate of crop (default: 0) y_offset: Top-left Y coordinate of crop (default: 0)

Returns: str: Path to the cropped video.

Inputs: input_video_path (required), safe_crop, height, width, +2 more.

extract_audioB

Function to extract audio from the given input video.

Params: input_video_path (str): Path to the input video.

Returns: audio_file_path (str): Path to the audio file.

Inputs: input_video_path (required).

extract_framesA

Extract frames from a video file and save each frame with a unique UUID filename.

Behavior: - If number_of_frames is provided, extracts that many frames evenly across the video. If requested frames exceed total frames available, caps at total frames. - If timestamp_offset is provided (and number_of_frames is None), extracts frames at every given second interval. - If neither is provided, defaults to extracting one frame per second. - number_of_frames takes priority if both are provided.

Params: input_video_path (str): Path to the input video file. number_of_frames (Optional[int]): Total number of frames to extract evenly across the video. timestamp_offset (Optional[int]): Time interval in seconds between frames.

Returns: List[str]: List of file paths for the extracted frames with UUID-based filenames.

Inputs: input_video_path (required), number_of_frames, timestamp_offset. Returns: result

get_normalized_clipsA

Normalize multiple video clips in parallel by adjusting resolution, frame rate, codec, and compression parameters.

Parameters: input_video_clips (list[str]): should give input video clips in the form of string resolution (tuple, optional): Target resolution as (width, height). Defaults to (1280, 720). frame_rate (int, optional): Target frame rate. Defaults to 30. crf (int, optional): Constant Rate Factor for quality control (lower = better quality). Defaults to 23. audio_bitrate (str, optional): Target audio bitrate. Defaults to '128k'. preset (str, optional): Encoding speed vs. compression efficiency preset. Defaults to 'fast'. max_workers (int, optional): Number of parallel worker threads. If None, uses os.cpu_count().

Returns: list: Sorted list of file paths to the successfully normalized video clips.

Notes: - Runs normalization tasks in parallel using ThreadPoolExecutor. - Includes a progress bar (tqdm) to track processing status. - Automatically determines the number of workers based on CPU cores if not specified. - Skips clips that encounter errors but continues processing the rest.

Inputs: input_video_clips (required), resolution, frame_rate, crf, +2 more.

get_video_metadataC

Function to extract metadata of the given input video.

Params: input_video_path (str): Path to the input video.

Returns: JSON of the video metadata.

Inputs: input_video_path (required).

make_gifB

Make gif using video path provided by user.

Args: input_video_path (str): Path to the source video file. start_timestamp (float, optional): Start time in seconds. Defaults to 0.0. duration (float, optional): Clip length in seconds. Defaults to 4.0.

Returns: str: Path to the generated clip, or an exception message string on failure.

Inputs: input_video_path (required), start_timestamp, duration.

overlay_imageA

Overlay an image on top of a video with timing control.

Args: input_video_path (str): Path to background video. overlay_image_path (str): Path to image file. output_filename (str): Output video filename (saved inside VIDEO_OVERLAY_PATH). positioning (Literal): Where to place overlay. scale (tuple | None): (width, height) to resize image before placing. keep_audio (bool): Whether to keep background audio. opacity (float | None): Transparency level (0–1). None = no alpha applied. start_time (float): When to start showing overlay (seconds). duration (float | None): How long to show overlay (seconds). None = until end of video.

Returns: str: Path to generated video.

Inputs: input_video_path (required), overlay_image_path (required), output_filename, positioning, +5 more. Returns: result

overlays_videoA

Overlay a video on top of another with simple positioning. Loops the overlay video until the background video ends, trimming any extra frames.

Args: input_video_path (str): Path to background video. overlay_video_path (str): Path to overlay video. output_filename (str): Name of the output video file (saved inside VIDEO_OVERLAY_PATH). positioning (Literal): Where to place overlay. scale (tuple): (width, height) to resize overlay video before placing. keep_audio (bool): Whether to keep background audio.

Returns: str: Path to the generated video.

Inputs: input_video_path (required), overlay_video_path (required), output_filename, positioning, +2 more. Returns: result

scale_videoA

Upscales a video to 1080p, 2K, or 4K using FFmpeg while preserving aspect ratio and color accuracy.

Args: input_video_path (str): Path to the input video file. resolution (str, optional): Target resolution for upscaling. Acceptable values are '1080p', '2k', or '4k'. Defaults to '1080p'.

Returns: str: Path to the upscaled video if successful.

Inputs: input_video_path (required), resolution. Returns: result

trim_and_concat_operationA

Trim and concatenate multiple videos (portrait orientation, normalize format).

Args: inputs (list[dict]): Each dict must have: - 'path' (str): path to the video file - 'start_time' (str, optional): start time in seconds - 'end_time' (str, optional): end time in seconds width (int): Width to scale each video (portrait). height (int): Height to scale each video (portrait). x (int): X position for overlay (default 0). y (int): Y position for overlay (default 0).

Returns: str: Path to the output video if successful. None: If an error occurs.

Inputs: inputs (required), width, height, x, +1 more. Returns: result

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A3.6/5.0

    Scored across 12 tools

    Disambiguation4/5

    Most tools have distinct purposes like clipping, cropping, extracting, and overlaying, but some overlap exists: 'clip_video' and 'trim_and_concat_operation' both involve trimming video segments, which could cause confusion. However, their descriptions clarify that 'clip_video' is for single clips while 'trim_and_concat_operation' handles multiple videos with concatenation, mitigating ambiguity.

    Naming Consistency3/5

    The naming is mixed with no clear pattern: some tools use verb_noun (e.g., 'clip_video', 'crop_video'), others use noun_verb (e.g., 'get_video_metadata'), and there are inconsistencies like 'overlay_image' vs. 'overlays_video'. While readable, the lack of a consistent convention across all tools reduces predictability.

    Tool Count5/5

    With 12 tools, the count is well-scoped for a video processing server, covering essential operations like editing, conversion, and metadata extraction. Each tool serves a specific function without redundancy, making the set comprehensive yet manageable for typical video manipulation tasks.

    Completeness4/5

    The toolset covers core video processing needs including clipping, cropping, scaling, overlaying, and format conversion, with good lifecycle coverage. Minor gaps exist, such as no direct tool for adding subtitles or advanced audio editing beyond extraction, but agents can likely work around these with the provided tools.

    Maintenance

    ActivityInactive
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers