Definition
Ein Browser-MCP-Server ist eine Variante eines MCP-Servers, die Tools bereitstellt, die nur im Browser-Kontext Sinn ergeben — Lese-/Schreib-Zugriff auf den DOM, Local-Storage, Geolocation, Clipboard etc. Der LLM-Host kann damit die Seite veraendern, auf der er selbst eingebettet ist, oder andere Browser-spezifische Daten lesen.
Mechanik
Pyground laedt Pyodide in einem WebWorker — Worker haben keinen direkten DOM-Zugriff. Wir bauen daher eine postMessage-Bruecke vom Worker zum Main-Thread:
[runnable-Block]
|
v
WebWorker (Pyodide)
+-- Python: pyground.dom.add_class("h2", "highlight")
| |
| v postMessage({type:'dom:add_class', selector, name})
| |
| v await response
|
Main-Thread:
+-- document.querySelectorAll('h2').forEach(el => el.classList.add('highlight'))
+-- postMessage({type:'dom:result', value: 5})
Aus dem Pyodide-Snippet sind 19 DOM-Tools nutzbar (alle async):
Lesen: read(selector) (Text — bei <input>/<textarea> der .value), html(selector) (innerHTML), attr(selector, name), query_all(selector) (Liste mit text/href/attrs/tag/id), exists(selector)
Schreiben: set_text, set_html, add_class, remove_class, set_style(selector, dict), inject(selector, position, html) (beforebegin/afterbegin/beforeend/afterend), remove
Interaktiv: scroll_to, click, focus
Magic: create_widget(selector, position, code, opts) — fuegt ein neues runnable-Pyodide-Widget direkt in die Seite ein. show_modal(title, code, opts) — oeffnet das gleiche, aber als zentriertes Modal mit Schliessen-Button (genau das, was die Demo unten nutzt). show_fallback_snake_modal(reason) — Hardcoded-Snake im Modal, fuer Faelle wo der LLM-Output nicht parsbar war.
Reset: reset() triggert location.reload() — alle Modifikationen weg.
Hinweis JsProxy:
query_all()liefert ein JS-Array von JS-Objekten zurueck. In den Snippets nutze Attribut-Zugriff (link.text,link.href), nicht Item-Zugriff (link['text']schlaegt fehl mit „JsProxy object is not subscriptable"). Wenn du echte Python-Dicts willst:link.to_py()pro Eintrag.
Magisches Spiel-Modal — LLM-generiert
Tippe einen Spielnamen in das Feld unten, klicke Spiel generieren. Llama-3.1-8B (aus dem MCP-Eintrag, ~5 GB OPFS-Cache) schreibt ein Pygame-aehnliches Snippet, das anschliessend als spielbares Mini-Widget in einem Modal-Fenster ueber dem Content erscheint — der Agent ruft das Tool show_game(name, code) auf, das intern dom.show_modal(...) triggert.
Das ist die magische Verbindung: das LLM erzeugt nicht nur Text, sondern eine Aktion — die Seite veraendert sich live, das Ergebnis ist sofort spielbar, und mit dem ×-Button (oder ESC) ist es genauso schnell wieder weg.
Tipp: Was funktioniert zuverlaessig? Llama-3.1-8B kennt snake, pong, breakout und einfache bouncing ball-Variationen. Komplexere Spiele wie tetris oder pacman klappen mal, mal nicht — dann springt der Fallback-Snake ein.
Sicherheitsmodell
Aktuell loose: jeder Selector ist erlaubt, Schreibzugriff auf das ganze document. Das ist bewusst Tueftler-Default — Pyground ist kein Security-Sandbox-Tool, der User entscheidet ob er Snippets vertraut. Wenn der gleiche Mechanismus in produktiven Apps deployt werden soll, sind drei Stufen denkbar:
- Loose (was wir haben): voller
document-Zugriff. Maximal magisch. - Strict-Sandbox: Schreibzugriff nur in einer
<div data-mcp-sandbox>-Container, Lesen ueberall. - Hybrid: Lesen frei, Schreiben erfordert explizites
dom.enable_writes()als User-Gesture.
In Cloud-LLM-Hosts wie Claude oder GPT mit Browser-Tool-Use ist das Sandboxing typischerweise strikter — der LLM sieht eine isolierte Page-Capture, nicht die Live-DOM des Hosts.
In der Praxis
Browser-MCP-Server in der freien Wildbahn:
- Anthropic Browser-Tool: Claude kann Webseiten via Headless-Browser-Sandbox ansteuern, mit Screenshots + Element-Tree als Input
- OpenAI Operator: aehnlicher Ansatz, mit eigenem virtuellen Browser
- browser-use (Open-Source): Library, die einen Playwright-Browser an einen LLM koppelt
- Pyground.dom (was du gerade siehst): Pyodide-Pyground-spezifisch, aber das gleiche Pattern auf Browser-Worker-Bridge runtergebrochen
Die DOM-Bridge-Architektur ist nicht spezifisch fuer pyground — jeder Pyodide-im-Browser-Stack kann das nachbauen. Was pyground hier zeigt: dass die Komponenten (Pyodide + WebLLM + DOM-Bridge) ohne Cloud-Backend kombinierbar sind.