OmniBrowse

Web Browser for your AI Agent.

Documentation

OmniBrowse

OmniBrowse is a Model Context Protocol (MCP) server providing a private-mode text-based headless browser for AI agents. No Selenium, Playwright, or Chromium — just Node.js with Chrome TLS impersonation (curl-impersonate), jsdom JavaScript execution, full DOM/input handling, and 31 tools designed for AI browsing workflows.

Pages are parsed into an accessibility-style text snapshot with interactive element refs (r1, r2, …). The model clicks, types, scrolls, and runs JavaScript — each action triggers the real protocol (HTTP/curl-impersonate with true Chrome JA3, or local schemes like data:/file:/ftp:/ipfs:).

Install

Add to your MCP client config (Claude Desktop, Kilo, Cursor, etc.):

{ "mcpServers": { "web-browser": { "command": "npx", "args": ["-y", "omnibrowse"] } } }

Until the npm package is published, run locally:

{ "mcpServers": { "web-browser": { "command": "node", "args": ["/absolute/path/to/omnibrowse/dist/index.js"] } } }

Tools

#ToolDescription
1navigateOpen a URL (http/https/data/file/ftp/gopher/ipfs/about/javascript). Set js=true for jsdom SPA rendering. Set newSession=true to wipe history/cookies before navigating. Returns an accessibility snapshot.
2read_snapshotRe-read the current viewport of the page.
3scroll_read_moreAdvance to the next chunk of a long page (viewport-sized scroll).
4clickClick an element by ref. Links navigate; buttons/submit inputs submit their form with all filled fields.
5type_textType into a textbox/textarea by ref. submit=true submits the enclosing form afterward.
6select_optionChoose option(s) in a by ref (values array).
7checkToggle a checkbox/radio by ref (checked true/false).
8go_backGo back one page in session history.
9findSearch the current snapshot by plain text (case-insensitive) or regex (/pattern/flags). Returns matching lines with context.
10url_barReturn the current page URL.
11view_sourceReturn raw HTML of the current page (post-JS if js=true was used). Byte-offset pagination supported.
12evaluate_jsRun arbitrary JavaScript in the current page's window context via jsdom. Expressions are auto-wrapped and the return value is extracted with JSON.stringify. Returns console output + eval result.
13wait_forRe-run jsdom on the current page and poll until a CSS selector appears (or timeout). Returns the new snapshot.
14network_requestsList XHR/fetch/subresource requests observed during the last jsdom run.
15console_logsDump captured console.log/error/warnings and uncaught script errors from page scripts. Filter by level (all/log/error).
16cookie_jarInspect cookies in this private session (in-memory only, per-hostname, never persisted).
17route_infoShow redirect chain, DNS resolution (via dig), transport info (curl-impersonate binary, TLS impersonation target), and security headers for the current page.
18inspect_elementReturn raw HTML + parsed attributes for a specific element ref.
19list_linksEnumerate all links, headings, and images on the current page for fast scanning.
20fetch_resourceMake a raw HTTP(S) request (GET/POST/PUT/HEAD) or fetch a local-scheme resource. Non-HTML content is rendered through content handlers: JSON pretty-printed with summary, PDF text extracted via pdftotext+pdfinfo, images dimensioned and optionally OCR'd, media probed via ffprobe, archives described.
21resource_discoveryAuto-discover well-known resources: robots.txt, sitemap.xml, RSS/Atom feeds (/rss, /feed, /atom.xml, etc.), web app manifest.json, OpenSearch descriptor, favicon.ico/png. Set kind to fetch one specifically.
22resize_viewportChange the snapshot window size (lines per viewport) and re-snapshot the current page from the top.
23permissionsList which browser Web APIs are stubbed, granted silently, or blocked in this private browsing session.
24go_forwardGo forward to the next page in session history (after using go_back).
25history_listList all pages in the browsing session history with the current page marked.
26press_keyPress a keyboard key (ref?, key). Enter submits the enclosing form; Escape clears form state; Tab/Backspace/Delete/arrows/Space/page-keys/single characters are simulated on text inputs.
27hoverHover over an element by ref to dispatch mouseenter/mouseover/mousemove events; re-renders via jsdom if the DOM changes (reveals hover-triggered tooltips and menus).
28file_uploadSelect local file(s) for a by absolute path. Submit the form afterwards (click on submit button or press Enter) to upload via multipart/form-data.
29screenshotCapture a structured text "screenshot" (full-page layout dump) of the current page. Pair with view_source for raw HTML.
30handle_dialogAccept/dismiss an alert/confirm/prompt dialog raised by page JS during the last jsdom run (with optional response for prompts).
31dialog_listList any dialogs (alert/confirm/prompt) queued from the last jsdom run, with the next-to-handle marked.

All tools with an empty input schema use z.object({}) for MCP SDK compatibility.

Protocols

HTTP/HTTPS goes through curl-impersonate with --impersonate chrome131, producing a true Chrome JA3 fingerprint. Local protocols are handled directly without network access:

