replica-omnisciente/experiments/hermes-launch/skills/client.py

57 lines
2.3 KiB
Python

"""Generic MCP client helper for Aurelio remote SSE servers."""
import os
from contextlib import asynccontextmanager
from typing import Any
from mcp import ClientSession
from mcp.client.sse import sse_client
DEFAULT_ENDPOINTS = {
# Public gabinete gateway (CT 206)
"gabinete": os.getenv("MCP_GABINETE_URL", "https://mcp.portugalfuturista.org/sse"),
# Internal Proxmox services — configure via env or SSH tunnel
"savearth": os.getenv("MCP_SAVEARTH_URL", "http://192.168.0.212:8080/sse"),
"sourcing": os.getenv("MCP_ELECTRICAL_SOURCING_URL", "http://192.168.0.125:8081/sse"),
"eda": os.getenv("MCP_ELECTRICAL_EDA_URL", "http://192.168.0.125:8082/sse"),
"knowledge": os.getenv("MCP_KNOWLEDGE_URL", "http://192.168.0.125:8083/sse"),
"jules": os.getenv("MCP_JULES_URL", "http://192.168.0.227:.../sse"),
"orpheu": os.getenv("MCP_OLHOS_DE_ORPHEU_URL", "https://olhos-de-orpheu.portugalfuturista.org/sse"),
}
@asynccontextmanager
async def mcp_session(server_name: str):
"""Open an MCP client session against a named Aurelio SSE server."""
url = DEFAULT_ENDPOINTS.get(server_name)
if not url:
raise ValueError(f"Unknown MCP server: {server_name}")
async with sse_client(url) as (read, write):
async with ClientSession(read, write) as session:
await session.initialize()
yield session
async def call_tool(server_name: str, tool_name: str, arguments: dict | None = None) -> Any:
"""Call a single tool on a remote MCP server and return the text content."""
async with mcp_session(server_name) as session:
result = await session.call_tool(tool_name, arguments=arguments or {})
# FastMCP returns content as a list of TextContent objects
texts = [item.text for item in result.content if hasattr(item, "text")]
return "\n".join(texts) if texts else str(result.content)
async def list_tools(server_name: str) -> list[dict]:
"""List available tools on a remote MCP server."""
async with mcp_session(server_name) as session:
tools = await session.list_tools()
return [
{
"name": tool.name,
"description": tool.description,
"parameters": tool.inputSchema,
}
for tool in tools.tools
]