import os import logging from mcp.server.fastmcp import FastMCP # --- CONFIGURATION LOGGING --- logging.basicConfig(level=logging.INFO) logger = logging.getLogger("ops-gpt-mcp") # --- INITIALISATION --- # On utilise FastMCP pour gérer nativement le transport SSE et les routes /sse /messages mcp = FastMCP("Ops-GPT-Unified-Diagnostics", host="0.0.0.0", port=8080) BASE_DATA_PATH = "/app/data" # --- CATALOGUE D'OUTILS SRE (INTEGRAL) --- @mcp.tool() async def list_services_with_config(hostname: str): """ RECOGNITION: Identifie les middlewares (Nginx, Apache, etc.) avec fichiers de configuration agrégés. Indispensable pour la découverte initiale des composants actifs sur l'hôte. """ try: host_path = os.path.join(BASE_DATA_PATH, hostname) if not os.path.exists(host_path): return f"FATAL_ERROR: Host directory {hostname} not found." services = [f.replace("_conf.txt", "") for f in os.listdir(host_path) if f.endswith("_conf.txt")] return f"STATUS_SUCCESS: Services found: {', '.join(services) if services else 'NONE'}" except Exception as e: return f"SYSTEM_EXCEPTION: {str(e)}" @mcp.tool() async def get_rpm_inventory(hostname: str): """ AUDIT: Récupère l'inventaire complet des paquets RPM et la version du noyau. Utile pour identifier les dérives de configuration OS. """ try: path = os.path.join(BASE_DATA_PATH, hostname, "rpm_inventory.txt") with open(path, "r", encoding='utf-8') as f: return f"--- RPM_INVENTORY | {hostname} ---\n{f.read()}" except FileNotFoundError: return f"DATA_ERROR: rpm_inventory.txt not found for {hostname}." @mcp.tool() async def get_network_sockets(hostname: str): """ NETWORKING: Exécute 'ss -ntulop'. Fournit l'état des sockets et le mapping PID/Processus. """ try: path = os.path.join(BASE_DATA_PATH, hostname, "network_ss.txt") with open(path, "r", encoding='utf-8') as f: return f"--- NETWORK_SOCKETS | {hostname} ---\n{f.read()}" except FileNotFoundError: return f"DATA_ERROR: network_ss.txt not found for {hostname}." @mcp.tool() async def get_system_metrics(hostname: str): """ MONITORING: Récupère les métriques CPU/RAM/IO (VictoriaMetrics) pour l'hôte spécifié. """ try: path = os.path.join(BASE_DATA_PATH, hostname, "metrics_vm.txt") with open(path, "r", encoding='utf-8') as f: return f"--- SYSTEM_METRICS | {hostname} ---\n{f.read()}" except FileNotFoundError: return f"DATA_ERROR: metrics_vm.txt not found for {hostname}." @mcp.tool() async def get_live_config(hostname: str, service_name: str): """ DEEP ANALYSIS: Extrait le contenu brut du fichier [service]_conf.txt agrégé. """ try: target_file = f"{service_name}_conf.txt" path = os.path.join(BASE_DATA_PATH, hostname, target_file) with open(path, "r", encoding='utf-8') as f: return f"--- CONFIG_FILE: {target_file} | {hostname} ---\n{f.read()}" except FileNotFoundError: return f"DATA_ERROR: Config for '{service_name}' not found for {hostname}." # --- LANCEMENT DU SERVEUR --- if __name__ == "__main__": logger.info("Starting Ops-GPT MCP Engine via FastMCP on port 8080") # FastMCP gère lui-même la boucle uvicorn et le transport SSE mcp.run(transport="sse")