Are you the author? Sign in to claim
YouTube playlist curation engine — inventory, deduplicate, merge, clean, and reorganise 20 years of playlists via CLI, M
YouTube playlist curation engine — inventory, deduplicate, merge, clean up, and reorganise thousands of playlists spanning 20 years.
┌────────────────────────────────────────────────────┐
│ yt-curator │
│ │
│ ┌─────────┐ ┌─────────┐ ┌────────────────────┐ │
│ │ CLI │ │ MCP │ │ Python Library │ │
│ │ (Click)│ │ (FastMCP)│ │ (import yt_curator)│ │
│ └────┬────┘ └────┬────┘ └─────────┬──────────┘ │
│ │ │ │ │
│ └──────┬─────┘─────────────────┘ │
│ │ │
│ ┌────────▼────────┐ │
│ │ YouTube Data │ │
│ │ API v3 + OAuth│ │
│ │ + Local SQLite │ │
│ └─────────────────┘ │
└────────────────────────────────────────────────────┘
yt-curator)# OAuth setup (one-time)
yt-curator auth
# Full inventory scan
yt-curator inventory
# Reports
yt-curator report
yt-curator find-dupes
yt-curator find-dead
# Curation (try --dry-run first!)
yt-curator merge PL_source_id PL_target_id --dry-run
yt-curator dedup PL_playlist_id --dry-run
yt-curator delete PL_playlist_id --dry-run
# Start MCP server
yt-curator serve-mcp
yt-curator-mcp)Register as a backend for any MCP client (Claude Desktop, Hermes, Cursor, etc.).
stdio mode (default — plug-and-play with Claude Desktop):
{
"mcpServers": {
"yt-curator": {
"command": "yt-curator",
"args": ["serve-mcp"]
}
}
}
SSE mode (register with the mcp-gateway):
yt-curator serve-mcp --host 0.0.0.0 --port 39401
Then add to your gateway config:
backends:
- name: yt-curator
type: sse
url: http://127.0.0.1:39401
Available MCP tools:
| Tool | Description |
|---|---|
list_playlists() | List all playlists in the inventory DB |
get_playlist_contents(id) | List all videos in a specific playlist with status |
scan_inventory() | Full scan — all playlists, items, and video status |
curation_report() | Summary stats from inventory |
find_duplicates(min=2) | Cross-playlist duplicate detection |
find_dead_videos() | Dead/private/blocked videos |
find_empty_playlists() | Zero-video playlists |
suggest_merges() | Title-similarity merge candidates |
merge_playlists(src, dst, dry_run=True) | Merge with dry-run mode |
delete_playlist(id, dry_run=True) | Delete with dry-run mode |
remove_dead_videos(dry_run=True) | Bulk dead video removal |
auth_status() | Check OAuth credentials |
import yt_curator)from yt_curator.core.client import YouTubeClient
from yt_curator.core.inventory import scan_all
client = YouTubeClient()
report = scan_all(client)
print(f"Scanned {report.total_playlists} playlists")
YouTube Data API v3 default: 10,000 units/day (free).
| Operation | Cost per call | Your 900-playlist scan |
|---|---|---|
playlists.list | 1 | ~18 calls |
playlistItems.list | 1 | ~900 calls |
videos.list (status check) | 1 | ~120 calls |
playlists.insert / .update | 50 | per operation |
playlistItems.insert / .delete | 50 | per operation |
| Full inventory scan | ~1,200 units ✅ |
A full scan uses ~12% of your daily quota, leaving 8,800 units for curation writes (about 175 write operations per day).
client_secret.json~/.config/yt-curator/client_secret.jsonyt-curator auth — opens a browser for Google loginTip for headless servers: Run
yt-curator authonce on a desktop machine with a browser, then copy~/.config/yt-curator/token.jsonto the server.
Add yt-curator to your flake inputs:
{
inputs.yt-curator = {
url = "github:telos-systems/yt-curator";
inputs.nixpkgs.follows = "nixpkgs";
};
}
Then enable the module:
{
imports = [ yt-curator.nixosModules.default ];
services.yt-curator = {
enable = true;
mcpServer.enable = true;
mcpServer.port = 39401;
credentials.clientSecretPath = config.sops.secrets."yt-curator/client_secret".path;
};
}
Or use the flake directly:
nix run github:telos-systems/yt-curator -- inventory
nix run github:telos-systems/yt-curator#mcp -- serve-mcp
yt-curator/
├── src/yt_curator/
│ ├── __init__.py # Package entry
│ ├── cli/app.py # Click CLI (11 commands)
│ ├── mcp/server.py # FastMCP server (12 tools)
│ ├── core/
│ │ ├── auth.py # OAuth 2.0 + token storage
│ │ ├── client.py # YouTube API client wrapper
│ │ ├── inventory.py # Full scan → SQLite
│ │ ├── curator.py # Merge, delete, dedup operations
│ │ ├── dedup.py # Cross-playlist dedup + suggestions
│ │ └── __init__.py # Data models (dataclasses)
│ └── db/schema.py # SQLite schema
├── nix/module.nix # NixOS module
├── flake.nix # Nix flake
├── pyproject.toml # Python project metadata
├── LICENSE # MIT
└── README.md
YouTube's web UI has no bulk operations. If you have 900+ playlists accumulated over 20 years, there's no way to:
Existing MCP servers for YouTube are read-only analytics tools or basic CRUD wrappers. None do inventory, dedup, merge, or bulk curation. This fills that gap.
MIT © 2026 Telos Systems / Danny Poulson
Run analytics queries on ClickHouse — explore schemas, execute SQL, fetch results
Run Claude Code as an MCP server so any agent can delegate coding tasks to it
Browser automation using accessibility snapshots instead of screenshots
Google's universal MCP server supporting PostgreSQL, MySQL, MongoDB, Redis, and 10+ databases