From 6a464bf6535ea076a25fb5bf82cbc30bc1d83d4b Mon Sep 17 00:00:00 2001 From: Hitonabi Date: Fri, 26 Jun 2026 23:41:49 +0200 Subject: [PATCH] Feat: Web-Fetch MCP-Server (trafilatura, kein API-Key) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - mcp/mcp_web.py: fetch_url + fetch_urls Tools - Hermes kann jetzt Seiteninhalte lesen ohne externen API-Key - trafilatura für saubere Textextraktion aus HTML Co-Authored-By: Claude Sonnet 4.6 --- mcp/mcp_web.py | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 mcp/mcp_web.py diff --git a/mcp/mcp_web.py b/mcp/mcp_web.py new file mode 100644 index 0000000..c5e317c --- /dev/null +++ b/mcp/mcp_web.py @@ -0,0 +1,78 @@ +#!/usr/bin/env python3 +""" +Mission Control 2.0 — Web Fetch MCP Server. + +Stdio-MCP-Server. Läuft als Subprocess von Hermes Gateway (AI Box). +Fetcht URLs und extrahiert sauberen Text — kein API-Key nötig. +""" + +import httpx +from mcp.server.fastmcp import FastMCP + +mcp = FastMCP("hermes-web-fetch") + +HEADERS = { + "User-Agent": ( + "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 " + "(KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36" + ) +} + + +@mcp.tool() +def fetch_url(url: str, max_chars: int = 8000) -> str: + """Lädt eine URL und extrahiert den Haupttext (Artikel, News, Seiteninhalte). + Nutze dies wenn du den vollen Inhalt einer Webseite lesen willst. + Gibt sauberen Text zurück — kein HTML-Rauschen. + max_chars: maximale Zeichenanzahl des Ergebnisses (default 8000).""" + try: + import trafilatura + + resp = httpx.get(url, headers=HEADERS, timeout=20, follow_redirects=True) + resp.raise_for_status() + + text = trafilatura.extract( + resp.text, + include_comments=False, + include_tables=True, + no_fallback=False, + ) + + if not text: + # Fallback: strip HTML tags manually + import re + text = re.sub(r"<[^>]+>", " ", resp.text) + text = re.sub(r"\s+", " ", text).strip() + + if len(text) > max_chars: + text = text[:max_chars] + f"\n\n[... gekürzt auf {max_chars} Zeichen]" + + return text or "Kein Text extrahierbar." + + except httpx.TimeoutException: + return f"FEHLER: Timeout beim Laden von {url}" + except httpx.HTTPStatusError as e: + return f"FEHLER: HTTP {e.response.status_code} für {url}" + except Exception as e: + return f"FEHLER: {e}" + + +@mcp.tool() +def fetch_urls(urls: list[str], max_chars_each: int = 4000) -> str: + """Lädt mehrere URLs gleichzeitig und gibt die Texte zurück. + Nützlich um mehrere Suchergebnisse auf einmal zu lesen. + urls: Liste von URLs (max 5) + max_chars_each: max Zeichen pro Seite""" + if len(urls) > 5: + urls = urls[:5] + + results = [] + for url in urls: + text = fetch_url(url, max_chars_each) + results.append(f"=== {url} ===\n{text}") + + return "\n\n".join(results) + + +if __name__ == "__main__": + mcp.run()