daedalus
Daedalus
Fernsteuerung des Browsers über eine Chrome-Erweiterung. Eval-Brücke + dauerhafte Hotfixes + Steuerung pro Tab + Screenshots, CDP, Cookies, Netzwerkerfassung auf Seiten, auf denen Chrome die Erweiterung ausführt.
Installation
Bevor Sie installieren, sollten Sie Folgendes wissen: Normales Eval verwendet eine werbefreie MAIN-World-Injektion. Wenn eine quellenfreie CSP-Prüfung nicht feststellen kann, dass dynamische Kompilierung verfügbar ist, versucht Daedalus den CDP-Fallback; ein erfolgreicher Anschluss zeigt das Banner „Daedalus hat das Debugging dieses Browsers gestartet“ von Chrome, während dieser Fallback läuft. Eine aufrechterhaltene CDP-Sitzung oder Netzwerkerfassung kann die Verbindung länger halten. Das Banner kennzeichnet eine Debugger-Verbindung, keine Garantie für die Integrität von Werten.
Laden Sie die entpackte Erweiterung (extension/) in Chrome:
Besuchen Sie
chrome://extensionsAktivieren Sie den Entwicklermodus
Klicken Sie auf Entpackte Erweiterung laden und wählen Sie
extension/aus
Bei der ersten Installation wird automatisch ein eindeutiges Token generiert und in chrome.storage.local gespeichert. Sie können es auf der Optionsseite der Erweiterung anzeigen/ändern (Puzzle-Symbol → Daedalus → Optionen).
Für paralleles Scraping über mehrere Tabs deaktivieren Sie die Drosselung von Hintergrund-Tabs in Chrome:
chrome --disable-background-timer-throttling --disable-backgrounding-occluded-windows --disable-renderer-backgroundingDie Brücke selbst (server.py) verwendet nur die Standardbibliothek und benötigt keine Installation. Die CLI und der In-Process-MCP-Endpunkt sind das Python-Paket in diesem Repository:
pip install . # the `daedalus` CLI
pip install ".[mcp]" # ... and the MCP endpoint's dependenciesOhne das mcp-Extra startet die Brücke trotzdem und bedient alles andere; sie meldet den fehlgeschlagenen MCP-Bootstrap beim Start und /mcp wird nicht bereitgestellt.
Related MCP server: Real Browser MCP
So funktioniert es
Token: Wird bei der Installation einmalig über
crypto.randomUUID()generiert und inchrome.storage.localgespeichertTab-IDs: Die native
tabs-API von Chrome – jeder Tab wird durch seine Chrome-tabIdidentifiziert, die bei Erstellung/Aktualisierung mit einem 30-Sekunden-chrome.alarms-Herzschlag registriert wirdEin einzelner SSE-Stream:
background.jsöffnet eine einzige persistentefetch-SSE-Verbindung (tab=extension) und leitet eingehende Befehle an den richtigen Tab weiterSeitenbrücke:
content.js(ISOLATED-Welt) leitetwindow.GM-Nachrichten zwischen Hintergrund undpage.js(MAIN-Welt) weiter. Eval verwendet zuerst die MAIN-World-Injektion vonchrome.scripting. Eine quellenfreie Prüfung der dynamischen Kompilierung leitet CSP-blockierte Seiten an CDP weiter; ein Fehler beim Anschluss dort erreicht die Seiten-Relay. Jeder Kanal wird mit der Semantik der MAIN-Welt der Seite ausgeführt.Hotfixes: Werden im erweiterungsweiten
chrome.storage.local-Schlüsseldaedalus-hotfixesgespeichert (nicht pro Token), vom Hintergrund bei jedem berechtigten Top-Level-Seitenaufruf erneut abgespielt – MAIN-World-Injektion oder CDP, wenn die Seiten-CSP dynamische Kompilierung verbietet – und für nicht dauerhafte Fixes versionsabhängig. Das Drehen des Tokens isoliert oder löscht diesen Speicher nicht.
Befehle senden
Daedalus stellt seine Erweiterungsbefehlsfläche als MCP-Server unter <your-bridge>/mcp bereit (streamable-HTTP-Transport). Vor dem Senden einer Anfrage muss der Bearer-Wert exakt mit dem Brücken-Token übereinstimmen, das über den vorhandenen Konfigurationspfad der CLI aufgelöst wird: TOKEN überschreibt DAEDALUS_TOKEN, einschließlich eines optionalen _settings-Anbieters. Ohne konfiguriertes Token schlägt die MCP-Oberfläche mit 401 fehl. Der Endpunkt existiert nur, wenn das mcp-Extra installiert ist (siehe „Installation“ oben). Fügen Sie es zu Claude Code (oder einem beliebigen MCP-Client) hinzu mit:
{
"mcpServers": {
"daedalus": {
"url": "https://daedalus.example.com/mcp",
"headers": { "Authorization": "Bearer <your-bridge-token>" }
}
}
}Das Brücken-Token ist dasjenige, das die Erweiterung bei der Installation generiert – sichtbar auf der Optionsseite der Erweiterung (Puzzle-Symbol → Daedalus → Optionen).
Dieses Beispiel stellt den MCP-Server hinter einem öffentlichen Hostnamen bereit, aber die Standard-Hosts des Transports sind nur Loopback (127.0.0.1:*,localhost:*): Nennen Sie den öffentlichen Hostnamen in DAEDALUS_MCP_ALLOWED_HOSTS, sonst werden die Proxy-Anfragen abgelehnt. Siehe „Server“ unten für alle drei MCP-Einstellungen.
40 Tools in 7 Gruppen – Tabs, Eval/Debug, Medien, Cookies, CSS/Blockierung, Hotfixes, Netzwerk/CDP. Siehe <mcp>-Abschnitt in CLAUDE.md für die vollständige Liste, oder rufen Sie tools/list auf dem MCP-Endpunkt auf.
Manuelles Verifizierungshilfsprogramm (kein MCP-Client erforderlich):
TOKEN=<tok> python3 scripts/mcp_probe.py list
TOKEN=<tok> python3 scripts/mcp_probe.py call title '{"tab_id":"<tabId>"}'
TOKEN=<tok> python3 scripts/mcp_probe.py call screenshot '{"include_image":true}'CLI
Eine Shell-CLI wird als daedalus-cli-Wheel in diesem Repository ausgeliefert (daedalus_cli/), installiert als Befehl daedalus. Sie liest DAEDALUS_URL und DAEDALUS_TOKEN aus der Umgebung, mit TOKEN als einmaliger Überschreibung und ID=<tabId> für die gezielte Auswahl pro Tab (weglassen für Broadcast):
DAEDALUS_TOKEN=<tok> daedalus tabs
DAEDALUS_TOKEN=<tok> ID=<tabId> daedalus title
DAEDALUS_TOKEN=<tok> daedalus exec myid 'document.title'daedalus --help listet jeden Unterbefehl auf, und jeder hat sein eigenes --help. Der exec-Code, den Sie senden, ist ein Ausdruck oder ein Funktionskörper, dessen Rückgabewert als Ergebnis zurückkommt – siehe „Befehle senden“ oben für den Vertrag.
Eine optionale Import-Schnittstelle ist ebenfalls verfügbar: Wenn ein Modul namens _settings auf sys.path importierbar ist, verwendet die CLI dessen Funktionen setting(name, default) und required(name) für DAEDALUS_URL und DAEDALUS_TOKEN anstelle des eingebauten Umgebungs-Fallbacks. Die Umgebungsvariable TOKEN bleibt die einmalige Token-Überschreibung und hat Vorrang; ohne _settings verwendet DAEDALUS_URL seinen Standardwert und DAEDALUS_TOKEN ist erforderlich. ID bleibt die Umgebungsvariable für die gezielte Auswahl pro Tab.
Oder veröffentlichen Sie atomar eine rohe Befehlsdatei (kein MCP, keine CLI). Direkte Umleitung auf den endgültigen .json-Namen wird nicht unterstützt, da der Stream eine Datei beobachten kann, bevor der Schreiber fertig ist. Schreiben Sie einen Geschwisternamen, der auf .tmp endet, und benennen Sie ihn dann im selben Verzeichnis um:
# Broadcast to all tabs
commands_dir="$DAEDALUS_DIR/commands"
final="$commands_dir/<token>.json"
tmp="$(mktemp "$commands_dir/.<token>.XXXXXX.tmp")"
printf '%s\n' '{"id":"test1","code":"document.title"}' > "$tmp" &&
mv "$tmp" "$final"
# Target a specific tab
final="$commands_dir/<token>_<tabId>.json"
tmp="$(mktemp "$commands_dir/.<token>_<tabId>.XXXXXX.tmp")"
printf '%s\n' '{"id":"test1","code":"document.title"}' > "$tmp" &&
mv "$tmp" "$final"Der Leser ignoriert Geschwisternamen mit .tmp. Wenn ein älterer Schreiber fehlerhaftes JSON unter dem endgültigen Namen hinterlässt, lässt der Leser es unberührt und versucht es erneut, anstatt eine möglicherweise laufende Schreiboperation zu löschen. Nach der atomaren Umbenennung liefert der SSE-Stream den Befehl und verbraucht ihn. Das Ergebnis landet in $DAEDALUS_DIR/results/<token>_<tabId>.json (pro Tab) und $DAEDALUS_DIR/results/<token>.json (letzter Schreiber gewinnt). page-main-Injektion und Seiten-Relay-Eval-Abschlüsse können ein exec_ms-Feld enthalten – die Ausführungszeit im Seitenkontext in Millisekunden. Eine Seite kann dieses seitenzeitgesteuerte Feld auf beiden Kanälen fälschen oder weglassen. CDP-Abschlüsse enthalten kein exec_ms. Ergebnisse, die mit einer Warteschlangenzustellung verbunden sind, enthalten auch roundtrip_ms – die vollständige vom Server beobachtete Roundtrip-Zeit in Millisekunden, von der Befehls-Einreihung (PUT /command) bis zum Eintreffen des Ergebnisses (POST /result); sie umfasst Wartezeit in der Warteschlange + SSE-Zustellung + Client-Relay + Ausführung + Rückweg, also ist roundtrip_ms − exec_ms eine Annäherung an den Transport-/Warteschlangen-Overhead, wenn beide Felder vorhanden sind. Diese Messungen verwenden unterschiedliche Uhren: exec_ms verwendet performance.now() der Seite, während roundtrip_ms Server-Wanduhr-Millisekunden verwendet, daher ist ihre Differenz eine Annäherung und keine exakte Subtraktion. Ein Legacy-Frame ohne _did hat kein roundtrip_ms.
Asynchrone Unterstützung
Der Standardkanal page-main führt Ausdrücke über das seiten eigene eval und Funktionskörper über das seiten eigene Function aus; ein asynchroner Wrapper stellt await auf oberster Ebene bereit. Vor dem Senden des Quellcodes injiziert der Hintergrund nur eine konstante Function-Sonde. Wenn diese Sonde true zurückgibt, wird die Quellcode-Injektion einmal versucht und jedes Ergebnis ist endgültig: Ein Wert, eine Ausnahme oder ein Injektions-Transportfehler wird gemeldet, ohne den Quellcode auf CDP erneut zu versuchen. Die Seite besitzt Function und kann diesen Routing-Hinweis beeinflussen, aber die Sonde enthält keinen gesendeten Quellcode, sodass die Wahl eines anderen Kanals seine Nebenwirkungen nicht duplizieren kann.
Wenn die quellenfreie Sonde nicht true zurückgibt, meist weil die Seiten-CSP dynamische Kompilierung blockiert, versucht Daedalus CDP. Ein erfolgreicher Anschluss zeigt das Debugger-Banner von Chrome. Runtime.evaluate verwendet den REPL-Modus für await auf oberster Ebene; Quellcode, der return enthält, wird als Funktionskörper behandelt, es sei denn, eine Wrapper-Sonde parst ihn als Ausdruck. Diese Wrapper-Sonde ist eine Parser-Heuristik, keine nicht ausführende Sicherheitsgrenze: Von einem Operator erstellter Quellcode kann sie umgehen und ausgeführt werden. Nachdem die endgültige CDP-Auswertung gesendet wurde, ist jedes Ergebnis endgültig. Nur ein Fehler beim Anschluss oder der Form, bevor der gesendete Quellcode ausgeführt wird, erreicht das Seiten-Relay. Die CDP-Promise-Abwicklung ist auf 10 Sekunden begrenzt, und Ergebnis- und Ausnahmeobjekt-Handles werden freigegeben, auch wenn eine aufrechterhaltene Sitzung oder Erfassung die Debugger-Verbindung beibehält.
JavaScript, das in einer Seite ausgewertet wird, die Sie nicht kontrollieren, gibt einen Wert zurück, den diese Seite wählen kann, unabhängig davon, welcher Kanal ihn ausgeführt hat. Das Feld world zeichnet nur auf, welcher Ausführungskanal den gesendeten Quellcode ausgeführt hat; es ist diagnostische Metadaten für CSP- und Debugger-Verhalten, kein Vertrauenssignal. Seine Eval-Werte sind page-main für gewöhnliche Injektion, cdp für den Inspektor-Fallback und page:<hostname> für das endgültige Relay, wobei <hostname> der location.hostname des Inhalts-Skripts ist. Der Hintergrund fügt das Präfix page: hinzu, sodass ein Relay-Hostname nicht mit cdp oder page-main kollidieren kann; diese Namensraum-Tatsache sagt nichts über den zurückgegebenen Wert aus. Die CLI rendert das Feld als channel=..., das Dashboard tut dasselbe, und MCP exec, put, result und ping bewahren den genauen world-Wert. Keiner weist eine Vertrauensklasse zu.
Die Standard-Injektion und der CDP-Fallback bewahren das klassische Skriptverhalten für die dokumentierten Sloppy-Mode-Fälle: with kompiliert, legacy oktale Literale werden akzeptiert, und eine nicht deklarierte Zuweisung erstellt eine globale Variable. Der CDP-REPL-Modus erlaubt auch wiederholte let- oder const-Deklarationen. CLI- und MCP-Ergebniswartezeiten betragen standardmäßig 15 Sekunden; ein Timeout des Aufrufers bricht keinen bereits in der Seite laufenden Code ab. Das Blob-Relay wartet separat bis zu 10 Sekunden auf Code, der await enthält, und 3 Sekunden sonst, bevor es ein Fallback-Timeout meldet.
Die Relay-Korrelation bleibt beschreibend und begrenzt: Der sendende Tab muss übereinstimmen, eine akzeptierte Nachricht verbraucht die zufällige Relay-ID, und keine Relay-ID wird registriert, bis die quellenfreie Injektionssonde und der CDP-Fallback vor dem Senden abgeschlossen sind. Diese Kontrollen verhindern tabübergreifende oder doppelte Relay-Abschlüsse; sie stellen keine Wertintegrität her.
Es können höchstens 1.000 Seiten-Relay-Einträge aktiv sein. Ein neuer Fallback bei voller Kapazität erhält einen endgültigen Kapazitätsfehler, ohne laufende Arbeit zu verdrängen. Jeder registrierte Eintrag läuft nach 300.000 ms ab und erhält einen endgültigen Timeout-Fehler, wenn kein Abschluss im selben Tab oder ein früherer Sendefehler ihn entfernt.
Dashboard
Eine browserbasierte Steueroberfläche unter <your-bridge>/dashboard, die die gesamte Erweiterungsbefehlsfläche ohne CLI steuert – Live-Tab-Liste, Eval-REPL, Screenshots, Cookies, Hotfixes, Blockregeln, Netzwerkerfassung, CDP, CSS-Injektion, Fetch-Zeiten, Upload-Browser.
Öffnen Sie die URL in einem Tab, den die Erweiterung steuert.
Scrollen Sie zu §12 Einstellungen und fügen Sie das Token von der Optionsseite der Erweiterung ein (Puzzle-Symbol → Daedalus → Optionen). Speichern.
Der SSE-Statuspunkt in der oberen Leiste wird cyan, wenn das Dashboard Live-Ereignisse abonniert hat.
Wird direkt von server.py aus dem dashboard/-Verzeichnis des Repositorys bereitgestellt (Vanilla-JS + ES-Module, kein Build). Live-Updates kommen über den vorhandenen /stream-Endpunkt: server.py stellt Ereignisse in commands/<token>_dashboard/<ts>_<uuid>.json ein, wenn /register einen vorhandenen Tab aktualisiert, und auf den erfolgreichen Pfaden von /sync-tabs, /unregister und /result; /unregister sendet auch, wenn kein Tab vorhanden war. Das Dashboard verbraucht sie als kind:'event'-Frames.
Hinweis: Die Inhalts- und Seiten-Skripte der Erweiterung injizieren in passende Seiten, einschließlich des Dashboard-Tabs. Broadcast-Eval-Befehle (exec -b) werden auch im Dashboard ausgeführt – bevorzugen Sie die gezielte Auswahl pro Tab oder schließen Sie das Dashboard, bevor Sie störenden Code senden.
Selbst-Patch
Hotfixes
Speichern Sie kleine Patches, die bei jedem berechtigten Top-Level-Seitenaufruf erneut abgespielt werden. Über MCP-Tools: store_hotfix, list_hotfixes, clear_hotfix, clear_hotfixes, set_permanent. Beispiel (über das Probe-Skript):
TOKEN=<tok> python3 scripts/mcp_probe.py call store_hotfix '{"fix_id":"my-fix","code":"console.log(\"patched\")"}'
TOKEN=<tok> python3 scripts/mcp_probe.py call store_hotfix '{"fix_id":"always-on","code":"console.log(\"baseline\")","permanent":true}'
TOKEN=<tok> python3 scripts/mcp_probe.py call set_permanent '{"fix_id":"my-fix","permanent":true}'
TOKEN=<tok> python3 scripts/mcp_probe.py call list_hotfixes
TOKEN=<tok> python3 scripts/mcp_probe.py call clear_hotfix '{"fix_id":"my-fix"}'
TOKEN=<tok> python3 scripts/mcp_probe.py call clear_hotfixes
TOKEN=<tok> python3 scripts/mcp_probe.py call clear_hotfixes '{"include_permanent":true}'Hotfixes sind standardmäßig versionsabhängig. Nach einer Änderung der Erweiterungsversion werden beibehaltene nicht dauerhafte Fixes übersprungen, nicht gelöscht; das Speichern eines Fixes aktualisiert den Datensatz auf die aktuelle Version und macht seine beibehaltenen nicht dauerhaften Fixes wieder berechtigt. Markieren Sie einen Fix als dauerhaft (über permanent: true bei store_hotfix oder set_permanent), um ihn über Versionsänderungen hinweg erneut abzuspielen. clear_hotfixes entfernt nicht dauerhafte Fixes und behält dauerhafte standardmäßig; übergeben Sie include_permanent: true, um den gesamten Speicher zu entfernen.
Erweiterungsbefehle
Der Hintergrund-Service-Worker akzeptiert typisierte Befehle (ausgegeben über MCP-Tools oder durch Schreiben von JSON mit "type": "..." in $DAEDALUS_DIR/commands/):
Befehl | Zweck |
| Sichtbaren Tab als PNG erfassen |
| Rohe Chrome-DevTools-Protokoll-Aufrufe ausführen |
| Vollständige Anfrage-/Antwort-Interception über CDP |
| Zugriff auf den Cookie-Bestand |
| Tab-Steuerung |
| CSS-Injektion pro Tab |
| declarativeNetRequest-Blockierung |
| Hotfix-Verwaltung (permanente Fixes überstehen Versionssprünge) |
| Die Erweiterung selbst von der Festplatte neu laden |
| Diagnose-Ringpuffer für Fetch-Relays |
GM Bridge
window.GM (in page.js, MAIN-Welt) bietet diese Tampermonkey-artige Teilmenge:
Methode | Beschreibung |
| Liest einen nicht reservierten String-Schlüssel aus dem erweiterungsweiten |
| Schreibt einen nicht reservierten String-Schlüssel in den erweiterungsweiten Speicher |
| Löscht einen nicht reservierten String-Schlüssel aus dem erweiterungsweiten Speicher |
| Listet nicht reservierte Speicherschlüssel auf |
| Über den Hintergrund weitergeleitete HTTP-Anfrage (CSP-immun) |
| CSS injizieren |
| In die Zwischenablage schreiben |
| Desktop-Benachrichtigung |
| Neuen Tab öffnen |
| Download auslösen |
| Skript-Metadaten |
Cookie-Zugriff ist eine Operator-Fähigkeit, keine Seiten-Fähigkeit: Er läuft über die oben genannten token-authentifizierten Befehle cookies / set-cookie / remove-cookie / clear-cookies und ist bewusst nicht im Seitenkontext verfügbar — page.js läuft in jeder passenden Top-Level-Seite, die sonst Cookies lesen könnte, die ihr eigenes document.cookie nicht sehen kann.
Architektur
Browser (matching tab) Server (your bridge host)
┌────────────────────────────────────────────┐ ┌──────────────────────┐
│ MAIN world │ │ bridge (server.py) │
│ ├─ page-main: default injection channel │ │ /stream?token │
│ └─ page.js: GM + relay channel │ │ watches commands/ │
│ ▲ │ │ │
│ │ window.postMessage │ │ /result writes │
│ content.js (ISOLATED) │ │ results/ │
│ ▲ │ │ │
│ │ chrome.runtime │ │ │
│ background.js (service worker) │ │ │
│ ├─ CDP: CSP fallback channel │ │ │
│ ├─ single SSE stream ◄────────────────────┼───┤ │
│ └─ POST result, fetch ────────────────────┼──►│ │
└────────────────────────────────────────────┘ └──────────────────────┘Ein SSE-Stream: Der Hintergrund öffnet eine einzelne
fetch-SSE-Verbindung (tab=extension) und leitet Befehle überchrome.tabs.sendMessagean den Ziel-Tab weiter. Ein 30-Sekunden-Watchdog erzwingt bei veralteten Streams eine Wiederverbindung.Routing pro Tab: Befehle adressieren eine bestimmte Chrome-
tabIdoder senden an alle Tabs.CSP-Verhalten:
GM.xmlhttpRequestsendet HTTP-Arbeit an denfetchdes Hintergrund-Service-Workers. Eval verwendet normalerweise bannerfreie MAIN-Welt-Injektion. Wenn die quellenfreie Sonde meldet, dass dynamische Kompilierung nicht verfügbar ist, liefert CDP den CSP-Fallback und zeigt Chromes Debugger-Banner, falls es sich anhängt; ein Anhängefehler erreicht das Seiten-/Blob-Relay. Der resultierendeworld-Wert beschreibt diesen Kanal und erhebt keinen Integritätsanspruch.
Server
DAEDALUS_DIR=<data-dir> DAEDALUS_PORT=<port> DAEDALUS_TOKEN=<bridge-token> python3 server.pyStarten Sie die Brücke mit ihren drei Pflichteinstellungen — sie beendet sich beim Start ohne DAEDALUS_DIR oder DAEDALUS_PORT, und jede Brückensteuerungsroute schlägt ohne konfiguriertes Token fehl:
server.py läuft unter dem Supervisor Ihrer Wahl (hier eine systemd-Unit). Stellen Sie einen TLS-terminierenden Reverse-Proxy davor, wenn Sie es über localhost hinaus verfügbar machen; die Brücke selbst spricht einfaches HTTP. Brückensteuerungs- und Speicherrouten vergleichen ihr Token mit einem konfigurierten Geheimnis, das über den CLI-Konfigurationspfad aufgelöst wird: TOKEN ist die einmalige Überschreibung, andernfalls ist DAEDALUS_TOKEN erforderlich (und ein eingebettetes _settings-Modul kann es liefern). Fehlende Konfiguration und Abweichungen schlagen fehl. Nur die seitenorientierten Routen POST /segment und GET /segment-status verwenden stattdessen eine auftragsbezogene Fähigkeit.
Das prozessinterne MCP-Frontend nimmt drei optionale Einstellungen entgegen, die zusammen dokumentiert werden, weil sie einen Listener beschreiben: DAEDALUS_MCP_PORT (Standard 8086) ist der Loopback-Port, an den es bindet; seine Tool-Handler verwenden die tatsächlich gebundene Loopback-URL der Brücke, auch wenn DAEDALUS_PORT=0 ist; DAEDALUS_LOCAL_URL überschreibt diese URL explizit für eine eigenständige MCP-Bereitstellung, die eine anderswo laufende Brücke frontet; und DAEDALUS_MCP_ALLOWED_HOSTS (Standard 127.0.0.1:*,localhost:*) ist die kommagetrennte Host-Allowlist, die sein DNS-Rebinding-Schutz akzeptiert. Wenn Sie also /mcp mit einem öffentlichen Hostnamen fronten, müssen Sie diesen Hostnamen dort angeben.
Endpunkte: GET /stream, GET /tabs, GET /health, GET /dashboard[/<asset>], POST /register, POST /sync-tabs, POST /unregister, POST /poll, POST /result, PUT /command, GET /result, POST/GET/DELETE /upload, GET /screenshot, POST /segment-job, POST /segment + GET /segment-status. POST /segment-job erfordert das konfigurierte Brücken-Token; nur POST /segment und GET /segment-status akzeptieren das auftragsbezogene sig. Siehe CLAUDE.md für Hinweise zu Payloads und Endpunkten.
POST /poll verbraucht und löscht die veraltete Broadcast-Befehlsdatei, falls eine vorhanden ist.
PUT /command stellt in eine FIFO-Verzeichniswarteschlange pro Ziel ein (aufeinanderfolgende Befehle an einen Tab überschreiben sich nicht mehr), stempelt jeden mit einer Zustell-ID (_did), damit die Erweiterung ein erneut zugestelltes Frame deduplizieren kann, und verwirft nach DAEDALUS_CMD_TTL Sekunden (Standard 90) nicht abgeholte Befehle per TTL. Ein Hintergrund-Sammler wendet diese TTL an und entfernt leere Warteschlangenverzeichnisse, auch wenn sich nie ein SSE-Consumer verbindet. GET /health meldet Stream-/Registry-/Letzte-Zustellung-Lebendigkeit, um eine still gestorbene Brücke zu erkennen.
Die Brücke lehnt wiederholte Autoritätsträger ab, anstatt einen Wert auszuwählen: Dazu gehören token in Query-Strings oder JSON-Bodies sowie job / sig auf den Segment-Fähigkeitsrouten, selbst wenn die wiederholten Werte gleich oder leer sind. Der MCP-Transport lehnt ebenfalls wiederholte Authorization-, Mcp-Session-Id-, Host- und Origin-Header sowie wiederholte job-Argumente für die Segment-Tools ab.
Wenn die Erweiterung ein Ergebnis postet, legt der Server die _did des Befehls als deliveryId offen und weist eine neue resultGeneration zu. CLI- und MCP-Warter prüfen zuerst den gemeinsamen Ergebnis-Slot, gleichen sowohl Befehls-ID als auch deliveryId ab und verbrauchen diese Generation dann bedingt mit GET /result?...&consume=1&expected=<resultGeneration>. Wenn ein anderes Ergebnis den Slot zwischen diesen Anfragen ersetzt, lässt der bedingte Verbrauch das neue Ergebnis an Ort und Stelle und meldet, dass es nicht verbraucht wurde. Ein nacktes consume=1 ohne expected bleibt ein destruktiver Kompatibilitätslesevorgang des aktuellen Slots.
GET /stream hält die SSE-Verbindung unbegrenzt offen und beweist Lebendigkeit mit einem Keepalive-Kommentar alle DAEDALUS_STREAM_KEEPALIVE Sekunden (Standard 15), anstatt die Verbindung über einen Timer zu zyklieren; DAEDALUS_STREAM_MAX_AGE (Standard 3600) ist nur eine Obergrenze als letzter Ausweg. Der Schließpfad ist durch tests/test_stream_lifecycle.py festgelegt.
DAEDALUS_MAX_BODY_SIZE (Standard 64 * 1024 * 1024 Bytes, 64 MiB) begrenzt die von den POST-, PUT- und DELETE-Handlern gelesenen Anforderungs-Bodies; ein deklarierter Body, der größer als das Limit ist, erhält 413, und eine Anforderung, die keine Content-Length deklariert, erhält 411, anstatt als leerer Body gelesen zu werden. Erhöhen Sie ihn, wenn Sie größere Segmente oder andere Payloads weiterleiten.
Dateisystemgestützte Aufruferwerte verwenden eine einzige Pfadkomponenten-Richtlinie: Sie lehnt .., C0/C1-Steuer- und Surrogatzeichen, unter Windows ungültige Pfadzeichen und Gerätenamen, nachgestellte Punkte oder Leerzeichen sowie UTF-8-Kodierungen länger als 240 Bytes ab. Brücken-Tokens sind strenger und lehnen auch Punkte und Unterstriche ab. Andere UTF-8-Jobnamen werden akzeptiert, daher müssen Clients sie in Query-Strings URL-kodieren.
POST /segment-job kopiert drei feste Kontingente in jeden neuen Jobdatensatz: DAEDALUS_MAX_SEGMENT_INDEX (Standard 99999), DAEDALUS_MAX_SEGMENTS_PER_JOB (Standard 10000) und DAEDALUS_MAX_SEGMENT_JOB_SIZE (Standard 4 * 1024 * 1024 * 1024 Bytes, 4 GiB). Das Ändern dieser Einstellungen wirkt sich auf später erstellte Jobs aus; ein Job mit gespeicherten Kontingenten verwendet weiterhin seine aufgezeichneten Werte. DAEDALUS_MAX_BODY_SIZE begrenzt auch jede einzelne Segmentanfrage.
Sicherheit
Lesen Sie dies, bevor Sie die Erweiterung installieren.
Es injiziert einen window.GM-Shim in jede passende Top-Level-Seite (<all_urls>, MAIN-Welt), wodurch ein mit put gesendetes Skript Cross-Origin-Anfragen stellen kann. Die Konsequenz ist der Teil, über den man sich im Klaren sein sollte: Jede passende Seite, die Sie besuchen, kann diesen Shim aufrufen, diese Seite kann also über die Berechtigungen der Erweiterung Cross-Origin-Anfragen stellen, genau wie ein Userscript-Manager mit einem Wildcard-@match. Wenn das für Ihr Surfen nicht akzeptabel ist, grenzen Sie die matches in extension/manifest.json auf die Hosts ein, die Sie tatsächlich steuern, und akzeptieren Sie, dass die Brücke dann auf anderen Seiten nichts tut.
Das Brücken-Token und die Server-URL sind über die GM-Speichermethoden der Seite nicht erreichbar. Sie liegen in chrome.storage.local unter dem Präfix daedalus-, und das Relay weigert sich, diesen Namensraum für Seitenskripte zu lesen, zu schreiben oder aufzulisten. Ohne diese Regel könnte jede besuchte Seite Ihr Brücken-Token mit GM.getValue('daedalus-token') lesen oder die Brücke mit GM.setValue('daedalus-server', ...) stillschweigend umleiten. tests/test_repo_contract.py legt die Regel fest.
Hotfix-Quellcode ist bewusst seitenbeobachtbarer Zustand, kein vertraulicher Erweiterungszustand. Der Hintergrund wählt permanente Fixes sowie nicht-permanente Fixes aus, die zur Erweiterungsversion passen, und führt jeden im Seitenkontext über dieselben Kanäle aus, die auch normales eval verwendet — MAIN-Welt-Injektion, wo die Seite dynamische Kompilierung erlaubt, CDP, wo nicht — sodass die Seite den Quellcode, den sie auf beiden Kanälen ausführt, beobachten kann.
Ein MCP-Inhaber kann keine Datei auf dem Server-Host benennen, die der MCP-Prozess lesen soll. Die MCP-Tools put, CSS-Injektion/-Entfernung und Hotfix-Speicher akzeptieren nur Inline-Quellcode. Die lokale CLI behält ihren Dateipfad-Komfort, aber der CLI-Prozess liest die vom Operator ausgewählte Datei und übermittelt ihren Inhalt inline. Das Halten des Brücken-Tokens gewährt daher die dokumentierte Browser- und Erweiterungssteuerungs-Befugnis, einschließlich des Lesens gespeicherter Hotfix-Quellcodes, fügt aber keinen beliebigen Host-Dateisystem-Lesezugriff über diese Tools hinzu.
Bridge-Control- und Speicherrouten erfordern das konfigurierte Bridge-Token; /segment und /segment-status sind die einzige Ausnahme bei den Capabilities. Der Server vergleicht Anfrage-Tokens mit dem aus TOKEN oder DAEDALUS_TOKEN aufgelösten Geheimnis und lehnt Anfragen ab, wenn kein Geheimnis konfiguriert ist. POST /segment-job erfordert dieses Bridge-Token, weil es die auf den Job begrenzte Capability erzeugt; nicht vertrauenswürdiges Seiten-JavaScript verwendet die Capability nur, um diesen Job zu posten und abzufragen. Jeder, der das Bridge-Token besitzt, kann Ihren Browser steuern. Setzen Sie den Bridge-Port nicht über Loopback hinaus ohne einen Reverse-Proxy aus, der TLS beendet, und behandeln Sie das Token als Anmeldedaten.
Eval-Ergebnisse tragen keine Garantie für die Integrität des Werts. JavaScript, das in einer Seite ausgeführt wird, die Sie nicht kontrollieren, gibt einen Wert zurück, den diese Seite wählen kann, unabhängig davon, welcher Kanal es ausgeführt hat. Das Feld world sagt, wie der übermittelte Quellcode ausgeführt wurde, nicht ob man seinem Wert vertrauen kann: page-main ist eine gewöhnliche MAIN-World-Injektion, cdp ist der Inspector-CSP-Fallback und page:<hostname> ist das Relay. Das obligatorische Präfix page: wird außerhalb des Seitenkontexts hinzugefügt, sodass kein Hostname cdp oder page-main erzeugen kann; diese Kollisionsresistenz ist nur beschreibend. Bei page-main können die von der Seite gehaltenen Bindungen eval und Function den übermittelten Quellcode lesen und auch dessen zurückgegebenen Wert beeinflussen.
Die CDP-Kompilierung vermeidet das Auflösen der eval- und Function-Bindungen der Seite, und die Implementierung ruft direkte Handles per Referenz ab, bevor sie serialisiert werden. Diese Transportmechanismen ändern die Vertrauensgrenze nicht: Der übermittelte Quellcode liest weiterhin den von der Seite kontrollierten Zustand und kann jeden Wert, einschließlich eines primitiven, durch die Promise-Mechanik der Seite leiten, bevor CDP ihn erhält. Wenn der übermittelte Quellcode diese von der Seite kontrollierten Pfade verwendet, kann die Seite auch bei cdp den zurückgegebenen Wert wählen.
Das Relay akzeptiert nur den gespeicherten Aufruf, der mit dieser zufälligen ID verknüpft ist, verlangt, dass der Tab des Absenders übereinstimmt, und verbraucht den Eintrag einmal. Das Downgrade gibt weder das Bridge-Token, die Server-URL, die Zustell-ID noch die Ergebnisroute preis, gewährt keine zusätzliche Erweiterungs- oder Browser-Berechtigung und kann keinen Aufruf in einem anderen Tab beeinflussen. Diese Eigenschaften schützen Routing und Browser-Berechtigung; sie machen das Relay-Marker oder seinen zurückgegebenen JavaScript-Wert nicht zu einem Vertrauenssignal.
Bereitstellung
Die Bridge spricht einfaches HTTP auf Loopback. Bridge-Control- und Speicherrouten erfordern das konfigurierte Token und schlagen fehl, wenn es fehlt; nur /segment und /segment-status verwenden die auf den Job begrenzte Capability. Zwei Dinge tut sie bewusst NICHT, weil sie zu dem gehören, was davor sitzt:
TLS und CORS.
server.pysendet keine CORS-Header. Wenn die Bridge Cross-Origin ist, benötigen die seitenbezogenenfetch-Aufrufe des Beispiel-HLS-Relays Zugriff auf sowohlGET /segment-statusals auchPOST /segment; der Proxy muss den Seitenursprung auf beiden Routen erlauben und die Methoden/Header behandeln, die der Preflight des POST erfordert. Wenn der Status-GET blockiert, nicht verfügbar, nicht-2xx oder ungültig ist, behandelt das Beispiel den Job als neu und sendet jedes Segment erneut per POST. Diese Schreibvorgänge ersetzen weiterhin dieselben Dateien pro Index, aber der Lauf verliert seine Fortsetzungs-/Überspringungs-Ersparnisse. Leiten Sie beide Anfragen stattdessen über die GM-Bridge der Erweiterung, wenn die Bereitstellung diese CORS-Richtlinie nicht bieten kann.Bereitstellung gespeicherter Uploads. Das Dashboard verlinkt Downloads unter
/uploads/<path>, aber die Bridge hat keine solche Route. Servieren Sie keine vom Aufrufer gelieferten Upload-Namen und -Bytes direkt auf dem Ursprung des Dashboards, wo ausführbarer Inhalt einen Ursprung mit dem token-tragenden Speicher des Dashboards teilen würde. Lassen Sie diese Links entweder nicht verfügbar oder lassen Sie/uploads/auf einen separaten Nur-Download-Ursprung umleiten, derContent-Disposition: attachmenterzwingt,application/octet-streamverwendet undX-Content-Type-Options: nosniffsendet.GET /upload(Auflistung) undGET /screenshotwerden von der Bridge selbst bedient und benötigen keine Proxy-Hilfe.
Führen Sie sie direkt mit einem konfigurierten Token aus, und beide sind einfach nicht vorhanden – alles andere funktioniert.
Dateien
Datei | Beschreibung |
| MV3-Manifest |
| Service Worker – SSE, Befehlsverteilung, Fetch-Relay, Screenshots, CDP, Cookies, Downloads |
| Nachrichten-Relay zwischen Seite und Hintergrund |
| MAIN-World-Bridge – |
| Token-/Server-Einstellungs-UI |
| Debug-Server (hostet auch den MCP-Daemon-Thread auf 127.0.0.1:8086) |
| MCP-Server – verbindet die Befehlsfläche der Erweiterung über HTTP mit |
| Minimaler MCP-Client-Helfer für manuelle Überprüfung |
| Versionskonsistenzprüfung / -erhöhung über alle Versionsstellen |
| Pre-Commit- und Pre-Push-Versionskonsistenz-Gates |
| Die Shell-CLI, veröffentlicht als |
| Die Browser-Steuerfläche, die |
| Skripte, die über |
| Die Test-Suiten; |
Beispiele
examples/ enthält Skripte, die über put in einer Seite ausgeführt werden sollen. Fünf der sechs demonstrieren einen Teil der Bridge und keine bestimmte Website; das Discord-Beispiel ist bewusst websitespezifisch, weil das Zurückscrollen durch eine virtualisierte Liste eine Technik ist, die man ohne eine echte virtualisierte Liste nicht zeigen kann:
Beispiel | Zeigt |
| Ein dauerhafter MAIN-World-Hotfix bei |
| Das |
| Finden und Zerstören einer Player-Instanz, die nicht aufhört, es erneut zu versuchen |
| Ausfüllen eines React-gesteuerten Eingabefelds, sodass sich Reacts eigener Zustand tatsächlich ändert |
| Zurückscrollen durch eine virtualisierte Nachrichtenliste und Extrahieren derselben |
| Der kleinstmögliche |
Sie erhalten ihre Konfiguration durch __PLACEHOLDER__-Substitution, bevor sie gesendet werden, weil put ein Skript liefert und keine Funktion aufruft und keine Möglichkeit hat, Argumente zu übergeben.
Jedes ist der BODY einer asynchronen Funktion, kein eigenständiges Skript: Die Bridge umschließt, was Sie senden. Deshalb enden die meisten mit einem return auf oberster Ebene, und eines davon – scrape-discord-messages.js – verwendet auch ein await auf oberster Ebene; beides ist gültig, wo diese tatsächlich ausgeführt werden. node --check parst jede Datei im CommonJS-Wrapper, der das return auf oberster Ebene erlaubt, lehnt aber das await auf oberster Ebene ab – also schlägt genau diese eine Datei bei der Syntaxprüfung fehl.
Entwicklung
python3 run_tests.py führt jede Suite aus und gibt eine aggregierte Zeile aus, die benennt, was überprüft wurde: wie viele Suiten liefen, wie viele Tests bestanden und wie viele übersprungen wurden. Eine Suite, in der jeder Test übersprungen wurde, hat nichts überprüft, daher wird sie als OVERALL: INCOMPLETE mit einem Exit-Code ungleich Null gemeldet und nicht als bestanden; die übliche Ursache ist eine fehlende Abhängigkeit, und die Zeile NO COVERAGE darüber benennt die Suite. Die Installation des mcp-Extras (siehe „Install") ist das, was die MCP-Suite benötigt.
Die Versionszeichenfolge befindet sich an mehreren Stellen in der Erweiterung, im Dashboard und im CLI-Paket. python3 scripts/check_versions.py ist die Liste – es benennt jede Stelle und meldet, wie viele es gefunden hat, weshalb dieser Absatz keine Anzahl wiederholt, die beim nächsten Hinzufügen veralten würde. Erhöhen Sie sie gemeinsam, niemals von Hand:
python3 scripts/check_versions.py --set 0.18.0 # rewrite every site
python3 scripts/check_versions.py # verify the working tree.githooks/pre-commit prüft den Index und .githooks/pre-push prüft jeden gepushten Commit, sodass eine halbe Erhöhung nicht landen kann. Jeder Klon muss einmal zustimmen – Git führt Hooks aus einem verfolgten Verzeichnis sonst nicht aus:
git config core.hooksPath .githooksWenn der Browser die Erweiterung aus einem anderen Checkout lädt als dem, das Sie bearbeiten, installieren Sie die Hooks auch dort – und denken Sie daran, dass das Neuladen der Erweiterung die Dateien auf der Browserseite neu liest, nicht auf Ihrer.
This server cannot be deployed
Maintenance
Related MCP Connectors
Hosted real Google Chrome MCP with per-user persistent state. Navigate, click, type, screenshot.
Browser MCP for logged-in tasks. Uses your Chrome — credentials stay local. Zero-token replay.
Access Kernel's cloud-based browsers and app actions via MCP (remote HTTP + OAuth).
Browserless MCP — wraps the Browserless headless-Chromium REST API (browserless.io)
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables MCP clients to drive a real, logged-in Chrome browser for web automation tasks like navigation, clicking, typing, and screenshotting.2 npmMIT
- AlicenseNot gradedqualityDmaintenanceEnables browser automation over MCP using a real Chrome browser with existing profile, supporting real tabs, downloads, cookies, and RPA workflows.104 npmMIT
- FlicenseNot gradedqualityCmaintenanceEnables MCP clients to control real Chrome tabs in existing profiles, supporting navigation, interaction, screenshots, and console/network inspection across multiple Chrome instances.-
- AlicenseBqualityCmaintenanceEnables MCP clients to drive a real Chromium browser for automation, including navigation, JavaScript execution, CDP commands, network capture, and multi-tab control.7GPL 3.0