"""MCP Server for YouTube operations."""
from typing import Any
from .youtube_client import YouTubeClient
from .browser_controller import BrowserController
class YouTubeMCPServer:
"""Model Context Protocol server for YouTube operations."""
def __init__(self, api_key: str) -> None:
"""
Initialize the YouTube MCP server.
Args:
api_key: Google API key for YouTube Data API v3
"""
self.youtube_client = YouTubeClient(api_key)
self.browser_controller = BrowserController()
def get_tools(self) -> list[dict[str, Any]]:
"""
Get available tools for the MCP server.
Returns:
List of tool definitions
"""
return [
{
"name": "search_youtube",
"description": (
"Busca una canción o artista en YouTube. Retorna información sobre título, artista, canal, "
"video_id y URL. IMPORTANTE: Esta herramienta solo busca. Para reproducir, SIEMPRE debes usar "
"la herramienta 'play_youtube' con la URL obtenida. Nunca intentes abrir URLs directamente en "
"PowerShell, terminal o navegador manual; siempre usa play_youtube para garantizar aislamiento "
"e instancia limpia."
),
"inputSchema": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "Nombre de la canción o artista a buscar",
},
"max_results": {
"type": "integer",
"description": "Número máximo de resultados a retornar (1-50, default 5)",
"default": 5,
},
},
"required": ["query"],
},
},
{
"name": "play_youtube",
"description": (
"HERRAMIENTA OBLIGATORIA para reproducir videos de YouTube. Abre la URL en una instancia "
"de navegador COMPLETAMENTE AISLADA con: (1) modo app (sin pestañas ni interfaz estándar), "
"(2) perfil temporal único (sin sesión compartida), (3) sin acceso al navegador del usuario. "
"Soporta URLs simples (watch?v=ID), playlists (watch_videos?video_ids=ID1,ID2,...) y Mix automático "
"(watch?v=ID&list=RDID). NO USES PowerShell, cmd, webbrowser u otros métodos: "
"SIEMPRE usa esta herramienta. Flujo correcto: 1) search_youtube → 2) play_youtube con URL."
),
"inputSchema": {
"type": "object",
"properties": {
"url": {
"type": "string",
"description": (
"URL completa de YouTube. Formatos válidos: "
"(a) Video simple: https://www.youtube.com/watch?v=VIDEO_ID "
"(b) Playlist: https://www.youtube.com/watch_videos?video_ids=ID1,ID2,ID3,... "
"(c) Mix automático: https://www.youtube.com/watch?v=ID&list=RDID&autoplay=1"
),
},
},
"required": ["url"],
},
}
]
def handle_search_youtube(
self, query: str, max_results: int = 5
) -> dict[str, Any]:
"""
Handle the search_youtube tool call.
Args:
query: Song name or artist to search
max_results: Maximum number of results to return
Returns:
Dictionary with search results
"""
try:
results = self.youtube_client.search_song(query, max_results)
response = {
"success": True,
"results": results,
"count": len(results),
}
return response
except Exception as e: # pylint: disable=broad-except
return {
"success": False,
"error": str(e),
}
def handle_play_youtube(self, url: str) -> dict[str, Any]:
"""
Handle the play_youtube tool call.
Args:
url: YouTube URL to play
Returns:
Dictionary with playback status
"""
try:
# Close previous browser window if still open
self.browser_controller._close_previous_browser() # pylint: disable=protected-access
playback_result = self.browser_controller.open_youtube_url(url)
return playback_result
except Exception as e: # pylint: disable=broad-except
return {
"success": False,
"error": str(e),
}