import asyncio import os from typing import Optional, List, Dict from contextlib import AsyncExitStack from mcp import ClientSession, StdioServerParameters from mcp.client.stdio import stdio_client from mcp.types import Tool class MCPStdioServer: def __init__( self, name: str, command: str, args: List[str], env: Optional[Dict[str, str]] = None ): self.name = name self.command = command self.args = args self.env = env or os.environ.copy() self.exit_stack = AsyncExitStack() self.session: Optional[ClientSession] = None self.tools: List[Tool] = [] async def start(self): # Configurar el bucle de eventos Proactor en Windows si es necesario if os.name == "nt": asyncio.set_event_loop_policy(asyncio.WindowsProactorEventLoopPolicy()) server_params = StdioServerParameters( command=self.command, args=self.args, env=self.env ) # Iniciar el transporte y establecer la sesión stdio_transport = await self.exit_stack.enter_async_context(stdio_client(server_params)) read, write = stdio_transport self.session = await self.exit_stack.enter_async_context(ClientSession(read, write)) await self.session.initialize() response = await self.session.list_tools() self.tools = response.tools if self.tools: print(f"[{self.name}] Servidor iniciado con herramientas:") for tool in self.tools: nombre = getattr(tool, "name", "[sin nombre]") descripcion = getattr(tool, "description", "[sin descripción]") print(f" - {nombre} - {descripcion}") else: print(f"[{self.name}] Servidor iniciado, pero no se detectaron herramientas.") async def call_tool(self, tool_name: str, arguments: Dict): if not self.session: raise RuntimeError("La sesión no está inicializada.") result = await self.session.call_tool(tool_name, arguments) return result.content def get_tool_names(self) -> List[str]: return [tool.name for tool in self.tools] async def stop(self): await self.exit_stack.aclose() print(f"[{self.name}] Servidor detenido.")