Skip to main content
Glama
easyhak

YouTube Search & Download MCP Server

by easyhak

download_audio

Extract and save audio from YouTube videos by specifying video ID, quality preset, and output format. Supports MP3, M4A, Opus, and WAV formats with configurable download directory.

Instructions

Download audio only from a YouTube video.

Args: video_id: YouTube video ID (11 characters) quality: Audio quality preset - "best", "high" (320kbps), "medium" (192kbps), "low" (128kbps) output_dir: Download directory path (uses config default if not specified) format: Output format - "mp3", "m4a", "opus", "wav" (default: "mp3")

Returns: JSON with download status, file path, file size, and metadata

Example: download_audio("dQw4w9WgXcQ", quality="high", format="mp3")

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
video_idYes
qualityNobest
output_dirNo
formatNomp3

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
resultYes

Implementation Reference

  • The 'download_audio' tool handler in the tools module. It validates parameters, prepares a DownloadParams object, invokes the downloader service, and formats the result as JSON.
    async def download_audio(
        video_id: str,
        quality: str = "best",
        output_dir: str | None = None,
        format: str = "mp3",
    ) -> str:
        """
        Download audio only from a YouTube video.
    
        Args:
            video_id: YouTube video ID (11 characters)
            quality: Audio quality preset - "best", "high" (320kbps), "medium" (192kbps), "low" (128kbps)
            output_dir: Download directory path (uses config default if not specified)
            format: Output format - "mp3", "m4a", "opus", "wav" (default: "mp3")
    
        Returns:
            JSON with download status, file path, file size, and metadata
    
        Example:
            download_audio("dQw4w9WgXcQ", quality="high", format="mp3")
        """
        try:
            logger.info(
                f"Download audio request: video_id='{video_id}', quality='{quality}', format='{format}'"
            )
    
            # Validate video ID
            if not validate_video_id(video_id):
                raise InvalidQueryError(f"Invalid video ID format: {video_id}")
    
            # Create download parameters
            params = DownloadParams(
                video_id=video_id,
                quality=quality,
                output_dir=output_dir,
                format=format,
                download_type="audio",
            )
    
            # Execute download
            downloader = get_downloader()
            result = await downloader.download_audio(params)
    
            logger.info(f"Audio download completed: {result.file_path}")
            return json.dumps(result.model_dump(), indent=2)
    
        except FFmpegNotFoundError as e:
            logger.error(f"FFmpeg not found: {e.message}")
            return json.dumps(
                {
                    "success": False,
                    "error": "ffmpeg_not_found",
                    "message": e.message,
                }
            )
        except InvalidQueryError as e:
            logger.warning(f"Invalid parameters: {e.message}")
            return json.dumps(
                {"success": False, "error": "invalid_parameters", "message": e.message}
            )
        except VideoNotFoundError as e:
            logger.warning(f"Video not found: {e.message}")
            return json.dumps(
                {
                    "success": False,
                    "error": "video_not_found",
                    "message": "Video not found or unavailable.",
                }
            )
        except DiskSpaceError as e:
            logger.error(f"Disk space error: {e.message}")
            return json.dumps({"success": False, "error": "disk_space", "message": e.message})
        except MCPPermissionError as e:
            logger.error(f"Permission error: {e.message}")
            return json.dumps(
                {"success": False, "error": "permission_denied", "message": e.message}
            )
        except NetworkError as e:
            logger.error(f"Network error: {e.message}")
            return json.dumps(
                {
                    "success": False,
                    "error": "network_error",
                    "message": "Download failed due to network error.",
                }
            )
        except DownloadError as e:
            logger.error(f"Download error: {e.message}")
            return json.dumps({"success": False, "error": "download_failed", "message": e.message})
        except Exception:
            logger.exception("Unexpected error in download_audio")
            return json.dumps(
                {
                    "success": False,
                    "error": "internal_error",
                    "message": "An unexpected error occurred.",
                }
            )
  • The actual implementation of the audio download logic using yt-dlp within the YtDlpDownloader class. It calls the internal _download method to handle the process.
    async def download_audio(self, params: DownloadParams) -> DownloadResult:
        """
        Download audio only from a video.
    
        Args:
            params: Download parameters
    
        Returns:
            Download result with file path and metadata
    
        Raises:
            VideoNotFoundError: If video doesn't exist
            DownloadError: If download operation fails
            DiskSpaceError: If insufficient disk space
            PermissionError: If cannot write to output directory
        """
        logger.info(
            f"Starting audio download: {params.video_id} "
            f"(quality={params.quality}, format={params.format})"
        )
        return await self._download(params, is_video=False)
Behavior3/5

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

With no annotations provided, the description carries the full burden of behavioral disclosure. It mentions the return format ('JSON with download status...') and default behaviors (output_dir uses config default, format defaults to mp3), but doesn't cover important aspects like error handling, rate limits, file overwriting behavior, or whether this requires internet access or specific permissions.

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 efficiently structured with a clear purpose statement followed by well-organized sections (Args, Returns, Example). Every sentence serves a purpose - no redundant information. The example demonstrates typical usage without unnecessary elaboration.

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

Completeness4/5

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

Given the tool's moderate complexity (4 parameters, 1 required), no annotations, but with an output schema, the description does well by thoroughly documenting parameters and return format. However, it lacks some behavioral context like error conditions or performance characteristics that would be helpful for a download operation. The existence of an output schema reduces but doesn't eliminate the need for some behavioral disclosure.

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

Parameters5/5

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

With 0% schema description coverage, the description fully compensates by providing comprehensive parameter documentation. Each parameter is clearly explained with semantics, constraints (e.g., '11 characters' for video_id), quality presets with bitrates, format options with defaults, and the config default behavior for output_dir. This adds significant value beyond the bare schema.

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

Purpose5/5

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

The description clearly states the specific action ('Download audio only') and resource ('from a YouTube video'), distinguishing it from sibling tools like 'download_video' which presumably downloads video content. The opening sentence is direct and unambiguous about the tool's function.

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

Usage Guidelines4/5

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

The description implies usage context by specifying 'audio only' and listing quality/format options, which helps differentiate from 'download_video'. However, it doesn't explicitly state when to use this tool versus alternatives or mention any prerequisites like authentication requirements, which would be needed for a perfect score.

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/easyhak/youtube-search-mcp'

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