Skip to main content
Glama
TrueNix

agent-browser

by TrueNix

agent-browser

Ein gehärteter lokaler Browser für KI-Agenten. Null Abhängigkeiten. Treibt das Chrome, das Sie bereits haben, über das DevTools-Protokoll, extrahiert token-effizientes Markdown und wird nicht trivial als Automatisierung erkannt.

Oberfläche

Installation

Verwendung für

MCP-Server

npx -y @truenix/agent-browser mcp

Claude Code, Cursor, Codex, jeder MCP-Client

CLI

npx -y @truenix/agent-browser markdown <url>

Shells, Skripte, CI

Bibliothek

import { withBrowser } from '@truenix/agent-browser'

Ihr eigener Node-Code

DSH-/Cordis-Plugin

Kompositionszeile

native Tools in einer DSH-Umgebung

npx -y @truenix/agent-browser markdown https://news.ycombinator.com

Alles läuft lokal. Kein Konto, kein API-Schlüssel, kein Remote-Dienst, kein Kontingent.

Warum

Wenn man einem Agenten rohes HTML füttert, verschwendet das den Großteil seines Kontexts. Gemessen auf echten Seiten:

Und ein Browser, der sich als Automatisierung zu erkennen gibt, wird blockiert, degradiert oder erhält andere Inhalte – was stillschweigend das korrumpiert, was der Agent geschlossen hat.

Benchmark für schwere Seiten (live, curl vs. markdown)

Seite

rohes HTML

Markdown

--links text

Ersparnis

en.wikipedia.org/wiki/WebAssembly

927 kB

120 kB

55 kB

7.7× / 16.8×

react.dev

273 kB

11 kB

8.7 kB

23.8× / 31.4×

nextjs.org

323 kB

10 kB

7.3 kB

32.0× / 44.2×

github.com/trending

648 kB

69 kB

13 kB

9.3× / 48.9×

apple.com

360 kB

4.6 kB

3.5 kB

78.6× / 102.8×

news.ycombinator.com

35 kB

10 kB

3.2 kB

3.4× / 11.0×

Regenerieren Sie beide Diagramme und die zugrunde liegenden Messwerte dieser Tabelle mit npm run charts – es misst live und zeichnet dann die PNGs mit agent-browser selbst, sodass die Zahlen in den Bildern nicht von dem abweichen können, was der Code erzeugt.

Weniger Tokens für dieselbe Seite ausgeben

URLs machen ein Drittel der Ausgabe bei einem Wikipedia-Artikel und vier Fünftel bei github.com/trending aus. Wenn der Agent liest statt zu navigieren, lassen Sie sie weg:

agent-browser markdown https://github.com/trending --links text      # 69 kB -> 13 kB
agent-browser markdown https://en.wikipedia.org/wiki/Rust --links relative

Modus

rendert

Verwendung, wenn

inline (Standard)

