youtube-playlist-mcp
README.md
# youtube-playlist-mcp
A small personal MCP server that lets Claude/Cowork read your YouTube
playlists — specifically "what got added recently" — so it can be wired
into a daily scheduled task that picks a video and books a calendar slot.
It exposes three tools over MCP:
- `list_my_playlists` — your playlists (id, title, item count)
- `list_recent_playlist_items` — most recently *added* videos in a playlist
- `get_new_items_since_last_check` — only videos added since the last time
this was called (this is the one you'll use for the daily automation —
it tracks its own checkpoint per playlist, so it naturally answers
"did anything land in the playlist since this morning's last check?")
Your YouTube credentials never leave this server — Claude only ever sees
the tool outputs (video titles/links/timestamps), never your OAuth tokens.
## 1. Google Cloud setup (one-time, ~5 min)
1. Go to https://console.cloud.google.com/ , create a project (or reuse one).
2. APIs & Services → Library → enable **YouTube Data API v3**.
3. APIs & Services → Credentials → Create Credentials → OAuth client ID.
- Application type: **Desktop app**.
- Note the Client ID and Client Secret.
4. If prompted to configure the OAuth consent screen, choose **External**,
fill in the basics, and add yourself as a test user (no need to publish
the app — test mode is fine for personal use, tokens just need
re-consent every ~7 days unless you request production access, which
for a single-user personal tool isn't necessary — see note below).
> Note on token expiry: apps in "Testing" mode get refresh tokens that
> expire after 7 days. For a server that should run indefinitely, either
> (a) publish the OAuth consent screen, or (b) just re-run
> `get_refresh_token.js` every so often. For (a): Google Cloud Console →
> your project → **Google Auth Platform → Branding** requires an
> Application home page and privacy policy link before the **Publish
> app** button (under Audience) becomes clickable — a one-line static
> page for each is enough, they don't need to be fancy. Publishing did
> **not** trigger a verification review for a single-user app requesting
> only `youtube.readonly` in testing so far — it went straight to "In
> production." After publishing, re-run `get_refresh_token.js` once more
> to mint a fresh token under the new status (a token issued while still
> in Testing may still carry the old expiry).
## 2. Get a refresh token (one-time, run on YOUR machine)
Run this on a computer where you can open a browser and sign into your
own Google account — not inside a shared/cloud sandbox.
```bash
npm install
YT_CLIENT_ID=xxx YT_CLIENT_SECRET=yyy npm run get-token
```
A browser tab opens, you approve read-only YouTube access, and the
refresh token prints to the terminal. Copy it.
## 3. Configure
```bash
cp .env.example .env
```
Fill in `YT_CLIENT_ID`, `YT_CLIENT_SECRET`, `YT_REFRESH_TOKEN` (from
above), make up a long random `MCP_AUTH_TOKEN`, and set
`DEFAULT_PLAYLIST_IDS` to the playlist ID(s) you want checked daily
(the part after `list=` in the playlist's URL). Comma-separate multiple.
## 4. Run it
Locally:
```bash
npm install
npm start
```
Or on your homelab with Docker:
```bash
docker compose up -d --build
```
Either way it listens on `PORT` (default 8787) at `POST /mcp`, and
requires `Authorization: Bearer <MCP_AUTH_TOKEN>` on every request.
**It needs a URL Claude can reach** — if you run it on your Proxmox
homelab, that means either exposing it through a reverse proxy with a
real domain + HTTPS (e.g. Caddy/nginx + your existing DNS, or a Cloudflare
Tunnel) or hosting it on a small cloud box instead. A bare LAN IP won't be
reachable from Claude's cloud side.
## 5. Add it to Claude as a custom connector
In Claude: Customize → Connectors → Add (this used to live under
Settings → Connectors — Anthropic moved it).
- Name: anything, e.g. `YouTube Playlists`
- Remote MCP server URL: `https://your-domain/mcp`
On the next screen, Claude probes the URL and — because it gets a 401
without credentials — will default **Authentication** to "Always
required" (OAuth), tagged "Detected". This server doesn't speak OAuth,
so switch that to **None**, then under **Request headers** click
**Add header**, pick `authorization` from the dropdown, and set the
value to `Bearer <the MCP_AUTH_TOKEN you chose>` (include the word
`Bearer`). Save, then click **Connect** on the connector's page — it
should show your three tools with no further sign-in step.
Once added, the tools are available in your sessions (and to scheduled
tasks / routines you create via `/schedule` or claude.ai/code/routines).
## 6. Wire up the daily automation
Create a scheduled routine (via `/schedule` in Claude Code, or
claude.ai/code/routines) — not a calendar recurrence, this needs to run
logic each morning — that on a weekday-morning cron:
1. Calls `get_new_items_since_last_check` for your playlist(s), with the
YouTube Playlists and Google Calendar connectors attached.
2. If nothing new comes back — stops, does nothing.
3. **Important:** calling `get_new_items_since_last_check` marks every
returned video as "seen" immediately and permanently — there's no way
to re-fetch or defer any of them later. If several videos landed
since the last check (e.g. over a weekend), the prompt needs to
schedule *all* of them in that same run, not just the newest — e.g.
process them oldest-first, finding each one the next free evening
slot (today, then tomorrow, and so on) so nothing gets silently
dropped.
4. For each video, check Google Calendar for a free slot (e.g. 6-8pm),
and create an event titled after the video with its URL in the
description. Consider creating a dedicated secondary calendar (e.g.
"Evening Videos") with its own color, via Calendar's own UI — the
Google Calendar MCP connector can create/color *events* but can't
create a new calendar itself, so that part's a one-time manual step.
Say the word once this server is deployed and reachable, and the
scheduled task prompt can be written and created.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues