Skip to main content
Glama

Web Speed

Web Speed löst das Signal-Rausch-Problem für KI-Agenten. Während das moderne Web für menschliche Augen optimiert ist (unübersichtliches HTML, komplexe Layouts, JS-lastige Oberflächen), übersetzt Web Speed dieses Chaos in eine deterministische, Token-effiziente strukturelle Karte, die für Agenten-Flotten mit hohem Durchsatz konzipiert ist.

Keine KI enthalten. Kein anthropic, kein openai, keinerlei LLM-Abhängigkeit. Die gesamte Interpretation findet im aufrufenden Agenten statt.


Warum es existiert

Problem

Web Speed Lösung

Rohes HTML besteht aus über 150.000 Zeichen an Skripten, Styles und SVG-Rauschen

Entfernt alles Nicht-Strukturelle → bis zu 97 % Token-Reduzierung

LLMs halluzinieren Element-IDs und übersehen Interaktionspunkte im rohen DOM

Gibt eine eingefrorene strukturelle Karte zurück — was da ist, ist da, nichts wird erfunden

Benutzerdefinierte Scraper gehen pro Website kaputt

Deterministisches Protokoll — dieselbe JSON-Struktur für jede Website im Web

Agent muss Seiten einzeln nacheinander neu entdecken

site_map crawlt eine gesamte Domain in einem Aufruf


Related MCP server: Delta-MCP

Tools

Tool

Beschreibung

interpret_page

Vollständige strukturierte Karte: Überschriften, Navigation, Inhaltslinks, Formulare, Tabellen, Text, Metadaten

submit_form

Formular absenden (GET oder POST), Karte der resultierenden Seite zurückerhalten

site_map

Von einer Root-URL aus crawlen, eine kombinierte Karte aller Seiten zurückgeben

inspect_element

Tiefe strukturelle Daten für Knoten, die einem CSS-Selektor entsprechen

page_type

Sofortige Seitenklassifizierung — login, listing, article, form, navigation, other

invalidate_cache

Einen zwischengespeicherten Map-Eintrag löschen, damit der nächste Aufruf frische Daten abruft


Installation

Mac / Linux

cd web-interpreter
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt

Windows

cd web-interpreter
python -m venv venv
venv\Scripts\activate
pip install -r requirements.txt

Ausführen

Für die lokale Entwicklung mit dem MCP-Inspektor:

mcp dev server.py

Um direkt über stdio auszuführen (wie MCP-Clients es starten):

python server.py

Registrierung bei Claude / Cowork

Fügen Sie dies zu ~/Library/Application Support/Claude/claude_desktop_config.json (Mac) oder dem Äquivalent unter Windows hinzu:

{
  "mcpServers": {
    "web-speed": {
      "command": "/absolute/path/to/web-interpreter/venv/bin/python",
      "args": ["/absolute/path/to/web-interpreter/server.py"]
    }
  }
}

Starten Sie dann Claude Desktop / Cowork neu. Die sechs Tools erscheinen unter dem web-speed MCP-Server.


Ausgabeschemata

interpret_page

{
  "url": "https://example.com/",
  "fetched_at": "2025-01-01T12:00:00Z",
  "page_type": "other",
  "title": "Example Domain",
  "description": "",
  "headings": [
    { "level": 1, "text": "Example Domain" }
  ],
  "navigation": [
    { "label": "Home", "url": "https://example.com/", "location": "header" }
  ],
  "content_links": {
    "total": 47,
    "truncated": false,
    "items": [
      { "label": "More information...", "url": "https://www.iana.org/domains/example" }
    ]
  },
  "forms": [
    {
      "id": "search",
      "action": "https://example.com/search",
      "method": "GET",
      "fields": [
        {
          "name": "q",
          "type": "text",
          "label": "Search",
          "placeholder": "Search...",
          "required": false,
          "value": ""
        },
        {
          "name": "_csrf",
          "type": "hidden",
          "label": "",
          "placeholder": "",
          "required": false,
          "value": "abc123"
        }
      ]
    }
  ],
  "tables": [
    {
      "id": "results",
      "headers": ["Name", "Price", "Stock"],
      "rows": [["Widget A", "$9.99", "In stock"]]
    }
  ],
  "text_blocks": [
    { "tag": "p", "text": "This domain is for use in illustrative examples." }
  ],
  "metadata": {
    "lang": "en",
    "canonical": "",
    "open_graph": { "title": "", "description": "", "image": "" }
  }
}

Wichtige Felder:

  • navigation — Links innerhalb semantischer Navigations-, Header- oder Footer-Elemente (Site-Chrome, Menüs). Auf 60 begrenzt.

  • content_links — Links innerhalb des Seitenkörpers (Artikel, Suchergebnisse, Auflistungen). Enthält immer total, damit Sie die tatsächliche Anzahl kennen, auch wenn bei 60 abgeschnitten wird.

  • forms — Jedes Formular mit jedem Feld, CSRF-Token werden wortgetreu im value des versteckten Feldes beibehalten.

  • page_type — Abgeleitet aus der Struktur: Passwortfeld → login, viele Elemente/Links → listing, <article> mit Absätzen → article, Formulare → form, hauptsächlich Links → navigation.


page_type

Leichtgewichtig — gibt nur die Klassifizierung zurück. Sofort verfügbar, wenn die Seite zwischengespeichert ist.

{
  "url": "https://example.com/login",
  "fetched_at": "2025-01-01T12:00:00Z",
  "page_type": "login",
  "title": "Sign In"
}

submit_form

Gleiche Ausgabeform wie interpret_page, für die Seite, auf der der Server nach dem Absenden landet.

{
  "url": "https://example.com/login",
  "method": "POST",
  "fields": {
    "email": "user@example.com",
    "password": "hunter2",
    "_csrf": "abc123"
  }
}

CSRF-Token kommen wortgetreu in fields — übernehmen Sie diese aus den versteckten Feldern im forms-Array des vorherigen interpret_page-Aufrufs.


inspect_element

Tiefe strukturelle Daten für Knoten, die einem CSS-Selektor entsprechen. Auf 25 Elemente begrenzt.

{
  "url": "https://example.com/shop",
  "selector": ".product-card",
  "matched": 48,
  "truncated": true,
  "elements": [
    {
      "tag": "div",
      "id": "product-42",
      "classes": ["product-card", "featured"],
      "text": "Widget Pro $49.99 Add to cart",
      "attributes": { "id": "product-42" },
      "links": [{ "label": "Add to cart", "url": "https://example.com/cart/add/42" }],
      "fields": [],
      "children": [
        { "tag": "h3", "text": "Widget Pro" },
        { "tag": "span", "text": "$49.99" },
        { "tag": "a", "text": "Add to cart", "href": "https://example.com/cart/add/42" }
      ]
    }
  ]
}

Beispiel-Selektoren: #login-form, .product-card, table.results tbody tr, nav a, [data-testid="price"]


site_map

{
  "root_url": "https://example.com",
  "crawled_at": "2025-01-01T12:00:00Z",
  "total_pages": 8,
  "pages": [
    {
      "url": "https://example.com",
      "title": "Home",
      "page_type": "navigation",
      "depth": 0,
      "links_to": ["https://example.com/about", "https://example.com/contact"]
    }
  ],
  "all_forms": [
    {
      "found_on": "https://example.com/contact",
      "id": "contact",
      "action": "https://example.com/contact/submit",
      "method": "POST",
      "fields": [
        { "name": "email", "type": "email", "label": "Your email", "placeholder": "", "required": true, "value": "" },
        { "name": "message", "type": "textarea", "label": "Message", "placeholder": "", "required": true, "value": "" }
      ]
    }
  ],
  "all_navigation": [
    { "label": "About", "url": "https://example.com/about" },
    { "label": "Contact", "url": "https://example.com/contact" }
  ]
}

invalidate_cache

{ "url": "https://example.com", "invalidated": true }

Fehler

Tools lösen niemals Fehler aus. Bei einem Fehler:

{
  "error": true,
  "code": "FETCH_FAILED | PARSE_FAILED | TIMEOUT | NOT_HTML",
  "message": "human-readable explanation",
  "url": "https://example.com/broken"
}

Wie ein Agent die Ausgabe verwenden sollte

Eine Website navigieren: Lesen Sie navigation für das Site-Chrome (Menüs, Header, Footer) und content_links für Links im Seitenkörper. content_links.total verrät Ihnen, wie viele existieren, auch wenn die Liste gekürzt ist. Wählen Sie den Link, der Ihrem Ziel entspricht, und rufen Sie interpret_page auf.

Ein Formular absenden: Lesen Sie forms. Jedes Feld hat name (was gesendet werden soll), type (welche Daten erwartet werden), label/placeholder (wofür es ist), required und value. Versteckte Felder (type: "hidden") enthalten CSRF-Token — übergeben Sie deren value wortgetreu zurück. Erstellen Sie ein flaches name → value-Wörterbuch und rufen Sie submit_form auf.

Klassifizieren vor dem Handeln: Rufen Sie zuerst page_type auf, wenn Sie Logik verzweigen müssen (z. B. ist dies eine Login-Seite oder ein Dashboard?), ohne für ein vollständiges interpret_page zu bezahlen.

In eine Komponente hineinbohren: Sie haben eine Tabelle in der Karte gesehen, möchten aber die einzelnen Zeilen? Eine Produktauflistung, aber Sie möchten den Link und Preis jeder Karte? Rufen Sie inspect_element mit einem CSS-Selektor auf, um strukturierte Details zu diesen spezifischen Knoten zu erhalten, ohne die gesamte Seite neu zu laden.

Einen mehrstufigen Workflow vorplanen: Rufen Sie site_map auf, bevor Sie beginnen. Sie erhalten den Titel, Typ, die Tiefe und ausgehende Links jeder Seite sowie jedes Formular auf der gesamten Website — Sie können den gesamten Workflow planen (Login-Formular finden, Dateneingabeseite finden, Submit-Endpunkt finden), ohne einen einzigen Round-Trip.

