Skip to main content
Glama
GeniusTechnoMystic

yt-curator-mcp

README.md
# yt-curator 🎬🧹

**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 β”‚                             β”‚
β”‚     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                             β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
```

## Features

- **Full inventory** β€” scan all your playlists and every video in them into a local SQLite database
- **Dead video detection** β€” find deleted, private, and blocked videos across all playlists
- **Cross-playlist deduplication** β€” find every video that appears in 2+ playlists
- **Intra-playlist dedup** β€” remove duplicate copies within a single playlist
- **Merge playlists** β€” move all videos from one playlist into another, then delete the source
- **Bulk delete** β€” remove empty or unwanted playlists
- **Merge suggestions** β€” AI-free title-similarity analysis to find consolidation candidates
- **Privacy audit** β€” see which playlists are public vs private
- **Dry-run everything** β€” all destructive operations preview before executing

## Three Interfaces

### 1. CLI (`yt-curator`)

```bash
# 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
```

### 2. MCP Server (`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):
```json
{
  "mcpServers": {
    "yt-curator": {
      "command": "yt-curator",
      "args": ["serve-mcp"]
    }
  }
}
```

**SSE mode** (register with the mcp-gateway):
```bash
yt-curator serve-mcp --host 0.0.0.0 --port 39401
```

Then add to your gateway config:
```yaml
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 |

### 3. Python Library (`import yt_curator`)

```python
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")
```

## Quota Budget

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).

## Setup

### One-time: Google Cloud + OAuth

1. Go to [Google Cloud Console](https://console.cloud.google.com/)
2. Create a project β†’ Enable **YouTube Data API v3**
3. **APIs & Services β†’ Credentials β†’ Create Credentials β†’ OAuth client ID**
   - Application type: **Desktop app**
   - Download `client_secret.json`
4. Save it to `~/.config/yt-curator/client_secret.json`
5. Run `yt-curator auth` β€” opens a browser for Google login

> **Tip for headless servers**: Run `yt-curator auth` once on a desktop machine
> with a browser, then copy `~/.config/yt-curator/token.json` to the server.

## NixOS Module

Add yt-curator to your flake inputs:

```nix
{
  inputs.yt-curator = {
    url = "github:telos-systems/yt-curator";
    inputs.nixpkgs.follows = "nixpkgs";
  };
}
```

Then enable the module:

```nix
{
  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:

```bash
nix run github:telos-systems/yt-curator -- inventory
nix run github:telos-systems/yt-curator#mcp -- serve-mcp
```

## Project Structure

```
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
```

## Why This Exists

YouTube's web UI has no bulk operations. If you have 900+ playlists accumulated
over 20 years, there's no way to:
- Find which videos are dead across all playlists
- See which videos appear in 10 different playlists
- Merge similar playlists
- Delete 50 empty playlists in one go

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.

## Roadmap

- [x] Core: inventory, dedup, merge, delete, dead video removal
- [x] CLI: 11 commands with --dry-run
- [x] MCP server: 12 tools (stdio + SSE)
- [x] Nix flake + NixOS module
- [ ] AI-assisted reorganisation (local LLM via Ollama)
- [ ] Playlist-as-code (declarative YAML β†’ desired state)
- [ ] GitHub release + PyPI publish
- [ ] Scheduled inventory drift detection (weekly cron)

## License

MIT Β© 2026 Telos Systems / Danny Poulson

TDQS

A3.7/5.0

Scored across 12 tools

Disambiguation4/5

Most tools target distinct resources/actions, but list_playlists and scan_inventory overlap slightly since both return playlist lists; the descriptions clarify that scan_inventory is the primary data-collection command. Overall, boundaries are clear.

Naming Consistency4/5

The set mostly follows a verb_noun pattern (list_*, get_*, find_*, merge_*, delete_*, remove_*). Exceptions like 'curation_report' and 'auth_status' are minor and still readable, so consistency is good but not perfect.

Tool Count5/5

With 12 tools, the server is well-scoped for a playlist curation domain. Each tool earns its place, covering inventory scanning, analysis, and actionable curation without unnecessary bloat.

Completeness4/5

The surface covers the full curation workflow: scan, analyze, merge, delete, and remove dead videos. Minor gaps exist (e.g., no playlist creation/renaming or single-video moves), but these are peripheral to the core purpose.

Maintenance

ActivitySlowing
ResponsivenessNo issues