Skip to main content
Glama

convert_video

Convert video files between formats like MP4, AVI, MOV, WMV, MKV, WEBM, and M4V. Adjust quality, resolution, bitrate, and frame rate for optimized playback across devices.

Instructions

将视频文件转换为指定格式。支持MP4、AVI、MOV、WMV、FLV、MKV、WEBM、M4V等主流格式之间的相互转换。

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
inputPathYes输入视频文件的完整路径
outputFormatYes目标输出格式
outputPathNo输出文件路径(可选,如果不指定则自动生成)
qualityNo视频质量预设(可选)
resolutionNo输出分辨率,格式为"宽度x高度",如"1920x1080"(可选)
videoBitrateNo视频码率,单位kbps(可选)
audioBitrateNo音频码率,单位kbps(可选)
frameRateNo输出帧率,单位fps(可选)
overwriteNo是否覆盖已存在的输出文件(默认false)

Implementation Reference

  • The primary handler function for the 'convert_video' MCP tool. It validates inputs, builds conversion options, calls FFmpegService.convertVideo, and returns detailed results including input/output info.
    export async function handleConvertVideo(args: ConvertVideoArgs): Promise<any> {
      const ffmpegService = FFmpegService.getInstance();
      const validator = ValidatorService.getInstance();
    
      try {
        // 验证输入文件
        const inputValidation = await validator.validateVideoFile(args.inputPath);
        if (!inputValidation.isValid) {
          return {
            success: false,
            error: `输入文件验证失败: ${inputValidation.error}`
          };
        }
    
        // 验证输出格式
        const formatValidation = validator.validateOutputFormat(args.outputFormat);
        if (!formatValidation.isValid) {
          return {
            success: false,
            error: formatValidation.error
          };
        }
    
        // 生成输出路径(如果未指定)
        let outputPath = args.outputPath;
        if (!outputPath) {
          const inputDir = path.dirname(args.inputPath);
          const inputName = path.parse(args.inputPath).name;
          outputPath = path.join(inputDir, `${inputName}_converted.${args.outputFormat}`);
        }
    
        // 验证输出路径
        const outputValidation = await validator.validateOutputPath(outputPath, args.overwrite || false);
        if (!outputValidation.isValid) {
          return {
            success: false,
            error: outputValidation.error
          };
        }
    
        // 构建转换选项
        const conversionOptions: any = {
          outputFormat: args.outputFormat as VideoFormat,
          overwrite: args.overwrite || false
        };
    
        // 添加可选参数
        if (args.quality) {
          conversionOptions.quality = args.quality;
        }
    
        if (args.resolution) {
          const resolutionValidation = validator.validateResolution(args.resolution);
          if (!resolutionValidation.isValid) {
            return {
              success: false,
              error: resolutionValidation.error
            };
          }
          conversionOptions.resolution = {
            width: resolutionValidation.width!,
            height: resolutionValidation.height!
          };
        }
    
        if (args.videoBitrate) {
          const bitrateValidation = validator.validateBitrate(args.videoBitrate, 'video');
          if (!bitrateValidation.isValid) {
            return {
              success: false,
              error: bitrateValidation.error
            };
          }
          conversionOptions.videoBitrate = args.videoBitrate;
        }
    
        if (args.audioBitrate) {
          const bitrateValidation = validator.validateBitrate(args.audioBitrate, 'audio');
          if (!bitrateValidation.isValid) {
            return {
              success: false,
              error: bitrateValidation.error
            };
          }
          conversionOptions.audioBitrate = args.audioBitrate;
        }
    
        if (args.frameRate) {
          const frameRateValidation = validator.validateFrameRate(args.frameRate);
          if (!frameRateValidation.isValid) {
            return {
              success: false,
              error: frameRateValidation.error
            };
          }
          conversionOptions.frameRate = args.frameRate;
        }
    
        // 获取输入文件信息
        const inputInfo = await ffmpegService.getVideoInfo(args.inputPath);
    
        // 执行转换
        console.log(`开始转换视频: ${args.inputPath} -> ${outputPath}`);
        
        const result = await ffmpegService.convertVideo(
          args.inputPath,
          outputPath,
          conversionOptions,
          (progress) => {
            console.log(`转换进度: ${progress.progress}% (${progress.status})`);
          }
        );
    
        // 获取输出文件信息
        const outputInfo = await ffmpegService.getVideoInfo(result);
    
        return {
          success: true,
          message: '视频转换完成',
          data: {
            inputPath: args.inputPath,
            outputPath: result,
            inputInfo: {
              format: inputInfo.format,
              size: `${(inputInfo.size / (1024 * 1024)).toFixed(2)} MB`,
              duration: `${Math.round(inputInfo.duration)} 秒`,
              resolution: inputInfo.video ? `${inputInfo.video.width}x${inputInfo.video.height}` : '未知',
              videoCodec: inputInfo.video?.codec || '未知',
              audioCodec: inputInfo.audio?.codec || '未知'
            },
            outputInfo: {
              format: outputInfo.format,
              size: `${(outputInfo.size / (1024 * 1024)).toFixed(2)} MB`,
              duration: `${Math.round(outputInfo.duration)} 秒`,
              resolution: outputInfo.video ? `${outputInfo.video.width}x${outputInfo.video.height}` : '未知',
              videoCodec: outputInfo.video?.codec || '未知',
              audioCodec: outputInfo.audio?.codec || '未知'
            },
            conversionOptions
          }
        };
    
      } catch (error: any) {
        console.error('视频转换失败:', error);
        return {
          success: false,
          error: `转换失败: ${error.message}`
        };
      }
    }
  • Tool specification for 'convert_video' including name, description, and detailed inputSchema for validation.
    export const convertVideoTool: Tool = {
      name: 'convert_video',
      description: '将视频文件转换为指定格式。支持MP4、AVI、MOV、WMV、FLV、MKV、WEBM、M4V等主流格式之间的相互转换。',
      inputSchema: {
        type: 'object',
        properties: {
          inputPath: {
            type: 'string',
            description: '输入视频文件的完整路径'
          },
          outputFormat: {
            type: 'string',
            enum: ['mp4', 'avi', 'mov', 'wmv', 'mkv', 'webm', 'm4v'],
            description: '目标输出格式'
          },
          outputPath: {
            type: 'string',
            description: '输出文件路径(可选,如果不指定则自动生成)'
          },
          quality: {
            type: 'string',
            enum: ['low', 'medium', 'high', 'ultra'],
            description: '视频质量预设(可选)'
          },
          resolution: {
            type: 'string',
            description: '输出分辨率,格式为"宽度x高度",如"1920x1080"(可选)'
          },
          videoBitrate: {
            type: 'number',
            description: '视频码率,单位kbps(可选)'
          },
          audioBitrate: {
            type: 'number',
            description: '音频码率,单位kbps(可选)'
          },
          frameRate: {
            type: 'number',
            description: '输出帧率,单位fps(可选)'
          },
          overwrite: {
            type: 'boolean',
            description: '是否覆盖已存在的输出文件(默认false)'
          }
        },
        required: ['inputPath', 'outputFormat']
      }
    };
  • Maps the 'convert_video' tool name to its handler function handleConvertVideo, used by the MCP server.
    export const toolHandlers = {
      convert_video: handleConvertVideo,
      get_video_info: handleGetVideoInfo,
      batch_convert: handleBatchConvert
    };
  • src/index.ts:64-117 (registration)
    MCP server request handler for tool calls, which dispatches to toolHandlers[name] including 'convert_video'.
    // 处理工具调用请求
    this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
      const { name, arguments: args } = request.params;
    
      try {
        // 检查工具是否存在
        if (!(name in toolHandlers)) {
          throw new McpError(
            ErrorCode.MethodNotFound,
            `未知的工具: ${name}`
          );
        }
    
        // 验证参数
        if (!args || typeof args !== 'object') {
          throw new McpError(
            ErrorCode.InvalidParams,
            '工具参数必须是一个对象'
          );
        }
    
        console.log(`正在执行工具: ${name}`);
        console.log('参数:', JSON.stringify(args, null, 2));
    
        // 调用对应的工具处理器
        const handler = toolHandlers[name as keyof typeof toolHandlers];
        const result = await handler(args as any);
    
        console.log(`工具 ${name} 执行完成`);
    
        return {
          content: [
            {
              type: 'text',
              text: JSON.stringify(result, null, 2)
            }
          ]
        };
    
      } catch (error: any) {
        console.error(`工具 ${name} 执行失败:`, error);
    
        // 如果是MCP错误,直接抛出
        if (error instanceof McpError) {
          throw error;
        }
    
        // 包装其他错误
        throw new McpError(
          ErrorCode.InternalError,
          `工具执行失败: ${error.message}`
        );
      }
    });
  • Core FFmpeg service method that performs the actual video format conversion, called by the tool handler.
    async convertVideo(
      inputPath: string,
      outputPath: string,
      options: ConversionOptions,
      onProgress?: (progress: ConversionProgress) => void
    ): Promise<string> {
      const taskId = this.generateTaskId();
      
      // 检查输入文件是否存在
      try {
        await fs.access(inputPath);
      } catch {
        throw new Error(`输入文件不存在: ${inputPath}`);
      }
    
      // 确保输出目录存在
      const outputDir = path.dirname(outputPath);
      await fs.mkdir(outputDir, { recursive: true });
    
      // 检查输出文件是否已存在
      if (!options.overwrite) {
        try {
          await fs.access(outputPath);
          throw new Error(`输出文件已存在: ${outputPath}`);
        } catch (err: any) {
          if (err.code !== 'ENOENT') {
            throw err;
          }
        }
      }
    
      return new Promise((resolve, reject) => {
        const progress: ConversionProgress = {
          taskId,
          inputPath,
          outputPath,
          progress: 0,
          status: 'pending',
          startTime: new Date(),
        };
    
        this.activeConversions.set(taskId, progress);
    
        let command = ffmpeg(inputPath);
    
        // 应用转换选项
        command = this.applyConversionOptions(command, options);
    
        command
          .output(outputPath)
          .on('start', (commandLine) => {
            console.log('开始转换:', commandLine);
            progress.status = 'processing';
            onProgress?.(progress);
          })
          .on('progress', (progressInfo) => {
            progress.progress = Math.round(progressInfo.percent || 0);
            onProgress?.(progress);
          })
          .on('end', async () => {
            try {
              // 验证输出文件是否完整
              await this.validateOutputFile(outputPath);
              
              progress.status = 'completed';
              progress.progress = 100;
              progress.endTime = new Date();
              this.activeConversions.delete(taskId);
              onProgress?.(progress);
              resolve(outputPath);
            } catch (validationError: any) {
              progress.status = 'failed';
              progress.error = `输出文件验证失败: ${validationError.message}`;
              progress.endTime = new Date();
              this.activeConversions.delete(taskId);
              onProgress?.(progress);
              reject(new Error(`转换完成但文件验证失败: ${validationError.message}`));
            }
          })
          .on('error', (err) => {
            progress.status = 'failed';
            progress.error = err.message;
            progress.endTime = new Date();
            this.activeConversions.delete(taskId);
            onProgress?.(progress);
            
            // 提供更详细的错误信息
            let errorMessage = `视频转换失败: ${err.message}`;
            
            // 针对常见错误提供解决建议
            if (err.message.includes('moov atom not found')) {
              errorMessage += '\n建议: 输入文件可能损坏或格式不完整,请检查源文件';
            } else if (err.message.includes('Invalid data found')) {
              errorMessage += '\n建议: 输入文件格式可能不受支持或文件已损坏';
            } else if (err.message.includes('No such file or directory')) {
              errorMessage += '\n建议: 请检查输入文件路径是否正确';
            } else if (err.message.includes('Permission denied')) {
              errorMessage += '\n建议: 请检查文件权限或确保输出目录可写';
            } else if (err.message.includes('codec not found')) {
              errorMessage += '\n建议: 缺少必要的编解码器,请检查FFmpeg安装';
            }
            
            reject(new Error(errorMessage));
          })
          .run();
      });
    }
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries full burden for behavioral disclosure. It states the conversion function but lacks critical behavioral details: whether it's a read/write operation, if it modifies source files, what happens on failure, performance characteristics, or output location behavior. The description doesn't compensate for the missing annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is extremely concise - a single sentence that efficiently states the core function and lists supported formats. Every word earns its place with no redundancy or unnecessary elaboration. It's appropriately sized for a conversion tool.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a complex video conversion tool with 9 parameters, no annotations, and no output schema, the description is insufficient. It doesn't address behavioral aspects, error conditions, performance implications, or provide usage context. The agent would struggle to understand when and how to use this tool effectively beyond basic parameter passing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents all 9 parameters thoroughly. The description adds minimal value beyond the schema by listing format examples, but doesn't provide additional semantic context about parameter interactions, defaults, or constraints. Baseline 3 is appropriate when schema does the heavy lifting.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose: '将视频文件转换为指定格式' (convert video files to specified format). It specifies the action (convert) and resource (video files), and lists supported formats. However, it doesn't explicitly differentiate from sibling tools like batch_convert or get_video_info, which prevents a perfect score.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides no guidance on when to use this tool versus alternatives like batch_convert (for multiple files) or get_video_info (for metadata extraction). It mentions supported formats but doesn't specify any context, prerequisites, or exclusions for usage.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

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/pickstar-2002/video-convert-mcp'

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