Feat: Hermes PC-Zugriff via MCP (executor + mcp_pc)

- mcp/mcp_pc.py: MCP-Server der PC-Tools an den Executor proxied
  (pc_shell, pc_screenshot, pc_type, pc_key, pc_open, pc_status)
- client/hermes-pc/executor.py: FastAPI auf Port 7777 (Daemon-Reg entfernt)
- client/hermes-pc/start.bat, install.bat, requirements.txt
- client/hermes-voice/agent_client.py, main.py: agent_client integration

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Hitonabi
2026-06-26 23:32:18 +02:00
parent a64b30c429
commit 483eb0b2fb
7 changed files with 307 additions and 2 deletions
+132
View File
@@ -0,0 +1,132 @@
"""
Hermes PC Executor — läuft auf dem Windows PC.
Empfängt Tool-Befehle vom MCP-Server der AI Box und führt sie lokal aus.
"""
import base64
import io
import os
import socket
import subprocess
import webbrowser
from urllib.parse import quote
import uvicorn
from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI(title="Hermes PC Executor")
app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_methods=["*"], allow_headers=["*"])
MY_PORT = int(os.environ.get("HERMES_PC_PORT", "7777"))
# ── Shell ──────────────────────────────────────────────────────────────────
@app.post("/shell")
async def run_shell(req: dict):
cmd = req.get("command", "")
try:
result = subprocess.run(
["powershell", "-NoProfile", "-NonInteractive", "-Command", cmd],
capture_output=True, text=True, timeout=60,
encoding="utf-8", errors="replace",
)
return {
"stdout": result.stdout.strip(),
"stderr": result.stderr.strip(),
"returncode": result.returncode,
}
except subprocess.TimeoutExpired:
raise HTTPException(408, "Timeout nach 60s")
except Exception as e:
raise HTTPException(500, str(e))
# ── Screen ─────────────────────────────────────────────────────────────────
@app.post("/screenshot")
async def take_screenshot():
try:
import mss
from PIL import Image
with mss.mss() as sct:
monitor = sct.monitors[1]
raw = sct.grab(monitor)
img = Image.frombytes("RGB", raw.size, raw.bgra, "raw", "BGRX")
img.thumbnail((1280, 720))
buf = io.BytesIO()
img.save(buf, format="JPEG", quality=75)
return {"screenshot": base64.b64encode(buf.getvalue()).decode()}
except Exception as e:
raise HTTPException(500, str(e))
# ── Input ──────────────────────────────────────────────────────────────────
@app.post("/type")
async def type_text(req: dict):
text = req.get("text", "")
try:
import pyautogui
pyautogui.write(text, interval=0.03)
return {"ok": True}
except Exception as e:
raise HTTPException(500, str(e))
@app.post("/key")
async def press_keys(req: dict):
keys = req.get("keys", "")
try:
import pyautogui
parts = [k.strip() for k in keys.split("+")]
pyautogui.hotkey(*parts)
return {"ok": True}
except Exception as e:
raise HTTPException(500, str(e))
# ── Apps / Browser ─────────────────────────────────────────────────────────
@app.post("/open")
async def open_target(req: dict):
target = req.get("target", "")
try:
if target.startswith("http://") or target.startswith("https://"):
webbrowser.open(target)
else:
os.startfile(target)
return {"ok": True}
except Exception as e:
raise HTTPException(500, str(e))
@app.post("/search")
async def search_web(req: dict):
query = req.get("query", "")
url = f"https://www.google.com/search?q={quote(query)}"
webbrowser.open(url)
return {"ok": True, "url": url}
# ── Health ─────────────────────────────────────────────────────────────────
@app.get("/health")
async def health():
return {"status": "ok", "host": socket.gethostname()}
def _get_local_ip() -> str:
try:
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
s.connect(("8.8.8.8", 80))
return s.getsockname()[0]
except Exception:
return socket.gethostbyname(socket.gethostname())
if __name__ == "__main__":
my_ip = _get_local_ip()
print(f"Hermes PC Executor läuft auf http://{my_ip}:{MY_PORT}")
uvicorn.run(app, host="0.0.0.0", port=MY_PORT)
+8
View File
@@ -0,0 +1,8 @@
@echo off
cd /d "%~dp0"
echo === Hermes PC Executor Setup ===
python -m venv .venv
.venv\Scripts\pip install -r requirements.txt -q
echo.
echo Fertig. Starte mit start.bat
pause
+6
View File
@@ -0,0 +1,6 @@
fastapi>=0.111.0
uvicorn>=0.30.0
httpx>=0.27.0
mss>=9.0.1
Pillow>=10.0.0
pyautogui>=0.9.54
+9
View File
@@ -0,0 +1,9 @@
@echo off
cd /d "%~dp0"
echo === Hermes PC Executor ===
echo Port: 7777
echo Hermes (AI Box) kann jetzt auf diesen PC zugreifen.
echo Fenster offen lassen solange Hermes PC-Zugriff braucht.
echo.
.venv\Scripts\python executor.py
pause