extract-audio
Extract audio from video files in MP3, AAC, WAV, or OGG format using the MCP FFmpeg Video Processor. Convert video to audio by specifying input path and desired format.
Instructions
Extract audio from a video file
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| videoPath | Yes | Path to the video file to extract audio from | |
| format | No | Audio format to extract | mp3 |
| outputDir | No | Optional directory to save the output file (defaults to a temporary directory) |
Implementation Reference
- src/mcp-ffmpeg.ts:249-356 (handler)The handler function for the 'extract-audio' tool. It resolves paths, checks file existence and permissions, requests user permission, determines audio codec based on format, executes FFmpeg command to extract audio without video (-vn -acodec), and returns success or error response.async ({ videoPath, format, 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 permissionMessage = `Extract ${format} audio from video ${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" }] }; } // Get video filename without extension const videoFilename = path.basename(absVideoPath, path.extname(absVideoPath)); const outputFilename = `${videoFilename}.${format}`; const outputPath = path.join(outputDirectory, outputFilename); // Determine audio codec based on format let audioCodec; switch (format) { case 'mp3': audioCodec = 'libmp3lame'; break; case 'aac': audioCodec = 'aac'; break; case 'wav': audioCodec = 'pcm_s16le'; break; case 'ogg': audioCodec = 'libvorbis'; break; default: audioCodec = 'libmp3lame'; } // Build FFmpeg command const command = `ffmpeg -i "${absVideoPath}" -vn -acodec ${audioCodec} "${outputPath}"`; try { // Execute FFmpeg command const { stdout, stderr } = await execAsync(command); return { content: [{ type: "text" as const, text: `Successfully extracted audio to: ${outputPath}` }] }; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); return { isError: true, content: [{ type: "text" as const, text: `Error extracting audio: ${errorMessage}` }] }; } } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); return { isError: true, content: [{ type: "text" as const, text: `Error extracting audio: ${errorMessage}` }] }; } }
- src/mcp-ffmpeg.ts:244-248 (schema)Input schema using Zod for the 'extract-audio' tool, defining videoPath (required string), format (enum mp3|aac|wav|ogg, default mp3), outputDir (optional string).{ videoPath: z.string().describe("Path to the video file to extract audio from"), format: z.enum(["mp3", "aac", "wav", "ogg"]).default("mp3").describe("Audio format to extract"), outputDir: z.string().optional().describe("Optional directory to save the output file (defaults to a temporary directory)") },
- src/mcp-ffmpeg.ts:241-357 (registration)Registration of the 'extract-audio' tool on the MCP server using server.tool(), specifying name, description, input schema, and handler function.server.tool( "extract-audio", "Extract audio from a video file", { videoPath: z.string().describe("Path to the video file to extract audio from"), format: z.enum(["mp3", "aac", "wav", "ogg"]).default("mp3").describe("Audio format to extract"), outputDir: z.string().optional().describe("Optional directory to save the output file (defaults to a temporary directory)") }, async ({ videoPath, format, 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 permissionMessage = `Extract ${format} audio from video ${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" }] }; } // Get video filename without extension const videoFilename = path.basename(absVideoPath, path.extname(absVideoPath)); const outputFilename = `${videoFilename}.${format}`; const outputPath = path.join(outputDirectory, outputFilename); // Determine audio codec based on format let audioCodec; switch (format) { case 'mp3': audioCodec = 'libmp3lame'; break; case 'aac': audioCodec = 'aac'; break; case 'wav': audioCodec = 'pcm_s16le'; break; case 'ogg': audioCodec = 'libvorbis'; break; default: audioCodec = 'libmp3lame'; } // Build FFmpeg command const command = `ffmpeg -i "${absVideoPath}" -vn -acodec ${audioCodec} "${outputPath}"`; try { // Execute FFmpeg command const { stdout, stderr } = await execAsync(command); return { content: [{ type: "text" as const, text: `Successfully extracted audio to: ${outputPath}` }] }; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); return { isError: true, content: [{ type: "text" as const, text: `Error extracting audio: ${errorMessage}` }] }; } } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); return { isError: true, content: [{ type: "text" as const, text: `Error extracting audio: ${errorMessage}` }] }; } } );
- src/mcp-ffmpeg.ts:30-56 (helper)Helper function to request user permission via desktop notification before executing FFmpeg operations, used by extract-audio handler.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'); }); }); }
- src/mcp-ffmpeg.ts:61-70 (helper)Helper function to ensure output directory exists in temp folder, used by extract-audio to determine output path.async function ensureDirectoriesExist() { const outputDir = path.join(os.tmpdir(), 'ffmpeg-output'); try { await fs.mkdir(outputDir, { recursive: true }); return outputDir; } catch (error) { console.error('Error creating output directory:', error); return os.tmpdir(); } }