Rust MCP server and CLI for yt-dlp media search/downloads, metadata tagging, transfer queues, Plex playlists, SSH/rclone targets, and MCP app search UI.
claude mcp add rytdl -- npx -y @dinglebear/rytdl{
"mcpServers": {
"rytdl": {
"command": "npx",
"args": ["-y", "@dinglebear/rytdl"]
}
}
}MCP Servers overview
# ytdl-rmcp [](https://www.npmjs.com/package/ytdl-rmcp) [](https://github.com/dinglebear-ai/rytdl/actions/workflows/release.yml) [](https://github.com/dinglebear-ai/rytdl/actions/workflows/ci.yml) yt-dlp search, download, metadata, delivery, and Plex workflows over MCP and CLI. Written in Rust on the [`rmcp`](https://crates.io/crates/rmcp) crate. **yt-dlp and ffmpeg are auto-downloaded** into a per-user cache on first run, so the host needs neither pre-installed — the one binary is the whole install. **30-second path:** `npx -y @dinglebear/rytdl setup` -> configure a target path -> call `youtube_search` or `youtube_probe`; use `youtube_download` only after the destination and trust boundary are clear. **Status:** production personal-media MCP server. Read-only search/probe/stats paths are safe; download, playlist, queue-drain, and tag-writing paths create or move state and are intended for trusted callers. **Not for:** a generic web-downloader SaaS, a multi-tenant media ingestion boundary, a replacement for yt-dlp's upstream site handling, or an arbitrary filesystem writer for untrusted MCP callers. ## Contents - [Naming](#naming) - [Capabilities And Boundaries](#capabilities-and-boundaries) - [Install](#install) - [Quickstart](#quickstart) - [Client Configuration](#client-configuration) - [Runtime Surfaces](#runtime-surfaces) - [MCP Tool Reference](#mcp-tool-reference) - [CLI Reference](#cli-reference) - [Configuration](#configuration) - [Authentication](#authentication) - [Safety And Trust Model](#safety-and-trust-model) - [Architecture](#architecture) - [Distribution Contract](#distribution-contract) - [Development](#development) - [Verification](#verification) - [Deployment](#deployment) - [Troubleshooting](#troubleshooting) - [Related Servers](#related-servers) - [Documentation](#documentation) - [License](#license) ## Naming | Surface | This repo | | --- | --- | | Repository | [`dinglebear-ai/rytdl`](https://github.com/dinglebear-ai/rytdl) | | Cargo crate | `ytdl-rmcp` | | npm package | `@dinglebear/rytdl` | | CLI / binary | `rytdl` | | MCP tools | `youtube_search`, `youtube_search_ui`, `youtube_download`, `youtube_probe`, `youtube_identify`, `youtube_stats`, `youtube_plex_playlist`, `youtube_transfer_queue` | | Env prefix | `YTDLP_*`, plus `FFMPEG_*`, `FPCALC_PATH`, and `YTDLP_LOG` | | Transport | stdio only — no HTTP listener, no service port | The crate and npm package use the `*-rmcp` family naming pattern, while the repository and runtime binary are `rytdl` so local shells get a short Rust-native command. ## Capabilities And Boundaries - Searches YouTube through yt-dlp without downloading media. - Downloads audio, video, or both into a staging tree, tags audio metadata, and transfers the result to local, SSH, or rclone destinations. - Optionally fingerprints audio through AcoustID/MusicBrainz and syncs completed audio downloads into a Plex playlist. - Builds Plex playlists from successful transfer history and drains server-made retained-staging transfer manifests. - Exposes an MCP App search UI for hosts that can render embedded widgets. - Keeps a JSONL ledger for repeat-safe downloads and stats. | This repo owns | Upstream owns | Explicitly out of scope | | --- | --- | --- | | MCP tools, CLI setup, media staging, tagging, transfer policy, queue manifests, config validation, response shaping, plugin/package metadata. | yt-dlp extraction behavior, source-site availability, ffmpeg media conversion, Plex library indexing, SSH/rclone authentication. | Multi-tenant isolation, arbitrary local writes for untrusted callers, credential brokering, site-specific scraping guarantees, media-server replacement. | --- ## Features - **Audio, video, or both** — audio-first by default, with separate targets for audio and video. - **Proper tagging** — embeds title / artist / album / date and cover art, and organizes output as `Artist/Title [id].ext` so media servers (Plex, etc.) index it cleanly. A non-greedy `Artist - Title` parse recovers the artist from free-form video titles. Source `.info.json`, thumbnail, and description sidecars are preserved next to the media for future retagging/indexing. Common YouTube title noise like `(Official Video)`, `[Official Audio]`, and trailing channel handles is stripped from embedded title metadata by default. - **Self-contained paths** — the binary downloads/caches yt-dlp + ffmpeg when run directly; the container image bakes in ffmpeg, fpcalc, SSH, and rsync for media-host batch jobs. - **Self-installing** — `ytdl-rmcp setup` registers the server into Claude Code, Codex, and/or Gemini CLI via each tool's own `mcp add`. - **Robust transfers** — local paths (`/path`) are copied in-process by the binary itself, SSH targets (`host:/path`) use `rsync -a --partial --protect-args` with an `scp` fallback when `rsync` is missing, and rclone targets (`remote:path` or `rclone:remote:/path`) use `rclone copy`. On transfer failure the local staging copy is kept for retry and recorded as a drainable manifest for `youtube_transfer_queue`. - **Repeat-safe** — `use_archive` records downloaded IDs (per mode) and skips them on later runs; YouTube mix/radio URLs are auto-cleaned to the seed video. - **Stats-ready ledger** — every completed download call appends a JSONL entry with timestamp, destinations, files, bytes, uploader, and transfer status. - **Plex playlist sync** — when Plex credentials are configured, downloaded audio is added to `yt-dlp Downloads` by default. ## MCP Tool Reference | Tool | Purpose | | --- | --- | | `youtube_search` | Search YouTube with yt-dlp and return result URLs without downloading. | | `youtube_search_ui` | Open an interactive YouTube search UI in MCP App-capable hosts. | | `youtube_download` | Download one or more URLs (audio/video/both) and transfer them to a target path. | | `youtube_probe` | Read-only: resolve title/duration/uploader/format counts without downloading. | | `youtube_identify` | Fingerprint local audio with `fpcalc`, return AcoustID/MusicBrainz candidates, preview canonical tags, and optionally write high-confidence tags. | | `youtube_stats` | Summarize the download ledger: totals, file kinds, uploaders, and recent entries. | | `youtube_plex_playlist` | Build or preview Plex audio playlists from successful transferred audio history. | | `youtube_transfer_queue` | List and drain retained-staging transfer failure manifests. | ### `youtube_download` parameters | Param | Default | Meaning | | --- | --- | --- | | `urls` | — (required) | One URL string or an array of URLs. | | `mode` | `audio` | `audio`, `video`, or `both`. | | `audio_format` | env `YTDLP_AUDIO_FORMAT` → `mp3` | `mp3`/`m4a`/`opus`/`flac`/`wav`/`best`. | | `audio_quality` | `0` | yt-dlp quality for lossy codecs: `0`–`9` or a bitrate like `192K`. | | `max_height` | best | Cap video resolution (e.g. `1080`). | | `container` | `mp4` | `mp4` or `mkv` for video. | | `target_path` | env `YTDLP_TARGET_PATH` | Destination for audio. Use `/path` for local, `host:/path` for SSH, or `remote:path` or `rclone:remote:/path` for rclone. | | `video_target_path` | env `YTDLP_VIDEO_TARGET_PATH` → `target_path` | Destination for video when it should land somewhere different from audio. Same target forms. | | `keep_local` | `false` | Keep the local staging copy after transfer. | | `use_archive` | `false` | Record + skip already-downloaded IDs (per mode). | | `plex_playlist` | env `YTDLP_PLEX_PLAYLIST` → `yt-dlp Downloads` when Plex is configured | Plex playlist title or ID to add downloaded audio tracks to. Requires `YTDLP_PLEX_URL` and `YTDLP_PLEX_TOKEN`. | | `response_format` | `markdown` | `markdown` or `json`. | When Plex credentials are configured, successful downloads that produced audio files search Plex for each downloaded track, create the target playlist if needed, and add missing tracks while skipping entries already present. The default playlist is `yt-dlp Downloads`; set `YTDLP_PLEX_PLAYLIST` or pass `plex_playlist` to override it. Plex errors are reported as `plex_playlist_error` and do not make the completed download fail. JSON responses include a `plex_playlist` summary with `matched`, `added`, `already_present`, and `missing` counts. Canonical metadata matching through MusicBrainz/AcoustID is documented in `docs/musicbrainz-acoustid.md`. `youtube_download` automatically runs high-confidence MusicBrainz retagging for downloaded audio when `YTDLP_ACOUSTID_CLIENT_KEY` is configured; `youtube_identify` remains available for previewing or repairing existing library files, with manual tag writes enabled by `write_tags=true`. #### `youtube_download` JSON response With `response_format=json`, the call returns a single object describing the batch: | Field | Meaning | | --- | --- | | `transferred` | `true` if every produced subtree reached its target. | | `transfer_error` | `null` on success, else the failure/timeout message (string). | | `target_path` / `destination` / `destinations` | The per-kind target destination(s) actually used. | | `staging_kept_at` | Local staging path retained for retry (set when the transfer failed or `keep_local` was requested). | | `total_files` / `total_bytes` / `total_size` | Aggregate counts across all items. | | `partial_items` | Count of items that errored **but** still produced files. | | `failed_items` | Count of items that errored **and** produced no files. | | `items[]` | Per-URL results, each with a `status`, `title`, `video_id`, `error`, and a `files[]` list. | Each `items[].status` is one of: - `ok` — succeeded with files. - `partial` — an error occurred but some files were still produced. - `failed` — errored with no files. - `skipped` — nothing new (already in the
What people ask about rytdl
What is dinglebear-ai/rytdl?
+
dinglebear-ai/rytdl is mcp servers for the Claude AI ecosystem. Rust MCP server and CLI for yt-dlp media search/downloads, metadata tagging, transfer queues, Plex playlists, SSH/rclone targets, and MCP app search UI. It has 1 GitHub stars and was last updated today.
How do I install rytdl?
+
You can install rytdl by cloning the repository (https://github.com/dinglebear-ai/rytdl) or following the README instructions on GitHub. ClaudeWave also provides quick install blocks on this page.
Is dinglebear-ai/rytdl safe to use?
+
dinglebear-ai/rytdl has not been audited yet by our security agent. Review the original repository on GitHub before using it in production.
Who maintains dinglebear-ai/rytdl?
+
dinglebear-ai/rytdl is maintained by dinglebear-ai. The last recorded GitHub activity is from today, with 2 open issues.
Are there alternatives to rytdl?
+
Yes. On ClaudeWave you can browse similar mcp servers at /categories/mcp, sorted by popularity or recent activity.
Deploy rytdl to your cloud
Ship this repo to production in minutes. Each platform spins up its own environment with editable env vars.
Maintain this repo? Add a badge to your README
Drop the badge into your GitHub README to show it's tracked on ClaudeWave. Each badge links back to this page and reflects the live Trust Score.
[](https://claudewave.com/repo/dinglebear-ai-rytdl)<a href="https://claudewave.com/repo/dinglebear-ai-rytdl"><img src="https://claudewave.com/api/badge/dinglebear-ai-rytdl" alt="Featured on ClaudeWave: dinglebear-ai/rytdl" width="320" height="64" /></a>More MCP Servers
Fair-code workflow automation platform with native AI capabilities. Combine visual building with custom code, self-host or cloud, 400+ integrations.
User-friendly AI Interface (Supports Ollama, OpenAI API, ...)
An open-source AI agent that brings the power of Gemini directly into your terminal.
The fastest path to AI-powered full stack observability, even for lean teams.
Real-time global intelligence dashboard. AI-powered news aggregation, geopolitical monitoring, and infrastructure tracking in a unified situational awareness interface
🕷️ An adaptive Web Scraping framework that handles everything from a single request to a full-scale crawl!