Files
mission-control-v2/mcp/mcp_orchestrator.py
T
HitonabiandClaude Opus 5.5 12cefb427a Welle 3 · Lucys Freiheiten je Aktionsart, Rückfragen mit „ja 7“, Lucy untersucht rote Hinweise, Wochenbericht
- services/lucy_autonomie.py: Stufe je Aktionsart (nur lesen, erst fragen, selbst handeln), Start „mehr Freiheit“;
  Meldung danach (POST /api/lucy/gehandelt)
- services/rueckfragen.py: nummerierte Rückfragen, nur Knöpfe der Oberfläche (ERLAUBT), „ja“ führt genau die
  gespeicherte Aktion aus, 24 h gültig, hinfällig wenn der Hinweis weg ist, Nachprüfung danach
- notify.sh -k: Antworttasten (Antworttastatur über den Direktweg, ohne Eingriff in Hermes)
- services/ermittlung.py: Wächter meldet rote Hinweise an Lucy; Knopf wird Rückfrage, Lucy sieht über den
  api_server nach und schickt Ursache und Weg als eine Nachricht
- services/wochenbericht.py + mc2-wochenbericht.timer (So 07:30): feste Sätze, Absatz vom Modell, offene
  App-Updates als Rückfragen
- MCP: Werkzeuge fragen die Freiheiten (auf_bitte), neu: freiheiten, rueckfragen, rueckfrage_beantworten,
  sicherheitsupdates_einspielen, snapshot_zurueckspielen, snapshots, geraet_logs, dienst_logs
- Ausführer-Aktion journal (nur lesend), POST /api/homelab/ziele/{id}/sicherheitsupdates
- Läufe des Homelabs mit flock (Oberfläche und Steward schreiben beide)
- Skill homelab-orchestrator, SOUL-Abschnitt als Kopie in deploy/nur-box

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 19:12:50 +02:00

137 lines
4.6 KiB
Python

#!/usr/bin/env python3
"""
Homelab Orchestrator — MCP-Server für Lucy (Hermes), seit 25.09.2026.
Stdio-MCP-Server, von Hermes Gateway als Unterprozess gestartet (auf der KI-Box, mit dem venv von MC2). Gibt Lucy die
Knöpfe des Orchestrators: Lage lesen, Protokolle lesen, Updates und Sicherheitsupdates starten, „Alle aktualisieren“,
Dienste neu starten, Snapshots zurückspielen, Kernel aufräumen, Host neu starten, Modell-Radar — und die Rückfragen
an den Commander. Die Logik steht in orchestrator_werkzeuge.py (ohne MCP testbar); alles geht über die REST-API von MC2
mit denselben Leitplanken wie die Knöpfe der Oberfläche.
Handeln: auf ausdrückliche Bitte des Commanders (auf_bitte=true) oder nach Lucys Freiheiten je Aktionsart (seit dem
Abend des 25.09.2026, Einstellungen → Lucy) — selbst mit Meldung danach, als Rückfrage oder gar nicht. Grund und
Stufe jeder Aktion werden protokolliert. FastMCP liest die Beschreibung beim Anmelden, deshalb steht sie in
description= (orchestrator_werkzeuge.BESCHREIBUNG). Neue Werkzeuge sieht Hermes erst nach einem Neustart des Gateways.
Einrichten auf der Box (einmal): hermes mcp add homelab-orchestrator --command <venv>/bin/python --args <dieses Skript>
"""
import orchestrator_werkzeuge as w
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("homelab-orchestrator")
B = w.BESCHREIBUNG
# --- Lesen ----------------------------------------------------------------------------------------------------
@mcp.tool(description=B["lage"])
def lage() -> str:
return w.lage()
@mcp.tool(description=B["updates"])
def updates() -> str:
return w.updates()
@mcp.tool(description=B["speicher"])
def speicher() -> str:
return w.speicher()
@mcp.tool(description=B["protokoll"])
def protokoll(anzahl: int = 15, ziel: str | None = None) -> str:
return w.protokoll(anzahl, ziel)
@mcp.tool(description=B["radar"])
def radar() -> str:
return w.radar()
@mcp.tool(description=B["freiheiten"])
def freiheiten() -> str:
return w.freiheiten()
@mcp.tool(description=B["rueckfragen"])
def rueckfragen() -> str:
return w.rueckfragen()
@mcp.tool(description=B["geraet_logs"])
def geraet_logs(ziel: str, zeilen: int = 80) -> str:
return w.geraet_logs(ziel, zeilen)
@mcp.tool(description=B["dienst_logs"])
def dienst_logs(dienst: str, zeilen: int = 80) -> str:
return w.dienst_logs(dienst, zeilen)
@mcp.tool(description=B["snapshots"])
def snapshots(ziel: str) -> str:
return w.snapshots(ziel)
# --- Handeln --------------------------------------------------------------------------------------------------
@mcp.tool(description=B["update_starten"])
def update_starten(ziel: str, baustein: str, grund: str, auf_bitte: bool = False) -> str:
return w.update_starten(ziel, baustein, grund, auf_bitte)
@mcp.tool(description=B["sicherheitsupdates_einspielen"])
def sicherheitsupdates_einspielen(ziel: str, grund: str, auf_bitte: bool = False) -> str:
return w.sicherheitsupdates_einspielen(ziel, grund, auf_bitte)
@mcp.tool(description=B["alle_aktualisieren"])
def alle_aktualisieren(bereich: str, grund: str, auf_bitte: bool = False) -> str:
return w.alle_aktualisieren(bereich, grund, auf_bitte)
@mcp.tool(description=B["nach_updates_suchen"])
def nach_updates_suchen(grund: str, auf_bitte: bool = False) -> str:
return w.nach_updates_suchen(grund, auf_bitte)
@mcp.tool(description=B["dienst_neustarten"])
def dienst_neustarten(dienst: str, grund: str, auf_bitte: bool = False) -> str:
return w.dienst_neustarten(dienst, grund, auf_bitte)
@mcp.tool(description=B["snapshot_zurueckspielen"])
def snapshot_zurueckspielen(ziel: str, snapshot: str, grund: str, auf_bitte: bool = False) -> str:
return w.snapshot_zurueckspielen(ziel, snapshot, grund, auf_bitte)
@mcp.tool(description=B["kernel_aufraeumen"])
def kernel_aufraeumen(grund: str, auf_bitte: bool = False) -> str:
return w.kernel_aufraeumen(grund, auf_bitte)
@mcp.tool(description=B["host_neustarten"])
def host_neustarten(grund: str, auf_bitte: bool = False) -> str:
return w.host_neustarten(grund, auf_bitte)
@mcp.tool(description=B["radar_testen"])
def radar_testen(kandidat: str, grund: str, auf_bitte: bool = False) -> str:
return w.radar_testen(kandidat, grund, auf_bitte)
@mcp.tool(description=B["radar_suchen"])
def radar_suchen(grund: str, auf_bitte: bool = False) -> str:
return w.radar_suchen(grund, auf_bitte)
@mcp.tool(description=B["rueckfrage_beantworten"])
def rueckfrage_beantworten(antwort: str, nr: int | None = None) -> str:
return w.rueckfrage_beantworten(antwort, nr)
if __name__ == "__main__":
mcp.run()