SchemeHandler
data:Decodes base64 or percent-encoded payload, returns the MIME body.
blob:Unresolvable outside the originating JS context; an error note explains to use read_snapshot.
file:Reads regular files (sniffs MIME from extension) and generates directory listings (via ls -la with HTML-safe escaping).
javascript:Returns the source code for evaluate_js to run in page context.
about:Built-in pages: privatebrowsing, version, networking, preferences, blank, blobs, srcdoc. Default shows scheme + kind.
ftp: / ftps:Delegates to curl-impersonate. Directory listings are detected and wrapped in HTML
.
gopher:Fetches the selector text via curl-impersonate.
ipfs: / ipns:Resolves through public gateways in order: ipfs.io → dweb.link → cloudflare-ipfs.com → w3s.link.
ws: / wss:Returns informational text (WebSocket endpoints are detected but not connected).
mailto: / tel: / sms:External scheme — handled by the OS, not navigable.

Private browsing posture

  • Cookies live only in memory for the current MCP session, scoped per hostname. Third-party cookies (cross-registrable-domain Set-Cookie) are dropped. SameSite=None without Secure is rejected.
  • DNT: 1 and Sec-GPC: 1 sent on every HTTP request.
  • Referer suppressed to origin for cross-origin navigations.
  • No persistent cache, history, or storage written to disk between sessions.
  • WebRTC (RTCPeerConnection) blocked entirely. getUserMedia/getDisplayMedia denied. ServiceWorker.register throws SecurityError.
  • Geolocation, notifications, clipboard resolve silently without user prompts (denied/granted respectively).
  • Canvas/WebGL/AudioContext return plausible null contexts with no real pixels or audio output (fingerprint-safe).
  • crypto.subtle backed by Node's real WebCrypto — modern auth flows (PKCE, JWE) work.
  • fetch/XHR observed and recorded for the network-log tool.

Content rendering

Non-HTML resources fetched via fetch_resource are handled by content-type-specific renderers:

Content-TypeRenderer
image/*Dimensions via file / identify (ImageMagick). OCR via tesseract+imagemagick pipeline when installed.
application/pdfText extraction via pdftotext, metadata via pdfinfo.
application/json (and *+json)Pretty-printed with top-level object/array summary.
application/xml (and *+xml)Root element detection + raw text display.
audio/*, video/*ffprobe stream metadata when installed (codec, duration, resolution).
Archive types (application/zip,x-tar,gzip, etc.)Descriptive note (not expanded inline).
text/*Raw text with 30KB truncation.

How it works

LayerFileDescription
TLS/HTTPsrc/curl.tsDetects curl-impersonate binary (style-1 single binary or style-2 per-browser binaries), probes supported --impersonate targets, falls back to plain curl with crafted Chrome TLS ciphers/curves. Emits Chrome User-Agent, sec-ch-ua headers, HTTP/2/3, redirect chain tracking.
Private HTTPsrc/http.tsHttpClient wraps curlFetch with in-memory per-hostname CookieJar, SameSite enforcement, third-party cookie dropping, DNT/GPC headers, cross-origin Referer policy, DNS resolution via dig with caching, multipart POST assembly.
Protocolssrc/protocols.tsHandles all non-HTTP(S) URL schemes: data URI base64 decoding, file URI read+directory, ftp/gopher via curl, ipfs via public gateways, about: internal pages, javascript: eval forwarding, ws/wss info, external schemes.
DOMsrc/dom.tsnode-html-parser builds a tree; buildPage() walks it once producing an accessibility snapshot with [L] text lines and [rN] refs for interactive elements. Supports all HTML5 input types (slider, spinbutton, datetime, searchbox, color, file),
/, iframes, media elements (video/audio/canvas/object), heading markers, safe viewport scrolling with line-count guard.
JS Executionsrc/jsdom.tsjsdom with runScripts: "dangerously", real Internet ResourceLoader for subresources, Web API stubs (crypto.subtle→Node WebCrypto, Canvas/WebGL→null context, AudioContext→stub, Notification/Permission/Clipboard/Geolocation→silent deny, ServiceWorker/WebRTC→blocked), console+network capture.
Contentsrc/content.tsNon-HTML renderers: JSON pretty-print+summary, XML root detection, image dimensions+OCR (optional tesseract), PDF text extraction (optional pdftotext), media probe (optional ffprobe), archive descriptions.
Sessionsrc/browser.tsSession tracks page history, form state (filled values, toggled checkboxes, selected options), scroll position, and viewport size. performAction() routes all actions to the correct protocol fetch + render pipeline.
MCP Serversrc/index.ts31 tools registered via @modelcontextprotocol/sdk McpServer over StdioServerTransport. Stdio only — no HTTP server, no ports.

Build from source

npm install npm run build # outputs dist/ node dist/index.js # run the server (reads JSON-RPC from stdin)

Test

node test/test-comprehensive.mjs # 31 automated checks: navigation, JS, all protocols, tools, resources node test/test-ai-browse.mjs # Realistic 20-step AI browsing session (example.com → HN → DDG → resources → JS eval → protocols)

License

MIT