Skip to main content
Glama
README.md
# tldw-mcp — *Too Long; Didn't Watch*

An MCP server that turns any YouTube video into a clean **Markdown transcript** (plus
metadata), ready for an AI to summarize and discuss. No more sitting through a 1-hour
video to find out if it was worth it — fetch the transcript, let your AI summarize it,
then chat about it.

Built with **[FastMCP](https://github.com/jlowin/fastmcp)** (Python), served over
**Streamable HTTP**, and exposed remotely through a **Cloudflare Tunnel** so you can use
it from ChatGPT, Claude, your phone, or anywhere.

## Tools

| Tool | Input | Output |
|------|-------|--------|
| `get_transcript` | `url`, `lang?`, `include_timestamps?` | Markdown: frontmatter (title, channel, duration, date…) + transcript |
| `get_video_info` | `url` | Markdown: metadata + description (no transcript) |

- `lang` — preferred caption language (`en`, `fr`, …). If omitted: manual subs first, then
  the video's original language, then English.
- `include_timestamps` — prefix each line with `[mm:ss]`.

No video is ever downloaded — only the caption track (official subtitles preferred,
auto-generated as fallback) via [yt-dlp](https://github.com/yt-dlp/yt-dlp).

## How it works

```
client (ChatGPT / Claude / phone)
   │  HTTPS  https://<host>/<secret-path>/mcp
   ▼
Cloudflare Tunnel  ──►  127.0.0.1:8765 (uvicorn)
                          server.py (FastMCP)
                            └─ yt-dlp ──(proxy)──► YouTube captions
```

**Auth = a secret URL path.** The MCP endpoint is mounted at an unguessable path
(`MCP_PATH`); any other path returns 404. Simple, and works with clients that can't send
custom headers. The server binds only to `127.0.0.1` — it is never exposed directly.

## Local run

```bash
python3 -m venv .venv
.venv/bin/pip install -r requirements.txt
MCP_PATH=/mcp PORT=8765 .venv/bin/python server.py
```

## Configuration (env vars)

| Var | Default | Purpose |
|-----|---------|---------|
| `MCP_PATH` | `/mcp` | Secret URL path the MCP endpoint is mounted at |
| `PORT` | `8765` | Local port (bind is always `127.0.0.1`) |
| `YTDLP_BIN` | `yt-dlp` | Path to the yt-dlp binary |
| `YTDLP_PROXY` | *(none)* | HTTP proxy for yt-dlp **and** caption download (`http://user:pass@host:port`) |

> **Datacenter IPs are blocked by YouTube** ("Sign in to confirm you're not a bot").
> When deploying on a VPS/cloud server, set `YTDLP_PROXY` to a residential proxy or it
> won't work.

## Deploy on a server (systemd + Cloudflare Tunnel)

1. Copy `server.py` + `requirements.txt` to the server (e.g. `/root/youtube-mcp/`),
   create the venv, install deps.
2. Make sure `yt-dlp` is installed (`/usr/local/bin/yt-dlp`).
3. Install the systemd service (generates a random secret path, restarts on crash/reboot):
   ```bash
   export YTDLP_PROXY='http://user:pass@host:port'   # if your server IP is blocked
   bash deploy-setup.sh
   ```
4. Install cloudflared and connect a tunnel whose **public hostname** points to
   **`http://localhost:8765`** (HTTP, not HTTPS):
   ```bash
   cloudflared service install <YOUR_TUNNEL_TOKEN>
   ```
5. Your MCP URL is `https://<your-hostname>/<secret-path>/mcp`
   (the secret path is printed by `deploy-setup.sh` and stored in `.mcp_path`).

## Connect a client

- **Claude Code:** `claude mcp add --transport http tldw https://<host>/<secret>/mcp`
- **ChatGPT (Plus/Pro):** Settings → Connectors → developer mode → Add MCP server → paste the URL (auth: None).
- **Claude Desktop:** Settings → Connectors → add a custom connector with the URL.

## Test

```bash
MCP_URL="https://<host>/<secret>/mcp" bash test-public.sh
```

## License

MIT