内容
# ytdl-rmcp
[](https://www.npmjs.com/package/ytdl-rmcp)
[](https://github.com/jmagar/ytdl-rmcp/actions/workflows/release.yml)
[](https://github.com/jmagar/ytdl-rmcp/actions/workflows/ci.yml)
一个跨平台、单二进制文件的 **MCP 服务器**,可从任何
[yt-dlp](https://github.com/yt-dlp/yt-dlp)-支持的站点(YouTube、Vimeo等)下载媒体,
嵌入元数据和封面艺术,按艺术家组织文件,并将结果传输到SSH远程服务器的目录中 —
通过 `rsync`(如果主机不支持,则使用 `scp`作为备用方案,例如Windows)。
用Rust编写,使用 [`rmcp`](https://crates.io/crates/rmcp) crate。
**yt-dlp 和 ffmpeg 会自动下载**到每个用户的缓存中,因此主机不需要预安装 —
一个二进制文件就是整个安装包。
---
## 功能
- **音频、视频或两者** — 默认优先音频,音频和视频有单独的远程目的地。
- **正确的标签** — 嵌入标题/艺术家/专辑/日期和封面艺术,并按`Artist/Title [id].ext`组织输出,以便媒体服务器(例如Plex)能正确索引。非贪婪的`Artist - Title`解析从自由格式的视频标题中恢复艺术家。源`.info.json`、缩略图和描述侧边栏与媒体一起保留,以便将来重新标记/索引。 默认情况下,从嵌入的标题元数据中删除常见的YouTube标题噪音,如`(Official Video)`、 `[Official Audio]`和尾随的频道句柄。
- **自包含路径** — 二进制文件在运行时直接下载/缓存yt-dlp + ffmpeg;容器镜像包含ffmpeg、fpcalc、SSH和rsync,用于媒体主机批量作业。
- **自我安装** — `ytdl-rmcp setup`将服务器注册到Claude Code、Codex和/或Gemini CLI中,每个工具都有自己的`mcp add`。
- **强大的传输** — 如果存在`rsync --protect-args`,否则使用`scp`;非交互式SSH(`BatchMode=yes`,`StrictHostKeyChecking=accept-new`),以便TTY-less服务器不会在提示符上挂起。传输失败时,保留本地暂存副本以重试。
- **重复安全** — `use_archive`记录下载的ID(按模式),并在后续运行中跳过它们;YouTube混合/广播URL会自动清理为种子视频。
- **统计账本** — 每个完成的下载调用追加一个JSONL条目,包含时间戳、目的地、文件、字节、上载者和传输状态。
- **Plex播放列表同步** — 配置Plex凭证后,下载的音频默认添加到`yt-dlp Downloads`。
## 工具
| 工具 | 用途 |
| --- | --- |
| `youtube_search` | 使用yt-dlp搜索YouTube并返回结果URL而不下载。 |
| `youtube_search_ui` | 在支持MCP应用的主机上打开交互式YouTube搜索UI。 |
| `youtube_download` | 下载一个或多个URL(音频/视频/两者)并将它们rsync/scp到远程目录。 |
| `youtube_probe` | 只读:解析标题/时长/上传者/格式计数而不下载。 |
| `youtube_identify` | 使用`fpcalc`指纹识别本地音频,返回AcoustID/MusicBrainz候选项,预览规范标签,并可选地写入高置信度标签。 |
| `youtube_stats` | 总结下载账本:总数、文件类型、上传者、最近的条目。 |
### `youtube_download` 参数
| 参数 | 默认值 | 含义 |
| --- | --- | --- |
| `urls` | — (必填) | 一个URL字符串或URL数组。 |
| `mode` | `audio` | `audio`、`video`或`both`。 |
| `audio_format` | 环境变量`YTDLP_AUDIO_FORMAT` → `mp3` | `mp3`/`m4a`/`opus`/`flac`/`wav`/`best`。 |
| `audio_quality` | `0` | yt-dlp用于有损编码的质量:`0`–`9`或比特率,如`192K`。 |
| `max_height` | 最佳 | 视频分辨率上限(例如`1080`)。 |
| `container` | `mp4` | 视频容器`mp4`或`mkv`。 |
| `remote` | 环境变量`YTDLP_REMOTE` | SSH别名或`user@host`。 |
| `dest_path` | 环境变量`YTDLP_REMOTE_PATH` | 音频的绝对远程目录。 |
| `video_dest_path` | 环境变量`YTDLP_VIDEO_REMOTE_PATH` → `dest_path` | 视频的绝对远程目录。 |
| `keep_local` | `false` | 传输后保留本地暂存副本。 |
| `use_archive` | `false` | 记录+跳过已下载的ID(按模式)。 |
| `plex_playlist` | 环境变量`YTDLP_PLEX_PLAYLIST` → 配置Plex时为`yt-dlp Downloads` | Plex播放列表标题或ID,用于添加下载的音频轨道。 需要`YTDLP_PLEX_URL`和`YTDLP_PLEX_TOKEN`。 |
| `response_format` | `markdown` | `markdown`或`json`。 |
当配置了Plex凭证时,成功的下载会为每个下载的音轨搜索Plex,创建目标播放列表(如果需要),并添加缺失的音轨,同时跳过已存在的条目。 默认播放列表是`yt-dlp Downloads`;设置`YTDLP_PLEX_PLAYLIST`或传递`plex_playlist`以覆盖它。 Plex错误被报告为`plex_playlist_error`,不会使已完成的下载失败。 JSON响应包含`plex_playlist`摘要,包含`matched`、`added`、`already_present`和`missing`计数。
规范的元数据匹配通过MusicBrainz/AcoustID在`docs/musicbrainz-acoustid.md`中有详细说明。 `youtube_download`在配置了`YTDLP_ACOUSTID_CLIENT_KEY`时,会自动为下载的音频进行高置信度的MusicBrainz重新标记;`youtube_identify`仍然可用于预览或修复现有的库文件,并通过`write_tags=true`启用手动标记写入。
#### `youtube_download` JSON 响应
使用`response_format=json`时,调用返回一个描述批次的单个对象:
| 字段 | 含义 |
| --- | --- |
| `transferred` | 如果每个生成的子树都到达远程,则为`true`。 |
| `transfer_error` | 成功时为`null`,否则为失败/超时消息(字符串)。 |
| `remote` / `dest_path` / `destination` / `destinations` | 实际使用的远程和每个类型的目的地。 |
| `staging_kept_at` | 保留用于重试的本地暂存路径(如果传输失败或请求保留本地副本)。 |
| `total_files` / `total_bytes` / `total_size` | 跨所有项目的汇总计数。 |
| `partial_items` | 错误但仍生成文件的项目的计数。 |
| `failed_items` | 错误且未生成文件的项目的计数。 |
| `items[]` | 每个URL的结果,每个结果都有一个`status`、`title`、`video_id`、`error`和`files[]`列表。 |
每个`items[].status`都是以下之一:
- `ok` — 成功生成文件。
- `partial` — 发生错误,但仍生成了一些文件。
- `failed` — 错误且无文件。
- `skipped` — 无新内容(已在存档中)。
仅当相关阶段运行时,才会附加可选键:
- `metadata_retag` — MusicBrainz/AcoustID自动重新标记摘要(`attempted`、`matched`、`written`、`skipped`、`errors`或错误字符串);当配置了`YTDLP_ACOUSTID_CLIENT_KEY`时存在。
- `plex_playlist` — Plex播放列表摘要(`playlist`、`matched`、`added`、`already_present`、`missing`);如果Plex更新失败,则设置`plex_playlist_error`(Plex失败不会导致下载失败)。
- `history_error` — 当下载成功但JSONL账本追加失败时设置。
`youtube_probe`接受`urls`和`response_format`。
### `youtube_identify` 参数
| 参数 | 默认值 | 含义 |
| --- | --- | --- |
| `paths` | — (必填) | 一个本地音频文件路径字符串或路径数组。 |
| `write_tags` | `false` | 将高置信度的MusicBrainz预览写入音频文件。 |
| `response_format` | `markdown` | `markdown`或`json`。 |
`youtube_identify`运行Chromaprint `fpcalc`,将指纹发送到AcoustID,并返回MusicBrainz录音候选项。 当最佳候选项具有高置信度时,它还会获取MusicBrainz录音/发行版数据,并包含一个`retag_preview`,显示规范的艺术家、标题、发行版、发行日期、发行类型、曲目编号和MusicBrainz ID。 默认情况下,它仅用于预览。 使用`write_tags=true`时,它会使用Lofty将预览写入文件,包括常见的标题/艺术家/专辑/日期/曲目字段以及MusicBrainz录音、发行版、发行组和发行类型标签。 它需要`YTDLP_ACOUSTID_CLIENT_KEY`;设置`FPCALC_PATH`如果`fpcalc`不在`PATH`上。
### `youtube_search` 参数
| 参数 | 默认值 | 含义 |
| --- | --- | --- |
| `query` | - (必填) | YouTube搜索文本。 服务器将其传递给yt-dlp作为`ytsearchN:<query>`。 |
| `limit` | `10` | 结果数,限制在`1..=25`。 |
| `response_format` | `markdown` | `markdown`或`json`。 |
`youtube_search_ui`接受相同的输入并返回相同的搜索负载,以及MCP应用元数据以支持主机渲染嵌入式UI。
### `youtube_stats` 参数
| 参数 | 默认值 | 含义 |
| --- | --- | --- |
| `limit` | `10` | 要包含的最近账本条目数,限制在`0..=100`。 |
| `response_format` | `markdown` | `markdown`或`json`。 |
JSON统计数据包括`total_downloads`、`total_files`、`total_bytes`、`skipped_entries`、`by_kind`、`by_uploader`和`recent`。 桶字段包括`downloads`(兼容性别名调用计数)、`calls`、`items`、`files`、`bytes`和人类可读的`size`。 格式错误的账本行被跳过并计数,而不是使整个统计调用失败。 如果下载成功但账本追加失败,则下载响应仍然成功并在JSON输出中包含`history_error`。
## 安装
通过npm运行引导安装程序:
```bash
npx -y ytdl-rmcp setup
```
或全局安装命令:
```bash
npm i -g ytdl-rmcp
ytdl-rmcp setup
```
npm包在`postinstall`期间下载匹配的GitHub Release二进制文件;安装的命令是通过小Node启动器提供的Rust二进制文件。 您还可以使用一键安装程序:
```bash
curl -fsSL https://raw.githubusercontent.com/jmagar/ytdl-rmcp/main/scripts/install.sh | bash
```
或从
[Releases](https://github.com/jmagar/ytdl-rmcp/releases)下载二进制文件tarball,或自行构建(参见下文)。 引导安装程序获取yt-dlp + ffmpeg,提示您的SSH远程和音频/视频目的地,检测哪些代理CLI存在,并将服务器注册到您选择的代理中。
### 手动注册
运行不带子命令,`npx -y ytdl-rmcp`通过stdio提供MCP。 自己注册:
```bash
# Claude Code
claude mcp add -s user ytdl-rmcp -e YTDLP_REMOTE=tootie -e YTDLP_REMOTE_PATH=/media/music -- npx -y ytdl-rmcp
# Codex
codex mcp add --env YTDLP_REMOTE=tootie --env YTDLP_REMOTE_PATH=/media/music ytdl-rmcp -- npx -y ytdl-rmcp
# Gemini CLI(命令是位置参数,env在最后)
gemini mcp add -s user ytdl-rmcp npx -y ytdl-rmcp -e YTDLP_REMOTE=tootie -e YTDLP_REMOTE_PATH=/media/music```
如果您已经使用`npm i -g ytdl-rmcp`安装了独立二进制文件,使用该二进制文件路径代替`npx -y ytdl-rmcp`。
### 分发形式
- **npm启动器** — `npx -y ytdl-rmcp`下载并运行匹配的GitHub Release二进制文件。 运行不带子命令,它通过stdio提供MCP;`npx -y ytdl-rmcp setup`运行引导安装程序。 稳定版本从GitHub Actions发布包并带有npm证明。
- **Claude Code插件** — `.claude-plugin/plugin.json`提示用户配置via`userConfig`;`.mcp.json`启动`npx -y ytdl-rmcp`,它通过npm下载匹配的GitHub Release二进制文件。
- **Gemini CLI扩展** — `gemini-extension.json`;安装`gemini extensions install https://github.com/jmagar/ytdl-rmcp`。MCP客户端应优先使用npm启动器命令`npx -y ytdl-rmcp`。
- **容器镜像** — `ghcr.io/jmagar/ytdl-rmcp:main`在每次推送到`main`时发布。 它包含`ffmpeg`、`fpcalc`、`openssh-client`和`rsync`。 查看
[`docs/container.md`](docs/container.md)中的MCP和挂载库示例。
- **MCP包(`.mcpb` / `.dxt`)` — ``mcpb/manifest.json`定义一个`binary`类型的包,提供一键安装到支持MCPB的桌面主机。 每个主版本发布`ytdl-rmcp.mcpb`和旧版`ytdl-rmcp.dxt`别名;两者包含相同的linux + windows二进制文件。 包默认为可选配置值为空字符串,因此Claude Desktop可以在您填写SSH目标设置之前安装它。 在扩展设置中配置至少远程和音频目的地,然后再下载。
## 配置(环境变量)
| 变量 | 默认值 | 含义 |
| --- | --- | --- |
| `YTDLP_REMOTE` | — | 用于传输的SSH远程(别名或`user@host`)。 |
| `YTDLP_REMOTE_PATH` | — | 音频的绝对远程目录。 |
| `YTDLP_VIDEO_REMOTE_PATH` | 回归音频 | 视频的绝对远程目录。 |
| `YTDLP_AUDIO_FORMAT` | `mp3` | 默认音频编解码器。 |
| `YTDLP_STAGING_DIR` | 系统临时目录 | 本地暂存基准目录。 |
| `YTDLP_SSH_OPTS` | — | 使用shell-word语法解析的额外ssh选项;附加到强制的`BatchMode`/`StrictHostKeyChecking`标志后。 示例: `-i "~/.ssh/ytdl key" -o ProxyJump=media-bastion`。 格式错误的引用被拒绝。 |
| `YTDLP_ARCHIVE_DIR` | 每用户状态目录 | `use_archive`历史存储位置。 |
| `YTDLP_HISTORY_PATH` | 每用户状态目录`downloads.jsonl` | `youtube_stats`使用的JSONL下载账本。 |
| `YTDLP_PLEX_URL` | — | Plex服务器URL,例如`http://plex.local:32400`,用于将音频下载添加到Plex播放列表。 |
| `YTDLP_PLEX_TOKEN` | — | 用于播放列表/搜索API调用的Plex身份验证令牌。 |
| `YTDLP_PLEX_PLAYLIST` | 配置Plex URL/令牌时为`yt-dlp Downloads` | `youtube_download`的默认Plex播放列表标题或ID;可以通过`plex_playlist`参数覆盖。 |
| `YTDLP_CLEAN_METADATA` | `1` | 在嵌入元数据之前剥离常见的YouTube标题噪音。设置为`0`以精确保留源标题。 |
| `YTDLP_ACOUSTID_CLIENT_KEY` | — | `youtube_identify`所需的AcoustID应用程序API密钥;设置后,`youtube_download`自动将高置信度的MusicBrainz标签写入下载的音频。 |
| `FPCALC_PATH` | `PATH`上的`fpcalc` | Chromaprint `fpcalc`可执行文件的可选显式路径。 |
| `YTDLP_MUSICBRAINZ_CONTACT` | GitHub仓库URL | 查找User-Agent字符串中包含的联系网址/电子邮件。 |
| `YTDLP_AUTO_UPDATE` | `1` | yt-dlp过时时重新下载。 |
| `YTDLP_MAX_AGE_DAYS` | `14` | 过时阈值(天)。 |
| `YTDLP_UPDATE_PRE` | `0` | 跟踪yt-dlp的夜间频道。 |
| `YTDLP_EXTRACTOR_ARGS` | — | 传递给yt-dlp `--extractor-args`,例如 `youtube:player_client=android` 访问视频默认客户端无法访问的视频。 |
| `YTDLP_TIMEOUT_SECS` | `1800` | 每个yt-dlp探测/下载命令的超时时间。 |
| `YTDLP_TRANSFER_TIMEOUT_SECS` | `600` | 每个传输阶段的超时时间。 |
| `YTDLP_SHA256` / `FFMPEG_SHA256` | — | yt-dlp / ffmpeg解析所需的SHA-256哈希值。 |
| `YTDLP_PATH` / `FFMPEG_PATH` | — | 使用特定的yt-dlp / ffmpeg,而不是自动下载。 |
| `YTDLP_LOG` | `info` | `tracing`过滤器(仅stderr)。 |
> **维护者:** 该表格**手动维护**。 `scripts/check-packaging.sh`仅交叉检查四个机器可读的配置表面(Claude插件`.mcp.json` / `userConfig`,`gemini-extension.json`和`mcpb/manifest.json`);它**不**读取此README。 当您添加,重命名或删除`YTDLP_*`环境变量时,请手动更新此表格 - CI中没有任何内容会捕获漂移。
### 引导信任模型
默认情况下,第一次运行解析工具的顺序为:显式环境变量覆盖,`PATH`,缓存,然后是HTTPS从上游发布源下载。 设置`YTDLP_SHA256`和/或`FFMPEG_SHA256`以要求解析或下载后执行二进制文件摘要验证。 这些固定值验证磁盘上的字节,但它们不提供上游签名验证或自动发现受信任的哈希值;需要通过`YTDLP_PATH` / `FFMPEG_PATH`和匹配的SHA-256固定值提供已知良好的二进制文件,或者禁用yt-dlp自动更新。
对于更严格的引导控制,请将`YTDLP_PATH` / `FFMPEG_PATH`与匹配的`YTDLP_SHA256` / `FFMPEG_SHA256`固定值结合使用。 哈希固定值验证解析的二进制文件字节;它们不是上游签名验证。
### 安全姿态
该服务器旨在与**受信任的调用者和操作员提供的配置**一起运行 - 它不是一个强化的多租户边界。
- **工具调用URL到达yt-dlp。** 传递给yt-dlp的`urls`由MCP调用者传递。 调用者只允许使用http/https工具调用URL到达yt-dlp,并且每个位置参数都传递到 `--`结束选项分隔符之后,因此不能将`-`前缀值解析为标志;无论如何,信任假设仍然成立。
- **SSH仅限密钥,无交互。** 传输强制`BatchMode=yes`和`StrictHostKeyChecking=accept-new`,因此TTY-less服务器快速失败而不是提示;没有密码身份验证。 身份验证来自您的SSH密钥/代理和您通过`YTDLP_SSH_OPTS`添加的任何选项。
- **远程规格和路径经过验证。** `RemoteSpec`和`RemotePath`新类型拒绝空值,选项样式(以`-`开头的)远程和空白/控制字符,然后在`ssh`/`rsync`/`scp`到达远程shell之前对远程路径进行单引号转义。
## 需求
- **ssh** (和可选的**rsync** — 如果没有,则回退到**scp**,例如在Windows上)。
- 远程上无密码基于密钥的SSH身份验证。
- yt-dlp和ffmpeg自动获取(或使用`YTDLP_PATH` / `FFMPEG_PATH`覆盖,或者它们在`PATH`上)。
- `youtube_identify`还需要`fpcalc`; 容器镜像通过`libchromaprint-tools`包含它。
## 从源代码构建
```bash
cargo build --release # Linux/macOS
cargo test && cargo clippy --all-targets -- -D warnings # 检查
# 从 Linux 进行跨编译到 Windows(需要 nasm 和 LLVM 工具链):
sudo apt-get install -y nasm llvm clang lld
cargo install cargo-xwin
cargo xwin build --release --target x86_64-pc-windows-msvc
```
在 dookie/local shell 上,`~/.local/bin/cargo` 是一个包装器,可能会破坏
`cargo xwin`;在本地进行 Windows 演练时,请使用真正的 rustup cargo:
```bash
~/.cargo/bin/cargo xwin build --release --target x86_64-pc-windows-msvc
```
CI(`.github/workflows/`)在每次推送/PR 上运行 fmt + clippy + 测试和 Windows 跨编译构建,并将二进制文件发布到 `v*` 标签的 GitHub Release 上。
该 crate 故意保持在 Rust 2021 版本,以用于可分发的单二进制文件/插件构建。只有在证明了 Linux、Windows MSVC 跨编译和插件启动兼容性之后,才会迁移到 2024 版本。
## 工作原理
裸调用通过 stdio 提供 MCP 服务;`setup` 运行安装程序。`youtube_download` 调用:
1. 解析 yt-dlp + ffmpeg(环境变量覆盖 → PATH → 缓存 → 下载)并在配置时验证 SHA-256 校验和。
2. 清理混合/广播 URL,然后按模式运行 yt-dlp 到一个暂存树(`staging/audio`,`staging/video`),带有元数据/缩略图/存档标志、源元数据边车和 `Artist/Title [id]` 输出模板。
3. *(可选)* 当设置了 `YTDLP_ACOUSTID_CLIENT_KEY` 时,对下载的音频进行指纹识别,并写入高置信度的 MusicBrainz/AcoustID 标签原地 - 在传输之前,以便远程副本携带规范标签。
4. 将每种类型的子树传输到其自己的远程目录(rsync,否则 scp)。
5. *(可选)* 当配置了 Plex 凭证并且传输成功时,将下载的音频轨道添加到目标 Plex 播放列表中。
6. 将完成的调用追加到 JSONL 下载账本中。
7. 返回一个 markdown 或 JSON 摘要,列出文件、大小和实际目的地。
参见 `CLAUDE.md` 以了解架构、约定和注意事项。
## 许可证
MIT — 参见 `LICENSE`。
## Rust MCP 命名模式
此仓库遵循 Rust MCP 服务器命名约定:
- 仓库:`ytdl-rmcp`
- CLI 别名:`rytdl`
- npm 包:`ytdl-rmcp`
MCP 配置
以下是此 MCP Server 的配置信息,可直接复制到 Cursor 或其他 MCP 客户端中使用。
mcp.json
连接信息
猜你喜欢
暂无推荐服务器