# server_runner.py import subprocess import asyncio import socket import re from pathlib import Path async def wait_for_port(host: str, port: int, timeout: float = 10.0): for _ in range(int(timeout * 10)): try: with socket.create_connection((host, port), timeout=0.5): return True except (OSError, ConnectionRefusedError): await asyncio.sleep(0.1) raise TimeoutError(f"No se pudo conectar al servidor en {host}:{port}") class MCPServerRunner: def __init__(self, server_script_path: str, python_path: str = "python"): self.server_script_path = server_script_path self.python_path = python_path self.port: int = self._extraer_puerto() self.process: subprocess.Popen | None = None def _extraer_puerto(self) -> int: contenido = Path(self.server_script_path).read_text(encoding="utf-8") coincidencias = re.findall(r"port\s*=\s*(\d+)", contenido) if not coincidencias: raise ValueError(f"No se pudo detectar el puerto en {self.server_script_path}") return int(coincidencias[0]) async def start(self): if self.process is None or self.process.poll() is not None: self.process = subprocess.Popen( [self.python_path, self.server_script_path], stdout=subprocess.PIPE, stderr=subprocess.PIPE ) await wait_for_port("127.0.0.1", self.port) print(f"🟢 Servidor MCP iniciado en puerto {self.port}") async def stop(self): if self.process and self.process.poll() is None: self.process.terminate() try: self.process.wait(timeout=5) except subprocess.TimeoutExpired: self.process.kill() print("🔴 Servidor MCP detenido")