MCP server that gives AI assistants YouTube download capabilities. Also ships with a terminal UI.
Project description
yoink
MCP server that lets AI assistants download YouTube videos.
Give Claude, Cursor, or any MCP-compatible AI the ability to download YouTube videos, playlists, and audio through natural language. Also ships with a terminal UI for humans.
pip install yoink-yt · MCP Setup · Terminal UI · API Reference
What is yoink?
yoink is an MCP (Model Context Protocol) server that gives AI assistants like Claude Desktop, Cursor, Windsurf, and other MCP-compatible tools the ability to download YouTube videos on your behalf.
It also ships with a standalone terminal UI (TUI) for when you want to download videos yourself.
The problem
Every YouTube downloader makes you do the work — find the URL, open a tool, pick a format, wait for it, rename the file, repeat.
The yoink way
Just tell your AI assistant what you want:
"Download the latest 3Blue1Brown video in 720p"
"Grab that playlist as audio-only MP3s"
"Download this lecture with subtitles to my Desktop"
Your AI handles the entire workflow — resolves the URL, picks the format, starts the download, tracks progress. No copy-pasting. No menus. Just ask.
⚡ Quick Start
pip install yoink-yt
|
For AI assistants (MCP server) yoink-mcp
Add to Claude Desktop, Cursor, or any MCP client — your AI gets 7 YouTube tools instantly. |
For humans (terminal UI) yoink
A full terminal UI with progress bars, quality picker, playlist support, and keyboard shortcuts. |
[!TIP] Install ffmpeg for best results — needed to merge video+audio streams and convert to MP3.
brew install ffmpeg # macOS sudo apt install ffmpeg # Ubuntu/Debian
🤖 MCP Setup for AI Assistants
yoink exposes 7 tools via the Model Context Protocol over STDIO, giving any MCP-compatible AI assistant full YouTube download capabilities.
Claude Desktop
Add to your claude_desktop_config.json:
{
"mcpServers": {
"yoink": {
"command": "yoink-mcp"
}
}
}
Restart Claude Desktop. Done — Claude can now download YouTube videos.
Claude Code
Add to your .mcp.json:
{
"mcpServers": {
"yoink": {
"command": "yoink-mcp",
"type": "stdio"
}
}
}
Cursor / Windsurf / Other MCP Clients
Any MCP client that supports STDIO transport works. Point it at yoink-mcp as the command.
Using uv (from source instead of pip)
{
"mcpServers": {
"yoink": {
"command": "uv",
"args": ["--directory", "/path/to/yoink", "run", "yoink-mcp"]
}
}
}
Example prompts for your AI
| What you say | What yoink does |
|---|---|
| "Download this video: [url]" | Downloads in best quality to ~/Downloads |
| "Get the 720p version of [url]" | Fetches formats, picks 720p, downloads |
| "Download this playlist as audio" | Gets playlist info, downloads each as audio |
| "What formats are available for [url]?" | Lists all quality options with file sizes |
| "Cancel the download" | Stops an in-progress download |
| "What's the progress?" | Shows status of all active downloads |
| "Download [url] with subtitles" | Downloads video + subtitle files |
| "Convert [url] to MP3" | Downloads audio and converts to MP3 |
🔌 MCP Tools API Reference
These are the tools your AI assistant gets access to when yoink is configured as an MCP server:
| Tool | Description | Key Parameters |
|---|---|---|
get_video_info |
Fetch video metadata (title, duration, uploader, available formats) | url |
get_playlist_info |
List all videos in a YouTube playlist | url |
get_formats |
List available download qualities with file sizes | url |
start_download |
Start downloading a video, returns a tracking ID | url, format_string, output_dir |
list_downloads |
Get progress of all active and completed downloads | — |
get_download_progress |
Check status of a specific download by ID | download_id |
cancel_download |
Cancel an active download | download_id |
[!NOTE] Duplicate detection is built in — if a download is requested for a URL that's already being downloaded, yoink returns an error instead of starting a duplicate. This means your AI can safely retry without causing double-downloads.
🎬 Terminal UI for Humans
For when you want to download videos yourself. A full-featured TUI powered by Textual.
yoink # default: 3 concurrent downloads
yoink -j 5 # up to 10
|
Keyboard shortcuts
|
Features
|
🛠 Architecture
src/yoink/
├── core/ # Shared engine (used by both MCP + TUI)
│ ├── models.py # Pydantic data models
│ ├── errors.py # yt-dlp error → friendly message translation
│ ├── extractor.py # YouTube metadata extraction via yt-dlp
│ ├── engine.py # Single download executor with progress hooks
│ └── manager.py # Concurrent download orchestration + duplicate detection
├── mcp_server/ # MCP interface for AI assistants
│ └── server.py # FastMCP server with 7 tools over STDIO
└── tui/ # Terminal UI for humans
├── app.py # Main Textual application
├── screens/ # Main screen, format picker modal
├── widgets/ # URL bar, video panel, playlist panel, download queue
└── styles/ # Textual CSS styling
Both the MCP server and TUI are thin wrappers around the same core engine. The core handles all yt-dlp interaction, threading, progress tracking, and error handling.
Design decisions
- Threading model: yt-dlp is synchronous, so each download runs in its own thread via
ThreadPoolExecutor. A FIFO dispatcher thread ensures downloads start in submission order. - Progress reporting: Hooks are rate-limited to 100ms intervals to avoid callback floods in both MCP and TUI contexts.
- Playlist optimization: Uses
extract_flatto avoid fetching full metadata for large playlists upfront. - Error handling: Raw yt-dlp errors are pattern-matched against 15 common cases and translated to user-friendly messages.
- Duplicate detection: The download manager tracks active URLs and rejects duplicates at the engine level, with a
forcebypass for retries. - Cancellation: Uses
threading.Eventchecked in every progress hook callback for responsive cancellation. - Data contracts: Pydantic models are shared across core, TUI, and MCP layers for type safety.
🔧 Development
git clone https://github.com/JayshKhan/yoink.git
cd yoink
uv sync --extra dev # install with test deps
uv run pytest tests/ -v # 84 tests
uv run yoink # test the TUI
uv run yoink-mcp # test the MCP server
Frequently Asked Questions
What AI assistants work with yoink?
Any AI assistant that supports the Model Context Protocol (MCP) over STDIO transport. This includes Claude Desktop, Claude Code, Cursor, Windsurf, and any custom MCP client.
Does it only work with YouTube?
yoink uses yt-dlp under the hood, which supports thousands of sites. However, yoink is optimized and tested for YouTube. Other sites may work but are not officially supported.
Can I use the MCP server and TUI at the same time?
They are separate processes with separate download managers, so yes. They won't share state or conflict with each other.
Where do downloads go?
By default, ~/Downloads. The MCP start_download tool accepts an output_dir parameter, and the TUI has an editable path below the URL bar.
What if ffmpeg is not installed?
You can still download videos, but some quality options that require merging separate video and audio streams won't work. MP3 conversion also requires ffmpeg.
📄 License
MIT — do whatever you want with it. Yoink responsibly.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file yoink_yt-0.1.2.tar.gz.
File metadata
- Download URL: yoink_yt-0.1.2.tar.gz
- Upload date:
- Size: 459.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d225448e9321e24f6bec57cf420904ea5ea4838ebd60c3afbcd3bef0f02ec076
|
|
| MD5 |
66183dde083e1c874a3cc5cd10c79806
|
|
| BLAKE2b-256 |
ff3bc775a542ae65674a031db2e291e68bdd60044842f325cd3de751376c512d
|
Provenance
The following attestation bundles were made for yoink_yt-0.1.2.tar.gz:
Publisher:
publish.yml on JayshKhan/yoink
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
yoink_yt-0.1.2.tar.gz -
Subject digest:
d225448e9321e24f6bec57cf420904ea5ea4838ebd60c3afbcd3bef0f02ec076 - Sigstore transparency entry: 1006404109
- Sigstore integration time:
-
Permalink:
JayshKhan/yoink@f5b78c00431f8459eee5641a77ced8756de4644b -
Branch / Tag:
refs/tags/v0.1.2 - Owner: https://github.com/JayshKhan
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@f5b78c00431f8459eee5641a77ced8756de4644b -
Trigger Event:
push
-
Statement type:
File details
Details for the file yoink_yt-0.1.2-py3-none-any.whl.
File metadata
- Download URL: yoink_yt-0.1.2-py3-none-any.whl
- Upload date:
- Size: 405.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5c665b2a3ba5ddeda5c13cc1d858e3b1420a9a3a9c606dfb3d58a686244f9a7b
|
|
| MD5 |
4ea9db4169c05429531d9af5b04e6a50
|
|
| BLAKE2b-256 |
ed583d26f0d077a4bd2b4795491f6958ad1d359168e17649e3ab10733d95299b
|
Provenance
The following attestation bundles were made for yoink_yt-0.1.2-py3-none-any.whl:
Publisher:
publish.yml on JayshKhan/yoink
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
yoink_yt-0.1.2-py3-none-any.whl -
Subject digest:
5c665b2a3ba5ddeda5c13cc1d858e3b1420a9a3a9c606dfb3d58a686244f9a7b - Sigstore transparency entry: 1006404111
- Sigstore integration time:
-
Permalink:
JayshKhan/yoink@f5b78c00431f8459eee5641a77ced8756de4644b -
Branch / Tag:
refs/tags/v0.1.2 - Owner: https://github.com/JayshKhan
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@f5b78c00431f8459eee5641a77ced8756de4644b -
Trigger Event:
push
-
Statement type: