New:Microsoft Teams Notifications Are Now Available in Socket.Learn more →
Get Started

@leclap/mcp

Package Overview
Dependencies
Maintainers
1
Versions
8
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@leclap/mcp

MCP server exposing ffmpeg-video-composer as agent-callable video composition tools

latest
Source
npmnpm
Version
0.3.5
Version published
Weekly downloads
230
400%
Maintainers
1
Weekly downloads
 
Created
Source

@leclap/mcp

An MCP server that exposes the ffmpeg-video-composer engine as agent-callable video tools.

An AI agent (Claude Desktop, Cursor, …) is the LLM; this server helps it author a customized template with nice effects from the schema, then validates and renders it deterministically to an mp4. The server ships no built-in template catalog — it is decoupled from the app's creative-kit — so it stays a generic authoring tool. Remotion-assisted authoring is a bonus path. The result is agent-composable, deterministic, reproducible video — the opposite of generative video models, which sample rather than render.

Tools

ToolDescription
get_template_schemaThe JSON Schema for a template descriptor + a short authoring guide
validate_templateDry-run an inline descriptor (no render) → { valid, sectionCount, orientation, requiredClips, formFields, geometry? }
compose_videoValidate an inline descriptor and render → { outputPath, durationSeconds, sizeBytes, videoCodec, audioCodec, renderId }, plus a resource_link to the mp4
probe_mediaInspect a local media file → codecs, duration, sample rate, size
render_remotion_clip(bonus, opt-in) Render a composition from your own Remotion project → an mp4 clip for a project_video section
pingLiveness check

Typical agent flow: get_template_schema → author an inline descriptor (optionally prepend a render_remotion_clip intro) → validate_template (instant, iterate until valid) → compose_video → read the returned outputPath.

validate_template also reports, render-free, text that would run off the frame or out of title-safe, collide with other text, sit under a band, be too small, lack contrast, or sit over footage with no box, outline or shadow. Those findings arrive on the optional geometry field — one line each, saying what to change, and the field is absent entirely when there is nothing to fix. They are advisory: valid stays true. A line ending (approx: …) says why it is an estimate: the font could not be read, the text carries a {{ variable }} that only resolves at render time, or a section declares no duration. When a font is not bundled, the server fetches it from the LeClap asset catalog (5s timeout); offline, it estimates.

Pass render: true to validate_template to also render the sections that hold text and measure their contrast from real pixels — it settles text over images, grades and looks that the render-free check can only call unknown. It costs seconds (two renders of those sections), goes through the same media-dir sandbox as compose_video, reads assets from the media dir, and runs in the same forked render worker under the same timeout. It adds a render field (measured, seconds, and unavailable when it could not render — no FFmpeg with drawtext, a failed render, or a timeout); the render-free findings come back either way.

Recipe: video evidence for a pull or merge request

An agent working on a code change can use LeClap to package visual evidence for review:

  • Collect a short, real screen recording and state what the reviewer should inspect.
  • Author or reuse a review template such as examples/agentic-pr-video, or its evidence-video skill, which composes before/after cards and panels with measured captions first.
  • Call validate_template until the descriptor is valid.
  • Call compose_video with the recording in userVideoPaths and the review context in fields.
  • Attach the returned outputPath to the PR or MR beside the diff.

The MCP server renders and returns a local artifact. It does not upload to GitHub or GitLab; that remains an explicit step in the surrounding agent workflow.

Bring-your-own Remotion (optional). If you have a Remotion project, render_remotion_clip renders one of its compositions — genuine motion graphics (spring physics, kinetic typography) an FFmpeg filtergraph can't express — to an mp4. Point it at your entry (the module that calls registerRoot) or a prebuilt serveUrl, plus a compositionId and optional inputProps; or set a default with --remotion-entry / LECLAP_MCP_REMOTION_ENTRY. Feed the returned clip to compose_video as a project_video clip (via userVideoPaths) and the deterministic engine composites it in front of your scenes. It needs the optional peer deps @remotion/renderer + @remotion/bundler and is design-time only (headless Chromium) — everything else in the MCP stays self-contained and on-device.

Prompt

compose-video — a guided authoring prompt (surfaces as /compose-video in clients like Claude Desktop). Takes optional goal and orientation arguments and primes the agent with the schema, the premium building-block recipes (which filters give which look, the bundled font list, the on-device filter allowlist), and the validate_template → compose_video loop.

Run

# published — no checkout needed
npx -y @leclap/mcp
# or from a checkout: build the engine + this server, then start it over stdio
pnpm --filter ffmpeg-video-composer build
pnpm --filter @leclap/mcp build
node packages/leclap-mcp/dist/index.js

It speaks MCP over stdio (stdout is the protocol channel — all diagnostics go to stderr). The published bin is leclap-mcp.

FFmpeg. compose_video renders with the engine's FFmpeg: system FFmpeg first, then the bundled ffmpeg-static. ffmpeg-static ships no ffprobe. Templates with transitions, music, whole-video overlays or project_video clips need one, and so does probe_media. On that path a render stops before encoding and names the missing binary. Installing FFmpeg (brew install ffmpeg, sudo apt install ffmpeg) provides both. The optional ffprobe-static package, installed next to the server, also works.

Built on the MCP TypeScript SDK (@modelcontextprotocol/server), tracking the current protocol revision. Clients on an older revision keep working — the stdio entry serves both eras from the same tool definitions.

Configuration

SettingFlagEnvDefault
Output dir--output-dirLECLAP_MCP_OUTPUT_DIR~/.leclap/renders
Media allowlist--media-dirLECLAP_MCP_MEDIA_DIR~/.leclap/media
Remotion opt-in--allow-remotionLECLAP_MCP_ALLOW_REMOTIONoff
Render timeout--render-timeout-msLECLAP_MCP_RENDER_TIMEOUT_MS600000 (10 min)

Each render writes to <output-dir>/<renderId>/. Local input files (userVideoPaths, probe_media) must resolve inside the media-dir (symlink-safe containment check). The media-dir default is deliberately narrow — pointing it at ~ would let any tool call read the whole home directory. render_remotion_clip executes your project's own JS, so it is registered only when the opt-in is set (--allow-remotion or LECLAP_MCP_ALLOW_REMOTION=1); leclap init --remotion scaffolds a .mcp.json with it enabled.

Claude Desktop

~/Library/Application Support/Claude/claude_desktop_config.json (absolute paths only — env values are not tilde-expanded):

{
  "mcpServers": {
    "leclap": {
      "command": "npx",
      "args": ["-y", "@leclap/mcp"],
      "env": {
        "LECLAP_MCP_OUTPUT_DIR": "/abs/path/to/Movies/leclap-renders",
        "LECLAP_MCP_MEDIA_DIR": "/abs/path/to/Movies"
      }
    }
  }
}

From a checkout, swap the command for "command": "node" with "args": ["/abs/path/to/ffmpeg-video-composer/packages/leclap-mcp/dist/index.js"].

Then ask the agent to "compose a 10-second vertical title card with a fade-in and music, then render it" — it fetches the schema, authors a descriptor, validates it, and renders. Open the returned outputPath. (There is no catalog to list: the server authors templates rather than serving stock ones.)

Inspector

npx @modelcontextprotocol/inspector node packages/leclap-mcp/dist/index.js

Architecture

compose_video never runs the compile in the server process. The core logs to stdout during a render (including pino writing directly to fd 1), which would corrupt the MCP JSON-RPC stream — so the render runs in a forked child worker (dist/render-worker.js) and the result returns over the IPC channel, never the child's stdout. This also gives clean error capture (the parent buffers the worker's logs), render timeouts, and DI state isolation between renders.

compose_video returns a resource_link pointing at the rendered file rather than inlining megabytes of base64 — the client opens or fetches it. Render progress is written to stderr ([compose_video] render <id> NN%), not sent as a protocol notification: the per-request log channel is deprecated in the current revision, and stdout is reserved for JSON-RPC framing.

Security is inherited from the core: FFmpeg runs via execFile (no shell); remote template URLs are SSRF-guarded (private/metadata IPs + redirects blocked, http(s) only); descriptors are safeParse-validated; local file paths are containment-checked against the media dir.

Tests

pnpm --filter @leclap/mcp test              # vitest unit tests (mocked render)
pnpm --filter @leclap/mcp test:integration  # cucumber BDD over real stdio + a real render

The integration suite spawns the built server over stdio and renders a self-contained color-card template end to end — the regression guard proving the stdio framing survives a real (pino-heavy) compile.

Not yet (future)

Streamable HTTP transport, MCP resources (leclap://templates/{name}), client-visible progress notifications, remote-URL probing, an async job API.

Part of the LeClap monorepo.

Keywords

mcp

FAQs

Package last updated on 28 Sep 2026

Related posts