Skip to main content
Glama
bitscorp-mcp

MCP FFmpeg Video Processor

by bitscorp-mcp

get-video-info

Extract detailed technical information from video files, including resolution, duration, format, and codec data for analysis and processing.

Instructions

Get detailed information about a video file

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
videoPathYesPath to the video file to analyze

Implementation Reference

  • The handler function executes the core logic: resolves video path, checks file existence, requests user permission, executes ffprobe to retrieve JSON metadata, parses it, and formats detailed information about format, duration, size, bitrate, and streams (video/audio codecs, resolution, framerate, etc.) into readable text.
      async ({ videoPath }) => {
        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}`
              }]
            };
          }
    
          // Format command for permission request
          const permissionMessage = `Analyze video file ${path.basename(absVideoPath)}`;
    
          // Ask for permission
          const permitted = await askPermission(permissionMessage);
    
          if (!permitted) {
            return {
              isError: true,
              content: [{
                type: "text" as const,
                text: "Permission denied by user"
              }]
            };
          }
    
          // Build FFprobe command to get video information in JSON format
          const command = `ffprobe -v quiet -print_format json -show_format -show_streams "${absVideoPath}"`;
    
          // Execute FFprobe command
          const { stdout, stderr } = await execAsync(command);
    
          // Parse the JSON output
          const videoInfo = JSON.parse(stdout);
    
          // Format the output in a readable way
          let formattedInfo = `Video Information for: ${path.basename(absVideoPath)}\n\n`;
    
          // Format information
          if (videoInfo.format) {
            formattedInfo += `Format: ${videoInfo.format.format_name}\n`;
            formattedInfo += `Duration: ${videoInfo.format.duration} seconds\n`;
            formattedInfo += `Size: ${(parseInt(videoInfo.format.size) / (1024 * 1024)).toFixed(2)} MB\n`;
            formattedInfo += `Bitrate: ${(parseInt(videoInfo.format.bit_rate) / 1000).toFixed(2)} kbps\n\n`;
          }
    
          // Stream information
          if (videoInfo.streams && videoInfo.streams.length > 0) {
            formattedInfo += `Streams:\n`;
    
            videoInfo.streams.forEach((stream: any, index: number) => {
              formattedInfo += `\nStream #${index} (${stream.codec_type}):\n`;
    
              if (stream.codec_type === 'video') {
                formattedInfo += `  Codec: ${stream.codec_name}\n`;
                formattedInfo += `  Resolution: ${stream.width}x${stream.height}\n`;
                formattedInfo += `  Frame rate: ${stream.r_frame_rate}\n`;
                if (stream.bit_rate) {
                  formattedInfo += `  Bitrate: ${(parseInt(stream.bit_rate) / 1000).toFixed(2)} kbps\n`;
                }
              } else if (stream.codec_type === 'audio') {
                formattedInfo += `  Codec: ${stream.codec_name}\n`;
                formattedInfo += `  Sample rate: ${stream.sample_rate} Hz\n`;
                formattedInfo += `  Channels: ${stream.channels}\n`;
                if (stream.bit_rate) {
                  formattedInfo += `  Bitrate: ${(parseInt(stream.bit_rate) / 1000).toFixed(2)} kbps\n`;
                }
              }
            });
          }
    
          return {
            content: [{
              type: "text" as const,
              text: formattedInfo
            }]
          };
        } catch (error) {
          const errorMessage = error instanceof Error ? error.message : String(error);
          return {
            isError: true,
            content: [{
              type: "text" as const,
              text: `Error getting video information: ${errorMessage}`
            }]
          };
        }
      }
    );
  • Zod schema defining the input parameter: videoPath (string) - path to the video file.
    {
      videoPath: z.string().describe("Path to the video file to analyze")
    },
  • Registration of the 'get-video-info' tool on the MCP server with name, description, schema, and handler.
    server.tool(
      "get-video-info",
      "Get detailed information about a video file",
  • Helper function used by the tool to request user permission via desktop notification before analyzing the video.
    async function askPermission(action: string): Promise<boolean> {
      // Skip notification if DISABLE_NOTIFICATIONS is set
      if (process.env.DISABLE_NOTIFICATIONS === 'true') {
        console.log(`Auto-allowing action (notifications disabled): ${action}`);
        return true;
      }
    
      return new Promise((resolve) => {
        notifier.notify({
          title: 'FFmpeg Processor Permission Request',
          message: `${action}`,
          wait: true,
          timeout: 60,
          actions: 'Allow',
          closeLabel: 'Deny'
        }, (err, response, metadata) => {
          if (err) {
            console.error('Error showing notification:', err);
            resolve(false);
            return;
          }
    
          const buttonPressed = metadata?.activationValue || response;
          resolve(buttonPressed !== 'Deny');
        });
      });
    }

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