Skip to main content
Glama
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.