[text](https://site/page)

der Agent als Nächstes navigieren wird

relative

[text](/page)

Crawling innerhalb derselben Site; behält Ziele, verwirft die Herkunft

text

text

Lesen, Zusammenfassen, Beantworten von Fragen

Heavy-site benchmark

Token cost: Raw HTML vs agent-browser Token-Kosten pro YC-Check (HN + YC-Blog gelesen mit --links text, 51,1k → 1,5k Tokens, +500 Ausgabe) — Preisliste August 2026: Anthropic Haiku 4.5 $1/$5, Sonnet 5 $3/$15, Opus 5 $5/$25 • OpenAI GPT-4o $2.50/$10, GPT-4o mini $0.15/$0.60

Seiten, die nach dem Laden rendern

Die Navigation wartet auf das load-Ereignis, gesteuert durch CDP-Lebenszyklus-Ereignisse statt einer Polling-Schleife und einer festen Verzögerung. Auf echten Seiten ist das 2–3× schneller bei byteidentischer Ausgabe:

Seite

--wait load (Standard)

alte feste 250 ms Wartezeit

example.com

7 ms

258 ms

github.com/trending

115 ms

340 ms

nextjs.org

160 ms

365 ms

news.ycombinator.com

218 ms

466 ms

Eine client-gerenderte App, deren Inhalt nach dem Laden eintrifft, braucht ein echtes Signal, keine größere Vermutung – die alte 250-ms-Wartezeit hat diesen Inhalt ebenfalls verpasst:

agent-browser markdown https://some-spa.example --wait idle

Modus

wartet auf

Verwendung, wenn

domcontentloaded

das DOM geparst ist

Sie nur Markup benötigen, das im HTML enthalten ist

load (Standard)

das load-Ereignis

fast immer

idle

das Netzwerk ruhig wird

das Ergebnis wie eine leere Hülle aussieht

Related MCP server: Browser-MCP Navigator

Jede andere Umgebung

Wenn Ihr Framework JSON Schema spricht, kann es agent-browser steuern, ohne dass dieses Projekt von der Existenz des Frameworks weiß. agent-browser tools gibt den Katalog in der Form aus, die Sie benötigen:

agent-browser tools                     # MCP:       {name, description, inputSchema}
agent-browser tools --format openai     # OpenAI:    {type:"function", function:{...}}
agent-browser tools --format anthropic  # Anthropic: {name, description, input_schema}

Jedes Tool läuft dann auf beide Arten, je nachdem, was Ihr Harness kann:

import { findTool, TOOLS } from '@truenix/agent-browser/tools';
import { withBrowser } from '@truenix/agent-browser';

// in-process: the harness can hold a CDP session
const tool = findTool('browser_markdown');
const text = await withBrowser({}, async (session) => {
  await session.navigate('https://example.com');
  return tool.run(session, { url: 'https://example.com', links: 'text' });
});

// out-of-process: the harness can only run a command (sandboxes, shells)
tool.cli({ url: 'https://example.com', links: 'text' });
// => ['markdown', 'https://example.com', '--links', 'text']

Installation

Als MCP-Server

claude mcp add browser -- npx -y @truenix/agent-browser mcp
{
  "mcpServers": {
    "browser": {
      "command": "npx",
      "args": ["-y", "@truenix/agent-browser", "mcp"]
    }
  }
}

Tools: browser_markdown, browser_text, browser_html, browser_links, browser_screenshot, browser_evaluate, browser_accessibility_tree, browser_pdf, browser_probe.

Jede Oberfläche stellt dieselben neun Tools aus einem gemeinsamen Katalog bereit, sodass CLI, MCP-Server und DSH-Plugin nie auseinanderdriften können.

Als Bibliothek

npm install @truenix/agent-browser
import { withBrowser } from '@truenix/agent-browser';

const md = await withBrowser({}, async (session) => {
  await session.navigate('https://example.com');
  return session.markdown();
});

Als DSH-/Cordis-Plugin

Einzeiler (empfohlen – verdrahtet automatisch, wenn Sie DSH meinen):

npx -y @truenix/agent-browser install          # adds the bundle to ~/.dsh/profiles/web/package.json, then pnpm install (the mount ships in the package's own cordis.patch.yml layer)
# npx -y @truenix/agent-browser install --profile web --dry-run  # preview
# npx -y @truenix/agent-browser uninstall      # remove again

Starten Sie dsh neu – alle neun browser_*-Tools erscheinen als native Tools. Bei einer einfachen npm install wird kein Handler ausgeführt; eine absichtliche install ist erforderlich.

Manuell (wenn Sie die Komposition lieber selbst bearbeiten):

npm i -g @truenix/agent-browser
# or inside the harness checkout: pnpm add @truenix/agent-browser

Erfordert Node ≥ 18 und eine Chrome/Chromium-Installation. Fügen Sie dann zur Host-Komposition hinzu (die Tool-Registry lebt auf dem Host, nicht pro Agent):

# ~/.dsh/profiles/web/cordis.patch.yml  — persists for every web session
- insert:
  - id: agent-browser
    name: '@truenix/agent-browser/cordis'
    config:
      timeoutMs: 180000   # per-tool call budget; default respects AGENT_BROWSER_BIN / ENDPOINT
      # cli: 'npx -y @truenix/agent-browser'  # override only if needed

Kurzform (wenn die Komposition bereits insert umschließt):

- '@truenix/agent-browser/cordis':
    timeoutMs: 180000

Env-Overrides: AGENT_BROWSER_BIN (Chrome-Binärdatei), AGENT_BROWSER_ENDPOINT (an langlebigen Browser über --endpoint anhängen) oder config.cli.

CLI

agent-browser <command> [options]

  markdown <url>     Extract the whole page as Markdown (main content by default)
  text <url>         Visible text only
  html <url>         Full serialized DOM after JavaScript runs
  links <url>        Every anchor as JSON
  screenshot <url>   PNG/JPEG   (-o file, --full)
  pdf <url>          PDF        (-o file)
  a11y <url>         Filtered accessibility tree
  eval <url> <expr>  Evaluate JS, return only its value (cheapest)
  probe              Browser, GPU and capability report
  mcp                Run as an MCP server on stdio
  tools              Print tool schemas (--format mcp|openai|anthropic)

Optionen: --headful, --no-stealth, --block-images, --gpu/--no-gpu, --width, --height, --viewport WxH, --main, --raw, --links, --max-rows, --limit, --wait, --settle, --full, --endpoint <ws>, --timeout, --json, -o.

markdown zum Lesen, eval zum Nachschlagen

Der teuerste Fehler, den ein Agent mit diesem Tool macht, ist das Rendern einer ganzen Seite, um eine einzeilige Frage zu beantworten. Drei gezielte Fragen über drei schwere Seiten kosten 235 Bytes über eval, gegenüber 77 kB Markdown:

agent-browser eval https://github.com/trending \
  "JSON.stringify(Array.from(document.querySelectorAll('article h2 a')).slice(0,3).map(a=>a.innerText.trim()))"
# ["openai / codex","mattpocock / skills","affaan-m / ECC"]   -> 58 bytes

Greifen Sie zu innerText, nicht zu textContent. textContent gibt den rohen Quell-Whitespace zurück ("openai /\n\n codex"); innerText liefert, was tatsächlich gerendert wird ("openai / codex"). Ein Agent, der das falsch macht, zahlt eine ganze Wiederholungsrunde, die weit mehr kostet als die gesparten Bytes.

Verwenden Sie markdown, wenn Sie die Seite tatsächlich lesen, zusammenfassen oder durchsuchen müssen.

Jeder Aufruf startet einen eigenen Browser (~1,4 s). Für mehrere aufeinanderfolgende Abfragen halten Sie einen Browser am Leben und richten --endpoint darauf – dieselben drei Fragen dauern 5,9 s über drei Kaltstarts, 3,2 s gegen einen warmen.

--endpoint hängt an einen bereits laufenden Browser an, statt einen zu starten – nützlich, um einen einzelnen langlebigen Browser über viele Aufrufe hinweg wiederzuverwenden.

Speicher

Chromes Untergrenze liegt bei etwa 420 MB PSS über 18 Prozesse, bevor es etwas lädt, und diese Untergrenze gehört zu Chrome, nicht zu diesem Paket – Flag-Tuning verschiebt sie um ~5%, und das Flag, das sie weiter verschiebt (--enable-low-end-device-mode), meldet navigator.deviceMemory: 2 neben 24 Kernen, eine unmögliche Maschine und genau die Art von Inkonsistenz, die einen Browser auffliegen lässt. Der Hebel ist also weniger Browser, nicht kleinere.

Der MCP-Server hält einen Browser und gibt jedem Tool-Aufruf einen eigenen isolierten Kontext. Drei schwere Seiten gleichzeitig abgerufen:

Spitzen-PSS

Prozesse

Echtzeit

ein Browser pro Aufruf

1289 MB

44

2114 ms

ein Browser, 3 Kontexte

654 MB

20

2049 ms

Die Isolation bleibt unverändert – der Browser-Kontext pro Aufruf war schon immer das, was sie bereitstellte. Der Browser fährt nach 30 s Inaktivität herunter (AGENT_BROWSER_IDLE_MS, 0 zum sofortigen Schließen), sodass ein langlebiger Server nicht zwischen Gesprächen auf 420 MB sitzt. Ein wiederholter Aufruf, während er warm ist, überspringt den Start vollständig und läuft etwa doppelt so schnell.

Der Kompromiss: Aufgaben teilen sich einen Prozessbaum, sodass ein Absturz auf Browser-Ebene alles in Bearbeitung betrifft statt nur einen Aufruf. Ein toter Browser wird erkannt und beim nächsten Aufruf neu gestartet. Wenn Sie eine Isolierung des Schadensradius pro Aufgabe benötigen, verwenden Sie withBrowser, das jedem Aufruf weiterhin einen eigenen Browser gibt.

import { withPooledSession, shutdownPool } from '@truenix/agent-browser/pool';

await withPooledSession({}, async (session) => {
  await session.navigate('https://example.com');
  return session.markdown();
});
await shutdownPool();   // or let it idle out

Für die CLI ist jeder Aufruf ein eigener Prozess, Wiederverwendung bedeutet also, --endpoint auf einen Browser zu richten, den Sie selbst am Leben halten.

Der Daemon: ein Browser für jeden CLI-Aufruf

Jeder CLI-Aufruf ist ein eigener Prozess, also startet standardmäßig jeder einen eigenen Chrome – zehn gleichzeitige Aufrufe bedeuten zehn Browser. --daemon teilt stattdessen einen residenten Browser, wobei jeder Aufruf weiterhin seinen eigenen isolierten Kontext erhält:

agent-browser markdown https://example.com --daemon
agent-browser daemon --status
agent-browser daemon --stop

Echtzeit

Spitzen-Chrome-Prozesse

3 sequenzielle Abfragen, ohne Daemon

5330 ms

—

3 sequenzielle Abfragen, --daemon

3254 ms

—

10 gleichzeitige Aufrufe, ohne Daemon

1443 ms

140

10 gleichzeitige Aufrufe, --daemon

1144 ms

32

Es ist opt-in (--daemon oder AGENT_BROWSER_DAEMON=1), weil das Starten eines Hintergrundprozesses, der Ihren Befehl überlebt, ein Nebeneffekt ist, um den man bitten sollte. Er startet bei Bedarf und beendet sich nach fünf Minuten Inaktivität (AGENT_BROWSER_DAEMON_IDLE_MS). Das Setzen der Umgebungsvariable leitet auch den MCP-Server dorthin, was sinnvoll ist, wenn mehrere MCP-Clients eine Maschine teilen.

--headful, --width, --height, --block-images und --gpu werden beim Start eines Browsers festgelegt, sodass ein geteilter sie nicht berücksichtigen kann. Wenn Sie eines davon übergeben, gewinnt das: Dieser Aufruf erhält stillschweigend einen eigenen privaten Browser und meldet das auf stderr.

Vier Fehlermodi, um die herum es gebaut ist, jeder durch Tests verifiziert:

  • Genau ein Daemon. Zehn gleichzeitige Erstaufrufer starten alle einen; neun verlieren das Rennen um die Socket-Bindung und beenden sich, bevor sie etwas starten. Die Socket-Bindung ist die Sperre, also gibt es keine Lockdatei, die veralten kann.

  • Der offene Socket ist der Referenzzähler. Ein Client hält seine Verbindung, während er arbeitet, sodass ein mit SIGKILL getöteter Client trotzdem freigibt – der Kernel schließt den Socket. Eine „Bitte freigeben“-Nachricht hätte eine Referenz für immer verloren.

  • Beendigung bei Inaktivität, sodass er nicht zwischen Gesprächen auf ~420 MB sitzt.

  • Ein mit SIGKILL getöteter Daemon hinterlässt nichts: Sein Profilmarker nennt seine PID, sodass der unten beschriebene Durchlauf den Browser beim nächsten Start zurückholt.

Aufräumen nach sich selbst

Jeder Start schreibt einen Besitzermarker in sein temporäres Profil und durchsucht nach Profilen, deren Besitzer gestorben ist, und beendet den Browser, der noch daran hängt. Zusammen mit SIGINT/SIGTERM/SIGHUP-Handlern ergibt das:

wie der Aufruf endet

verwaiste Prozesse

nach dem nächsten Start

normal

0

0

SIGTERM / SIGINT

0

0

SIGKILL (nicht abfangbar)

1 Browser

0

Ein harter Kill kostet also höchstens einen verwaisten Browser, nicht einen pro unterbrochenem Aufruf. Zehn gleichzeitige CLI-Aufrufe, wiederholt, hinterlassen nichts. Ein laufender Browser wird nie weggeräumt – sein Besitzerprozess läuft noch, und ein nicht zuordenbares Profil bleibt in Ruhe, bis niemand mehr es offen hat und es 60 s lang im Leerlauf war.

Bot-Erkennung

Teste es selbst: npm run test:bot. Letztes Ergebnis:

Detektor

Ergebnis

bot.sannysoft.com

31 bestanden, 0 fehlgeschlagen

bot-detector.rebrowser.net

6 grün, 0 rot, runtimeEnableLeak: clean

deviceandbrowserinfo.com

isBot: false, 0 von 22 Prüfungen markiert

Normales Headless-Chrome scheitert bei vier sannysoft-Zeilen (HEADCHR_UA, CHR_MEMORY, WebGL SwiftShader, alte UA) und wird als Bot gemeldet.

Ein nicht erreichbarer Detektor zählt als SKIP, nie als bestanden, und das Gate verlangt drei erreichbare Bestätigungen – so kann ein Tag, an dem die Testseiten down sind, nicht als Erfolg fehlinterpretiert werden.

Die Umgebung zählt mehr als das Patchen

Derselbe Code, an zwei Orten gemessen:

dieser Arbeitsplatz

GitHub-Actions-Runner

IP

privat

Rechenzentrum

GPU

echt (NVIDIA)

keine → SwiftShader

bot.sannysoft.com

31 bestanden, 0 fehlgeschlagen

30 bestanden, 1 fehlgeschlagen (WebGL Renderer)

bot-detector.rebrowser.net

6 grün, 0 rot

6 grün, 0 rot

deviceandbrowserinfo.com

isBot: false

isBot: true (hasSuspiciousWeakSignals)

Alle CDP-Ebene-Signale bleiben in beiden Fällen sauber – das ist Code, und der Code ist richtig. Was das Urteil kippt, ist die Umgebung: eine Rechenzentrums-ASN plus Software-Rendering löst einen Schwachsignal-Verbund aus, den kein noch so viel Fingerprint-Patching behebt.

Das ist die ehrliche Form des Problems. Das Härten des Browsers entfernt die trivialen Anzeichen. Wo du es ausführst, entscheidet den Rest.

Was die Härtung bewirkt und warum

Jeder Punkt kam von einem Detektor, der uns sagte, dass wir falsch lagen:

  • Kein --enable-automation. Dieses Flag – das Puppeteer und Playwright hinzufügen – setzt navigator.webdriver = true. Rohes CDP setzt es nicht, also bleibt es false, ohne dass etwas gepatcht wird.

  • Kein Runtime.enable. Es ist das lauteste CDP-Signal und treibt den klassischen Console/Error.stack-Detektor. Runtime.evaluate funktioniert auch ohne.

  • Fenster und Bildschirm bewegen sich zusammen. --window-size ohne --ozone-override-screen-size ergibt outerWidth > screen.width, was physikalisch unmöglich ist – ein stärkeres Signal als reines Headless.

  • Keine Standard-Device-Metrics-Überschreibung. Die übliche 1280×720 ist Playwrights Standard-Viewport, und Detektoren markieren sie beim Namen. Setze --viewport nur, wenn du es brauchst.

  • Echte GPU, wenn verfügbar, was einen echten ANGLE (NVIDIA …)-Renderer statt SwiftShader ergibt.

  • UA beim Start gesetzt, nicht nur über CDP. Emulation.setUserAgentOverride erreicht Web Workers nicht, also meldet ein Worker weiterhin die Headless-UA, während die Seite die saubere meldet (hasInconsistentWorkerValues).

  • Kein acceptLanguage-Override. CDP leitet navigator.languages ab, indem es diesen Header aufteilt, also wird "en-US,en;q=0.9" zu ["en-US","en;q=0.9"] – ein q-Wert, wo keiner legal existieren kann, und eine weitere Seite/Worker-Diskrepanz. --lang macht es korrekt.

  • Client Hints, abgeleitet aus der eigenen Version des Binärs, sodass Sec-CH-UA nicht mit navigator.userAgent kollidieren kann.

  • Isolierter Browser-Kontext pro Sitzung, beim Schließen entsorgt – sauberer Zustand pro Aufgabe ohne zweiten Browserprozess.

Die wiederkehrende Lektion: Konsistenz schlägt Abdeckung. Vier davon sind Fälle, in denen teilweises Spoofing die Erkennung erleichterte, nur entdeckt durch das Ausführen echter Detektoren.

Warum WebGL-Spoofing standardmäßig deaktiviert ist

spoofWebgl existiert und ist sorgfältig implementiert – ein Proxy um natives getParameter, sodass Function.prototype.toString weiterhin [native code] meldet. Es ist aus, weil Messungen zeigen, dass es nach hinten losgeht. Aus test/webgl-spoof-experiment.mjs:

Arm

behaupteter Renderer

maxTexture

Erweiterungen

sannysoft

Urteil

echte GPU, kein Spoof

NVIDIA

32768

37

0 fehlgeschlagen

isBot: false ✅

SwiftShader, ehrlich

SwiftShader

8192

35

1 fehlgeschlagen

isBot: false ✅

SwiftShader + Spoof

NVIDIA

8192

35

0 fehlgeschlagen

isBot: true ❌

Hardware zu behaupten, die du nicht hast, behebt eine kosmetische Zeile und lässt den Verbunddetektor scheitern: Das injizierte Skript erreicht Web Workers nicht, also meldet der Worker weiterhin SwiftShader, und MAX_TEXTURE_SIZE bleibt beim Software-Wert, während die Renderer-Zeichenkette eine diskrete GPU behauptet.

Ehrliches SwiftShader besteht. Eine überzeugende Lüge nicht. Gib dem Browser stattdessen eine echte GPU – es ist kostenlos.

Was das NICHT tut

Fingerprint-Erkennung ist der gesamte Umfang. Es besiegt nicht und versucht nicht zu besiegen:

  • TLS/JA3-JA4- und HTTP/2-Fingerprinting – entschieden, bevor irgendein JavaScript läuft

  • IP-Reputation – Rechenzentrum vs. private ASN, oft der eigentliche Blocker

  • Verhaltensanalyse – Mauspfade, Timing, Verweildauer

Kommerzielle Challenge-Produkte stützen sich darauf, also bedeutet „das Gate bestehen“ nicht trivial als Automatisierung markiert zu werden, nie unerkennbar. Gedacht für deine eigenen Seiten, Tests, Barrierefreiheitsarbeit und normales Agenten-Browsing.

Speicher

Ein Chrome-Stack kostet ungefähr 450 MB. Der Hebel ist Architektur, nicht Flags: Starte einen Browser und viele isolierte Kontexte statt einen Browser pro Aufgabe. Starte einen Browser einmal und richte dann jeden Aufruf mit --endpoint / AGENT_BROWSER_ENDPOINT darauf. --block-images hilft bei Textarbeit.

Null Abhängigkeiten

dependencies ist leer, einschließlich des WebSocket-Transports.

Nodes globales WebSocket (WHATWG) kann keine Request-Header senden, was jeder authentifizierte oder proxierte CDP-Endpunkt braucht, und undici ist nicht eigenständig importierbar. Also implementiert src/ws.mjs RFC 6455 direkt über node:http(s) – Handshake, Maskierung, Fortsetzungsfragmente, 64-Bit-Längen, Ping/Pong – was alles ist, was CDP benötigt.

Der Markdown-Konverter durchläuft das DOM mit einem expliziten Stack, hält die JS-Aufruftiefe bei O(1) unabhängig von der Verschachtelung und verwendet natives innerText für Inline-Knoten auf Blattebene. Das macht ihn sowohl rekursionssicher bei tief verschachtelten Dokumenten als auch deutlich schneller bei großen Seiten.

Umgebung

AGENT_BROWSER_BIN

Pfad zu einem Chrome/Chromium-Binär

AGENT_BROWSER_ENDPOINT

an diesen CDP-Endpunkt anhängen statt starten

Anforderungen

Node ≥ 18 und eine Chrome/Chromium-Installation. Kein Build-Schritt.

Danksagungen

Die Härtung dieses Projekts ist fast vollständig aus der veröffentlichten Erkennungsforschung anderer Leute abgeleitet – siehe CREDITS.md. Besonderer Dank an rebrowser-bot-detector, bot.sannysoft.com, deviceandbrowserinfo.com und Camoufox dafür, dass sie gezeigt haben, wie man es richtig macht.

Lizenz

MIT

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    B
    maintenance
    MCP server for browser automation with anti-detection. Scout pages, find elements, interact with websites, and monitor network traffic from any AI client that supports the Model Context Protocol.
    21
    1
    MIT
  • A
    license
    A
    quality
    B
    maintenance
    A fault-tolerant, stealth-enabled Model Context Protocol (MCP) server for web searching and content fetching. Built for AI Agents (Cursor, Claude Code, OpenCode), it uses a stealth browser engine to fetch pages, dynamically handles SPAs/React, and converts bloat into token-optimized Markdown.
    2
    13 npm
    3
    MIT
  • A
    license
    A
    quality
    A
    maintenance
    MCP server that drives your real Chrome/Edge/Opera browser through a Chrome extension and DevTools Protocol, preserving logins and session state, and can also perform OS-level mouse and keyboard input behind approval.
    51
    34 PyPI
    2
    MIT