page_type ist ein Signal, keine Garantie: Die Klassifizierung ist heuristisch. JS-gerenderte SPAs, die leere HTML-Hüllen ausliefern, werden oft als other eingestuft — das Passwortfeld ist erst im HTML, nachdem JavaScript ausgeführt wurde. Betrachten Sie page_type als schnellen Filter und verifizieren Sie ihn dann anhand der tatsächlichen forms und headings.


Gemeinsame Registry-Synchronisierung

Standardmäßig wird jede neue Seitenkarte, die Ihr OSS-Server erstellt, asynchron an die Web Speed Shared Registry unter api.getwebspeed.io übermittelt. Dies ist das Crowdsourcing-Schwungrad — jeder Agent, der eine URL abruft, fügt sie dem globalen Cache hinzu, sodass der nächste Agent überall eine sofortige Antwort erhält.

Dies ist ein Opt-out, kein Opt-in. Die Standardeinstellung ist aktiviert, da je mehr Mitwirkende es gibt, desto schneller laufen die Agenten aller Beteiligten.

Was geteilt wird

Nur strukturelle Seitendaten:

  • Seitentyp, Titel, Beschreibung

  • Überschriften, Navigationslinks, Inhaltslinks

  • Formularfeldnamen, Typen und Labels (keine Werte)

  • Tabellen, Textblöcke

  • Open Graph Metadaten

Niemals geteilt: Cookies, Session-Token, Formularwerte, JS-gerenderte Karten (die sitzungsspezifische Login-Zustände enthalten könnten).

Synchronisierung deaktivieren

Setzen Sie die Umgebungsvariable, bevor Sie den Server starten:

WEB_SPEED_REGISTRY_SYNC=false python server.py

Oder in Ihrer MCP-Client-Konfiguration:

{
  "mcpServers": {
    "web-speed": {
      "command": "/path/to/venv/bin/python",
      "args": ["/path/to/server.py"],
      "env": {
        "WEB_SPEED_REGISTRY_SYNC": "false"
      }
    }
  }
}

Auf eine selbst gehostete Registry verweisen

Wenn Sie Ihre eigene gehostete Instanz betreiben, verweisen Sie die Synchronisierung dorthin:

WEB_SPEED_REGISTRY_URL=https://your-instance.example.com python server.py

Synchronisierungsverhalten

  • Fire-and-Forget: Der Beitrag wird im Hintergrund gesendet. Die Anfrage Ihres Agenten wird mit voller Geschwindigkeit abgeschlossen, unabhängig davon, ob der Ping erfolgreich ist.

  • Nur bei Cache-MISS: Karten, die bereits in Ihrem lokalen 24-Stunden-Festplatten-Cache vorhanden sind, werden nicht erneut gesendet.

  • Fehler sind lautlos: Netzwerkfehler, Timeouts und Server-Ablehnungen werden nur auf DEBUG-Ebene protokolliert und gelangen niemals zum Agenten.


Architektur

URL  ──▶  fetcher.py         (httpx: 10s timeout, 5 redirects, Chrome UA
                ▼             OR Playwright headless Chromium for js=true)
          cleaner.py         (BeautifulSoup/lxml: strip noise, split nav vs content
                ▼             links, filter layout tables, deduplicate text blocks,
          structured map      infer page_type, detect auth_gated)
                ▼
          cache.py           (24h TTL, MD5 keyed JSON files in ./cache/)
                ▼
          registry_sync.py   (fire-and-forget POST to api.getwebspeed.io/v1/contribute)
                ▼
          server.py          (FastMCP: 8 tools over stdio)

Keine KI. Keine Interpretation. Der Agent ist das Gehirn.


Bekannte Einschränkungen

  • JS-gerenderte SPAs: Seiten, die Inhalte über JavaScript (React, Vue, Angular) laden, geben nur die Pre-Render-HTML-Hülle zurück. Passwortfelder, Suchergebnisse und Navigation, die durch JS injiziert werden, fehlen. Verwenden Sie inspect_element auf dem, was sichtbar ist, und kombinieren Sie es mit einem Browser-Automatisierungstool für SPA-lastige Ziele.

  • page_type Heuristiken: Die Klassifizierung ist strukturell und schnell, aber nicht unfehlbar. Eine Marketingseite mit vielen internen Links könnte als listing eingestuft werden; eine Seite mit einem E-Mail-Feld und ohne Passwort wird nicht als login erkannt.

  • Cache ist lokale Festplatte: Das Verzeichnis ./cache/ ist lokal. In einer Multi-Prozess- oder verteilten Bereitstellung werden Cache-Einträge nicht über Instanzen hinweg geteilt. Für gemeinsames Caching ersetzen Sie cache.py durch ein Redis- oder Memcached-Backend.

  • Ratenbegrenzungen nicht durchgesetzt: Web Speed drosselt keine ausgehenden Anfragen. Für Agenten-Flotten mit hohem Volumen setzen Sie einen Ratenbegrenzungs-Proxy (z. B. Cloudflare, nginx) vor den Server.

Related MCP Connectors

Related MCP Servers