feat(yt-dlp-mcp): in-tree MCP server + /add-ytdlp installer#2306
Open
CrAzyScreamx wants to merge 8 commits into
Open
feat(yt-dlp-mcp): in-tree MCP server + /add-ytdlp installer#2306CrAzyScreamx wants to merge 8 commits into
CrAzyScreamx wants to merge 8 commits into
Conversation
Mirrors /add-ffmpeg's tactic: patches container/Dockerfile to install the standalone yt-dlp_linux binary, adds @kevinwatt/yt-dlp-mcp as an agent-runner runtime dep (pinned), and wires it as a stdio MCP server per agent group via mcpServers entry. The MCP server self-describes its 8 ytdlp_* tools (search, metadata, subtitles, transcripts, video, audio), so no container skill is shipped alongside. YTDLP_DOWNLOADS_DIR is set to /workspace/agent/tmp so downloads are ready for mcp__nanoclaw__send_file. Idempotent install via the '# ---- yt-dlp' Dockerfile anchor; removal section reverses each phase symmetrically. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
OneCLI's gateway intercepts HTTPS with a self-signed CA and sets SSL_CERT_FILE at the container level so tools trust it. The MCP SDK's StdioClientTransport, however, strips most env vars when spawning MCP server children — only HOME/LOGNAME/PATH/SHELL/TERM/USER propagate by default — so yt-dlp inside the MCP child never sees the CA bundle and fails with CERTIFICATE_VERIFY_FAILED, even on plain YouTube URLs. Re-inject SSL_CERT_FILE, REQUESTS_CA_BUNDLE, and CURL_CA_BUNDLE through the per-MCP env block in container.json so they survive the filter. The bundle is already mounted by OneCLI at /tmp/onecli-combined-ca.pem; we just need to point yt-dlp's three network paths (stdlib ssl, requests/urllib3, curl fallback) at it. Also adds a troubleshooting entry for the cert verify failure mode. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The previous attempt (4361425) re-injected SSL_CERT_FILE, REQUESTS_CA_BUNDLE, and CURL_CA_BUNDLE through the per-MCP env block on the theory that yt-dlp would honor them and trust OneCLI's intercepting CA. Empirical test in a live agent container showed this didn't work: standalone yt-dlp (PyInstaller binary) uses certifi's bundled CA store baked into the binary itself, ignoring all three env vars. curl trusts OneCLI's CA via the same env vars fine, but yt-dlp doesn't. The actual fix is to bypass the proxy entirely for yt-dlp via NO_PROXY=*. yt-dlp is fetching public video from YouTube/Vimeo/etc. — there's no credentialed API for OneCLI to inject into, so routing it through the gateway has no upside, only the cert friction. Both upper and lower case are set because Python stdlib checks NO_PROXY while some libs check no_proxy. Verified inside a live container: yt-dlp --simulate against YouTube returns the title with NO_PROXY=*; without it, fails with CERTIFICATE_VERIFY_FAILED on every retry. Updates the troubleshooting entry to reflect the actual cause and fix (binary's bundled certifi store cannot be overridden via env). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Switch the default download directory to /tmp, which is container- internal (not bind-mounted from the host). Previously, /workspace/agent/tmp was a RW bind-mount of groups/<folder>/tmp/, so every video the agent downloaded persisted on the host indefinitely — there is no auto-sweep for non-ffmpeg files in that directory, so downloads accumulated. /tmp lives only inside the running container, so --rm cleans everything up on container exit. send_file already copies the bytes to /workspace/outbox/<msg-id>/ before delivery, so downloads don't need to outlive the container — there's no functional regression, just less host clutter. Updates Phase 4 default + the explanation paragraph + troubleshooting. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replace the upstream @kevinwatt/yt-dlp-mcp dependency with an in-tree MCP
server under container/agent-runner/src/yt-dlp-mcp/. Mirrors the existing
ffmpeg-mcp pattern (stdio transport, per-group opt-in via container.json,
spawned by Bun directly off the source bind mount).
Curated tool surface tuned for chat agents:
ytdlp_search search with pagination, sort, duration/views filters,
md or json output, maxChars cap
ytdlp_get_metadata full json or compact summary, maxChars cap
ytdlp_download_video mp4 (default) → best-quality fallback on failure
ytdlp_download_audio mp3 (default) → native bestaudio fallback if ffmpeg
is missing or transcoding fails
Skill rewritten to drop the bun add step; container.json now points at
/app/src/yt-dlp-mcp/server.ts. Dockerfile patch (yt-dlp binary install) is
unchanged.
The previous mp4 selector (`bv*[ext=mp4]+ba[ext=m4a]`) resolved to whatever codec yt-dlp found inside the mp4 container. On most modern sources that's VP9 or AV1, which does not play in QuickTime, iOS Photos, or render inline in WhatsApp/Telegram — the user has to re-encode before sending. Add a `codec` parameter (default `h264`) that injects a vcodec filter into the format selector. Other codecs are exposed (h265, av1, vp9, any) for when the caller wants something else, but the chat-agent default now produces a file that plays everywhere out of the box. The existing best-quality fallback still runs unchanged when the codec constraint can't be satisfied, so requests don't fail just because a source lacks an H.264 ladder.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Type of Change
.claude/skills/<name>/, no source changes)Description
Adds
/add-ytdlp— installs yt-dlp (search YouTube, fetch metadata, download video/audio from YouTube, Vimeo, X, TikTok, ~1000 other sites) as an MCP tool for agent groups.Two pieces:
Install skill (
.claude/skills/add-ytdlp/SKILL.md) — patchescontainer/Dockerfileto install the standalone PyInstaller yt-dlp binary (~30MB, no Python on PATH needed, pinned viaYTDLP_VERSIONarg), then wires the in-tree MCP server into selected agent groups'
container.jsonundermcpServers. Idempotent install/removal with anchored Dockerfile blocks.In-tree MCP server (
container/agent-runner/src/yt-dlp-mcp/) — stdio transport, spawned by Bun directly off the source bind mount,Curated 4-tool surface tuned for chat agents:
ytdlp_search— paginated search with sort/duration/views filters, md or json output,maxCharscapytdlp_get_metadata— full json or compact summary,maxCharscapytdlp_download_video— mp4/H.264 (avc1) default for broad device compatibility, falls back to best-quality on failureytdlp_download_audio— mp3 default via ffmpeg, falls back to native bestaudio if ffmpeg missing or transcode failsYTDLP_DOWNLOADS_DIRdefaults to/tmpso downloaded files are ready formcp__nanoclaw__send_file.For Skills