rad-migrate
OfficialProvides tools to migrate YouTube channels to Rad TV, including downloading videos in HD, preserving title, description, thumbnail, release date, and creating playlists in upload order.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@rad-migrateMigrate my YouTube channel to Rad TV and show me the plan"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
rad-migrate
Move your YouTube channel to Rad TV in one command.
export RAD_API_KEY=rad_...
rad-migrate @yourchannelThat's the whole thing. rad-migrate downloads your channel in HD and publishes every video to Rad TV with its title, description, thumbnail, and original release date, then builds a playlist in the original upload order.
rad-migrate 0.1.0
✓ node 22.22 · ffmpeg 8.1 · yt-dlp 2026.08 · Rad auth ok
✓ quality probe 1080p available (no cookies)
→ channel: Your Channel · 47 videos
→ 12 already on Rad · 3 vertical, skipped · 32 to migrate
[ 7/32] Inside Barolo Grill uploading 412.8 MBStop it any time. Run it again and it picks up exactly where it left off.
Built for creators moving content they own. See Ownership.
Contents
Related MCP server: @kirbah/mcp-youtube
Install
There is nothing to build. rad-migrate is a Python package — install it and run it.
# Not yet on PyPI. For now, install from source:
uv tool install git+https://github.com/little-core-labs/rad-migrate
# or with pipx
pipx install git+https://github.com/little-core-labs/rad-migrateuvx rad-migrate @yourchannel # run without installing
uv tool install rad-migrate # or install it
pipx install rad-migrateTwo things pip cannot install for you
rad-migrate needs Node 20+ (22 recommended) and ffmpeg on your PATH.
# macOS
brew install node ffmpeg
# Windows
winget install OpenJS.NodeJS.LTS Gyan.FFmpeg
# Debian/Ubuntu
sudo apt install nodejs ffmpegNode is not optional and not a build tool — YouTube requires a JavaScript runtime to hand over HD stream URLs, and without it downloads silently drop to low quality rather than failing. ffmpeg merges YouTube's separate video and audio streams.
If you would rather not install any of this, use the Docker image — it ships the whole toolchain.
Your first run
Four steps. The first three cost seconds and save hours.
1. Check the machine.
rad-migrate doctorVerifies Node, ffmpeg, yt-dlp, disk space, and your Rad credentials.
2. Check what quality you'll actually get.
rad-migrate doctor @yourchannel
# ✓ quality probe 1080p available (no cookies)This probes one real video. It is the single most useful thing you can do before a long run — a degraded YouTube session caps everything at 360p, and this catches it in five seconds instead of one wasted file at a time.
3. See what would move.
rad-migrate plan @yourchannelDownloads and publishes nothing. Shows the videos, what's already on Rad, and what your filters excluded.
4. Migrate one video first, then the rest.
rad-migrate @yourchannel --limit 1 # one full round trip
rad-migrate @yourchannel # everythingThe --limit 1 run proves your credentials, the channel, the upload path, and the
transcode before you commit hours to it.
Do you need cookies? Probably not.
Most tools in this space open by telling you to export a cookies.txt. rad-migrate
doesn't, because usually it isn't necessary — and when it is, cookies are the last
resort rather than the first.
rad-migrate doctor @yourchannel tells you. If it reports 1080p, you're done — no
account, no setup, nothing to configure.
If it reports a cap, rad-migrate names the one command that fixes it, in this order:
1. A proof-of-origin token — no Google account involved.
rad-migrate setup-potokenYouTube increasingly wants a "proof of origin" token, now bound to each individual
video id, so tokens can't be extracted by hand any more. This installs a provider that
mints them: one self-contained binary, verified against the SHA-256 checksum GitHub
publishes for the pinned release. No Node, no npm, no Docker, no sign-in. It shows you
exactly what it will download and asks before doing it. Remove it with
rad-migrate setup-potoken --remove.
2. Your browser session — only if that isn't enough.
rad-migrate @yourchannel --cookies-from-browser firefoxReads cookies straight from your browser; no manual export. Prefer Firefox. Since Chrome 127, Windows binds the cookie encryption key to the Chrome process, so no external tool can read Chrome, Edge, or Brave cookies there. rad-migrate detects this and says so instead of failing with a decryption error.
Worth knowing: this is the risky rung, not the easy one. Bulk-downloading against your own signed-in session is the pattern YouTube's abuse systems look for — and for a creator migrating their own channel, that session belongs to the account the channel lives on. The token route above touches no account at all.
3. A cookie file — for Docker and headless machines, where browser extraction can't work:
rad-migrate @yourchannel --cookies-file cookies.txtCommands
rad-migrate @yourchannel # migrate (shorthand for `rad-migrate run`)
rad-migrate plan @yourchannel # show what would happen, change nothing
rad-migrate doctor @yourchannel # check the machine and the quality
rad-migrate status # progress from previous runs
rad-migrate retry @yourchannel # retry only what failed
rad-migrate setup-potoken # install the HD token provider
rad-migrate mcp # run as an MCP server for AI agentsAny of @handle, handle, a full URL, or a UC… channel id works.
Every command takes --help.
Choosing what moves
rad-migrate @yourchannel \
--newest 50 \ # the 50 most recent
--since 2024-01-01 \ # nothing older
--landscape-only \ # skip vertical videos (Shorts)
--min-duration 60 \ # skip anything under a minute
--playlist "My Channel" # build a playlist in upload orderFlag | What it does |
| Destination Rad channel, by id or name |
| Create the Rad channel if it doesn't exist |
| Cap this run at N videos — good for a first test |
| Only the N most recent |
| Nothing uploaded before this date |
| Skip vertical videos |
| Bounds in seconds |
|
|
| Quality floor, default 720 |
| Accept standard definition instead of failing |
| Build a playlist from what was migrated |
| Delete local files once Rad confirms processing |
| Where downloads and resume state live |
| Skip the pre-run checks |
| Machine-readable output |
Quality is verified, not assumed
Under the default hd-strict, a video that can't be had in HD is failed rather than
saved in standard definition — and every finished download is probed to confirm what
actually landed on disk, not what was requested. A failure is never recorded as done,
so the next run retries it on a healthier session. That's usually all it takes.
Pass --allow-sd if you'd rather have the video at any resolution.
What you end up with
On Rad: one content item per video, with the original title, description, thumbnail, and release date, plus a playlist in upload order if you asked for one. Portrait video is published as portrait. Videos are marked done only once Rad confirms the transcode finished — not merely that the upload succeeded.
On disk, under --workdir (default ./rad-migrate-work):
rad-migrate-work/
├── state.db resume journal
└── media/
└── <channel-id>/
└── 2024-03-15 - Video Title [dQw4w9WgXcQ]/
├── video.mp4 the download
├── video.info.json full yt-dlp metadata
├── video.webp original thumbnail
└── thumbnail.jpg converted for uploadAdd --cleanup to delete each folder once Rad confirms processing — a channel can
easily run to tens of gigabytes.
Resuming, and running it twice
Safe to interrupt, safe to re-run. State advances one video at a time and is written immediately, so a crash or a Ctrl-C loses at most the video in flight.
Re-running is idempotent because rad-migrate asks Rad what's already on the channel rather than trusting a local file. So a second run on a different machine, with no local state at all, still won't publish the same video twice.
state.db is a cache, not the source of truth. Delete it and the next run re-scans; it
still won't double-publish.
Known limits
All of these come from the Rad API as it stands today, and are documented in detail — with proposed fixes — in docs/rad-api-notes.md.
Limit | Why |
Dedupe matches on title + release date | The API has no field to record a source id, so matching can't be exact |
Dedupe only covers the 100 most recent items | The content listing endpoint caps at 100; rad-migrate warns rather than silently under-reporting |
No delete | The API exposes |
Subtitles aren't uploaded | They're downloaded and kept locally; Rad has no caption endpoint |
Use it from an AI agent
MCP server
Works with Claude Desktop, OpenClaw, Hermes, and anything else that speaks MCP:
{
"mcpServers": {
"rad-migrate": {
"command": "rad-migrate",
"args": ["mcp"],
"env": { "RAD_API_KEY": "rad_..." }
}
}
}Tools: check_environment, plan_migration, start_migration, migration_status,
cancel_migration, retry_failed, install_potoken_provider.
start_migration returns a job id immediately and runs in the background — a channel
can take hours, so no tool call ever blocks. The agent polls migration_status, which
reads the same journal the CLI does, so you and the agent watch the same run.
Claude Code
/plugin marketplace add little-core-labs/rad-migrate
/plugin install rad-migrateThen /rad-migrate @yourchannel.
Scripting
--json puts a single parseable result on stdout and streams NDJSON progress events on
stderr, so the two never interleave:
rad-migrate plan @yourchannel --json | jq '.to_migrate'Docker
Ships Node, ffmpeg, and yt-dlp, so there is nothing to install.
docker run --rm \
-e RAD_API_KEY \
-v "$PWD/work:/work" \
ghcr.io/little-core-labs/rad-migrate @yourchannel --workdir /workBrowser cookie extraction can't work in a container, so mount a cookies.txt and use
--cookies-file if you need it.
Configuration
Flags beat environment variables beat .env beat defaults. Copy
.env.example to .env to get started.
Variable | Purpose |
| Required. Your Rad TV API key. |
| Destination channel |
| Downloads and state, default |
|
|
| Path to a |
Your API key is never written to state, logs, or --json output. Everything rad-migrate
prints passes through a redaction filter first, and there's a test asserting it. See
SECURITY.md.
Troubleshooting
Everything downloads at 360p. Run rad-migrate doctor @yourchannel. Almost always a
missing JS runtime (install Node 22+) or a degraded session (rad-migrate setup-potoken).
"Sign in to confirm you're not a bot". YouTube is throttling. rad-migrate backs off automatically and reduces its API calls per video. If it persists, wait — the throttle is per-session and lifts.
Chrome cookies won't read on Windows. They can't be, by design, since Chrome 127.
Use Firefox or --cookies-file.
A transcode failed on Rad. The upload worked; the conversion didn't. Retry with
rad-migrate retry @yourchannel. Videos are only reported done once Rad confirms
processing, so a failure here is visible rather than silent.
It's slow. Deliberately. YouTube throttles the extraction API per session, so rad-migrate paces itself to survive a whole channel rather than sprinting into a block.
More detail: skills/rad-migrate/references/troubleshooting.md.
Ownership
This tool exists for creators moving their own work to a platform of their choosing. Downloading other people's videos to republish them is both a copyright problem and a YouTube Terms of Service problem, and that isn't what this is for.
If you want your own originals with no bot-detection in the loop at all, Google Takeout exports the source files YouTube holds for your channel. It's slower and more manual, but it's the fully sanctioned path.
Contributing
See CONTRIBUTING.md.
git clone https://github.com/little-core-labs/rad-migrate && cd rad-migrate
uv sync --dev
uv run pytestSources and destinations sit behind protocols in
source/base.py and
dest/base.py — new ones are welcome.
License
MIT
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceGives AI coding agents full control over a YouTube channel with 22 tools for channel management, videos, playlists, comments, search, analytics, thumbnails, and captions.272MIT
- AlicenseNot gradedqualityBmaintenanceProvides AI agents with token-optimized access to YouTube data, including video details, transcripts, channel statistics, trending videos, and search.572MIT
- FlicenseNot gradedqualityBmaintenanceEnables managing a YouTube channel through natural language: upload videos, edit metadata, set thumbnails, run pseudo A/B thumbnail tests, and pull analytics.
- AlicenseBqualityCmaintenanceProvides comprehensive access to YouTube Data, Analytics, and Reporting APIs, enabling AI assistants to manage videos, analyze performance, handle comments, and extract transcripts.40MIT
Related MCP Connectors
YouTube transcripts, search, channels, playlists and bulk transcript jobs for AI agents. 14 tools.
Manage SRG+ hubs, channels, content, assets, users, and workspaces from any MCP-aware AI agent.
15 media & data tools for AI agents: search, transcribe, subtitles, voiceover, translate & more.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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/little-core-labs/rad-migrate'
If you have feedback or need assistance with the MCP directory API, please join our Discord server