Skip to main content
Glama
bitscorp-mcp

MCP FFmpeg Video Processor

by bitscorp-mcp

resize-video

Resize videos to standard resolutions like 360p, 480p, 720p, or 1080p for compatibility across devices and platforms.

Instructions

Resize a video to one or more standard resolutions

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
videoPathYesPath to the video file to resize
resolutionsYesResolutions to convert the video to
outputDirNoOptional directory to save the output files (defaults to a temporary directory)

Implementation Reference

  • The core handler function that implements the resize-video tool logic. It resolves paths, checks existence and permissions, requests user permission, runs FFmpeg scale commands for each specified resolution, and returns formatted results or errors.
    async ({ videoPath, resolutions, outputDir }) => {
      try {
        // Resolve the absolute path
        const absVideoPath = path.resolve(videoPath);
    
        // Check if file exists
        try {
          await fs.access(absVideoPath);
        } catch (error) {
          return {
            isError: true,
            content: [{
              type: "text" as const,
              text: `Error: Video file not found at ${absVideoPath}`
            }]
          };
        }
    
        // Determine output directory
        let outputDirectory = outputDir ? path.resolve(outputDir) : await ensureDirectoriesExist();
    
        // Check if output directory exists and is writable
        try {
          await fs.access(outputDirectory, fs.constants.W_OK);
        } catch (error) {
          return {
            isError: true,
            content: [{
              type: "text" as const,
              text: `Error: Output directory ${outputDirectory} does not exist or is not writable`
            }]
          };
        }
    
        // Format command for permission request
        const resolutionsStr = resolutions.join(', ');
        const permissionMessage = `Resize video ${path.basename(absVideoPath)} to ${resolutionsStr}`;
    
        // Ask for permission
        const permitted = await askPermission(permissionMessage);
    
        if (!permitted) {
          return {
            isError: true,
            content: [{
              type: "text" as const,
              text: "Permission denied by user"
            }]
          };
        }
    
        // Get video filename without extension
        const videoFilename = path.basename(absVideoPath, path.extname(absVideoPath));
    
        // Define the type for our results
        type ResizeResult = {
          resolution: "360p" | "480p" | "720p" | "1080p";
          outputPath: string;
          success: boolean;
          error?: string;
        };
    
        // Process each resolution
        const results: ResizeResult[] = [];
    
        for (const resolution of resolutions) {
          const { width, height } = RESOLUTIONS[resolution as keyof typeof RESOLUTIONS];
          const outputFilename = `${videoFilename}_${resolution}${path.extname(absVideoPath)}`;
          const outputPath = path.join(outputDirectory, outputFilename);
    
          // Build FFmpeg command
          const command = `ffmpeg -i "${absVideoPath}" -vf "scale=${width}:${height}" -c:v libx264 -crf 23 -preset medium -c:a aac -b:a 128k "${outputPath}"`;
    
          try {
            // Execute FFmpeg command
            const { stdout, stderr } = await execAsync(command);
    
            results.push({
              resolution,
              outputPath,
              success: true
            });
          } catch (error) {
            const errorMessage = error instanceof Error ? error.message : String(error);
    
            results.push({
              resolution,
              outputPath,
              success: false,
              error: errorMessage
            });
          }
        }
    
        // Format results
        const successCount = results.filter(r => r.success).length;
        const failCount = results.length - successCount;
    
        let resultText = `Processed ${results.length} resolutions (${successCount} successful, ${failCount} failed)\n\n`;
    
        results.forEach(result => {
          if (result.success) {
            resultText += `✅ ${result.resolution}: ${result.outputPath}\n`;
          } else {
            resultText += `❌ ${result.resolution}: Failed - ${result.error}\n`;
          }
        });
    
        return {
          content: [{
            type: "text" as const,
            text: resultText
          }]
        };
      } catch (error) {
        const errorMessage = error instanceof Error ? error.message : String(error);
        return {
          isError: true,
          content: [{
            type: "text" as const,
            text: `Error resizing video: ${errorMessage}`
          }]
        };
      }
    }
  • Zod input schema defining parameters for the resize-video tool: videoPath (required string), resolutions (array of specific enums), outputDir (optional string).
    {
      videoPath: z.string().describe("Path to the video file to resize"),
      resolutions: z.array(z.enum(["360p", "480p", "720p", "1080p"])).describe("Resolutions to convert the video to"),
      outputDir: z.string().optional().describe("Optional directory to save the output files (defaults to a temporary directory)")
    },
  • Registration of the resize-video tool on the MCP server using server.tool(), providing name, description, input schema, and handler function.
    server.tool(
      "resize-video",
      "Resize a video to one or more standard resolutions",
      {
        videoPath: z.string().describe("Path to the video file to resize"),
        resolutions: z.array(z.enum(["360p", "480p", "720p", "1080p"])).describe("Resolutions to convert the video to"),
        outputDir: z.string().optional().describe("Optional directory to save the output files (defaults to a temporary directory)")
      },
      async ({ videoPath, resolutions, outputDir }) => {
        try {
          // Resolve the absolute path
          const absVideoPath = path.resolve(videoPath);
    
          // Check if file exists
          try {
            await fs.access(absVideoPath);
          } catch (error) {
            return {
              isError: true,
              content: [{
                type: "text" as const,
                text: `Error: Video file not found at ${absVideoPath}`
              }]
            };
          }
    
          // Determine output directory
          let outputDirectory = outputDir ? path.resolve(outputDir) : await ensureDirectoriesExist();
    
          // Check if output directory exists and is writable
          try {
            await fs.access(outputDirectory, fs.constants.W_OK);
          } catch (error) {
            return {
              isError: true,
              content: [{
                type: "text" as const,
                text: `Error: Output directory ${outputDirectory} does not exist or is not writable`
              }]
            };
          }
    
          // Format command for permission request
          const resolutionsStr = resolutions.join(', ');
          const permissionMessage = `Resize video ${path.basename(absVideoPath)} to ${resolutionsStr}`;
    
          // Ask for permission
          const permitted = await askPermission(permissionMessage);
    
          if (!permitted) {
            return {
              isError: true,
              content: [{
                type: "text" as const,
                text: "Permission denied by user"
              }]
            };
          }
    
          // Get video filename without extension
          const videoFilename = path.basename(absVideoPath, path.extname(absVideoPath));
    
          // Define the type for our results
          type ResizeResult = {
            resolution: "360p" | "480p" | "720p" | "1080p";
            outputPath: string;
            success: boolean;
            error?: string;
          };
    
          // Process each resolution
          const results: ResizeResult[] = [];
    
          for (const resolution of resolutions) {
            const { width, height } = RESOLUTIONS[resolution as keyof typeof RESOLUTIONS];
            const outputFilename = `${videoFilename}_${resolution}${path.extname(absVideoPath)}`;
            const outputPath = path.join(outputDirectory, outputFilename);
    
            // Build FFmpeg command
            const command = `ffmpeg -i "${absVideoPath}" -vf "scale=${width}:${height}" -c:v libx264 -crf 23 -preset medium -c:a aac -b:a 128k "${outputPath}"`;
    
            try {
              // Execute FFmpeg command
              const { stdout, stderr } = await execAsync(command);
    
              results.push({
                resolution,
                outputPath,
                success: true
              });
            } catch (error) {
              const errorMessage = error instanceof Error ? error.message : String(error);
    
              results.push({
                resolution,
                outputPath,
                success: false,
                error: errorMessage
              });
            }
          }
    
          // Format results
          const successCount = results.filter(r => r.success).length;
          const failCount = results.length - successCount;
    
          let resultText = `Processed ${results.length} resolutions (${successCount} successful, ${failCount} failed)\n\n`;
    
          results.forEach(result => {
            if (result.success) {
              resultText += `✅ ${result.resolution}: ${result.outputPath}\n`;
            } else {
              resultText += `❌ ${result.resolution}: Failed - ${result.error}\n`;
            }
          });
    
          return {
            content: [{
              type: "text" as const,
              text: resultText
            }]
          };
        } catch (error) {
          const errorMessage = error instanceof Error ? error.message : String(error);
          return {
            isError: true,
            content: [{
              type: "text" as const,
              text: `Error resizing video: ${errorMessage}`
            }]
          };
        }
      }
    );
  • Helper constant mapping resolution names to width/height dimensions, used exclusively by the resize-video tool handler.
    const RESOLUTIONS = {
      "360p": { width: 640, height: 360 },
      "480p": { width: 854, height: 480 },
      "720p": { width: 1280, height: 720 },
      "1080p": { width: 1920, height: 1080 }
    };

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/bitscorp-mcp/mcp-ffmpeg'

If you have feedback or need assistance with the MCP directory API, please join our Discord server