Zero-cost YouTube video search service powered by web scraping
- ✅ No YouTube API key required - completely free
- ✅ RESTful API design with Swagger documentation
- ✅ MCP (Model Context Protocol) support - integrate with AI assistants
- ✅ Redis caching optimization (1 hour TTL)
- ✅ Complete video metadata extraction
- ✅ Sorting and filtering capabilities
- ✅ Docker containerization support
uv syncpython main.pyThe service will start at http://localhost:8000.
Visit http://localhost:8000/docs for interactive API documentation.
curl "http://localhost:8000/api/v1/search?keyword=Python tutorial"curl "http://localhost:8000/api/v1/search?keyword=Python&limit=5"curl "http://localhost:8000/api/v1/search?keyword=Python&sort_by=date&limit=3"Download YouTube videos as MP3 audio files with automatic caching and cleanup.
- ✅ Download YouTube videos as 128kbps MP3 files
- ✅ Support for single and batch downloads
- ✅ Redis-based caching to avoid duplicate downloads
- ✅ Automatic cleanup of expired files (24-hour TTL)
- ✅ Rate limiting: 20 downloads per IP per hour
- ✅ Video duration limit: maximum 10 minutes
- ✅ Direct streaming or download link format
# Get download link
curl -X POST "http://localhost:8000/api/v1/download/audio?video_id=dQw4w9WgXcQ&format=link"
# Response
{
"video_id": "dQw4w9WgXcQ",
"title": "Rick Astley - Never Gonna Give You Up",
"duration": 212,
"download_url": "http://localhost:8000/downloads/dQw4w9WgXcQ_Rick_Astley.mp3",
"cached": false,
"file_size": 3400000
}# Direct MP3 stream - returns binary audio data
curl -X POST "http://localhost:8000/api/v1/download/audio?video_id=dQw4w9WgXcQ&format=stream" -o output.mp3# Download multiple videos at once (max 20)
curl -X POST "http://localhost:8000/api/v1/download/batch" \
-H "Content-Type: application/json" \
-d '{
"video_ids": ["dQw4w9WgXcQ", "jNQXAC9IVRw"]
}'
# Response
{
"total": 2,
"successful": 1,
"failed": 1,
"items": [
{
"video_id": "dQw4w9WgXcQ",
"status": "success",
"download_url": "http://localhost:8000/downloads/...",
"duration": 212,
"cached": false
},
{
"video_id": "jNQXAC9IVRw",
"status": "failed",
"error_message": "Video duration exceeds limit"
}
]
}Set these environment variables to customize download behavior:
# Download storage directory
DOWNLOAD_DIR=/tmp/youtube_audio
# Base URL for serving downloads (used in download links)
DOWNLOAD_BASE_URL=http://localhost:8000/downloads
# Download timeout in seconds
DOWNLOAD_TIMEOUT=300
# Maximum video duration in seconds (default: 600 = 10 minutes)
MAX_VIDEO_DURATION=600
# Audio bitrate in kbps
AUDIO_BITRATE=128
# Cache TTL in hours
CACHE_TTL_HOURS=24
# Rate limit: downloads per IP per hour
RATE_LIMIT_DOWNLOAD_PER_HOUR=20
# Enable rate limiting
RATE_LIMIT_ENABLED=trueThe API returns appropriate HTTP status codes:
400- Invalid video ID or parameters403- Video too long, live stream, or access restricted404- Video not found or deleted503- Download failed or YouTube unavailable507- Server storage full
Expired audio files are automatically deleted after 24 hours. Manual cleanup can be triggered:
# Manual cleanup script
python scripts/cleanup_cron.py
# Schedule with cron (daily at 2 AM)
0 2 * * * /usr/bin/python /path/to/scripts/cleanup_cron.py >> /path/to/logs/cleanup.log 2>&1This service provides MCP server functionality, allowing AI assistants (such as Claude Desktop) to directly invoke YouTube search tools via the MCP protocol.
- HTTP Service: Provided via StreamableHTTPSessionManager, integrated with existing FastAPI application
- Supported Transport Modes: HTTP (MVP)
- Future Iterations: Consider supporting stdio and SSE modes
- REST API Preservation: Existing REST API endpoints (
/api/v1/search, etc.) remain fully functional - Flexible Deployment: Choose between integrated (same FastAPI app) or separate (independent process) deployment
- Backward Compatibility: MCP additions do not modify any existing REST API signatures or behaviors
Add the following to Claude Desktop's configuration file (~/.config/claude/settings.json or %APPDATA%\Claude\settings.json):
{
"servers": {
"youtube-search-mcp": {
"command": "uv",
"args": ["run", "python", "mcp_stdio.py"],
"env": {
"MCP_SEARCH_TIMEOUT": "15",
"MCP_SEARCH_RETRIES": "3",
"PYTHONUNBUFFERED": "1"
}
}
}
}MCP_SEARCH_TIMEOUT(default: 15 seconds): Search operation timeoutMCP_SEARCH_RETRIES(default: 3 times): Retry attempts on search failureREDIS_HOST,REDIS_PORT,REDIS_DB: Redis cache configuration (optional)
# Start MCP server (stdio mode)
python mcp_stdio.py
# Or using uv
uv run python mcp_stdio.pyTool Name: youtube_search
Description: Search YouTube videos and return complete metadata
Parameters:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
keyword |
string | ✅ | - | Search keyword (1-200 characters) |
limit |
integer | ❌ | 1 | Number of results to return (1-100) |
sort_by |
string | ❌ | relevance | Sort order: relevance or date |
Response Format:
{
"videos": [
{
"video_id": "mIF-nn_y2_8",
"title": "Jackie Cheung - Farewell Kiss",
"channel": "Music Without Boundaries",
"url": "https://www.youtube.com/watch?v=mIF-nn_y2_8",
"channel_url": "https://www.youtube.com/@channel_name",
"publish_date": "2020-01-15",
"view_count": "1500000",
"description": "Classic Cantonese song..."
}
],
"message": "Successfully returned 1 result"
}Error Handling:
- Empty keyword: Returns
{"error": "INVALID_KEYWORD", "message": "Search keyword cannot be empty..."} - Invalid limit: Returns
{"error": "INVALID_LIMIT", "message": "limit must be between 1-100..."} - YouTube service unavailable: Returns
{"error": "SERVICE_UNAVAILABLE", "message": "YouTube service is temporarily unavailable..."} - Cache service failure: Gracefully degrades to direct search and returns normal results
Copy .env.example to .env and modify as needed:
cp .env.example .envdocker-compose up -dpytest tests/src/youtube_search/
├── models/ # Pydantic data models
├── services/ # Business logic layer
├── api/ # API routes
└── utils/ # Utility functions
MIT License