convert_to_gif
Convert WebM videos to optimized GIFs using ffmpeg's two-pass palette method. Specify frame rate, dimensions, and trim start time for browser page recordings.
Instructions
Convert a .webm video to an optimized GIF using ffmpeg two-pass palette method.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| webmPath | Yes | Path to the .webm file | |
| fps | No | GIF frame rate (default 10) | |
| width | No | GIF width in pixels (default 640, height auto-scaled) | |
| startTime | No | Skip first N seconds (useful to trim blank loading frames) |
Implementation Reference
- src/converter.js:27-64 (handler)The actual implementation of the tool logic, using ffmpeg to convert a .webm file to an optimized GIF.
export async function convertToGif(webmPath, options = {}) { await checkFfmpeg(); await access(webmPath); // throws if file doesn't exist const fps = options.fps || 10; const width = options.width || 640; const startTime = options.startTime || 0; // skip blank loading frames const gifPath = options.outputPath || webmPath.replace(/\.webm$/, '.gif'); const palettePath = webmPath.replace(/\.webm$/, '-palette.png'); const scaleFilter = `fps=${fps},scale=${width}:-1:flags=lanczos`; const inputArgs = startTime > 0 ? ['-ss', String(startTime), '-i', webmPath] : ['-i', webmPath]; // Pass 1: generate palette await run('ffmpeg', [ ...inputArgs, '-vf', `${scaleFilter},palettegen=stats_mode=diff`, '-y', palettePath ]); // Pass 2: encode GIF with palette await run('ffmpeg', [ ...inputArgs, '-i', palettePath, '-lavfi', `${scaleFilter}[x];[x][1:v]paletteuse=dither=bayer:bayer_scale=5:diff_mode=rectangle`, '-y', gifPath ]); // Clean up palette await unlink(palettePath).catch(() => {}); const gifStat = await stat(gifPath); return { gifPath, sizeBytes: gifStat.size, sizeMB: (gifStat.size / 1024 / 1024).toFixed(2) }; } - src/index.js:99-121 (registration)Registration of the 'convert_to_gif' MCP tool.
mcp.tool( 'convert_to_gif', 'Convert a .webm video to an optimized GIF using ffmpeg two-pass palette method.', { webmPath: z.string().describe('Path to the .webm file'), fps: z.number().optional().default(10).describe('GIF frame rate (default 10)'), width: z.number().optional().default(640).describe('GIF width in pixels (default 640, height auto-scaled)'), startTime: z.number().optional().default(0).describe('Skip first N seconds (useful to trim blank loading frames)') }, async ({ webmPath, fps, width, startTime }) => { try { const result = await convertToGif(webmPath, { fps, width, startTime }); return { content: [{ type: 'text', text: `GIF created!\n\nFile: ${result.gifPath}\nSize: ${result.sizeMB} MB` }] }; } catch (err) { return { content: [{ type: 'text', text: `Error: ${err.message}` }], isError: true }; } } );