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:
>
> ```json
> {
> "mcpServers": {
> "web-browser": {
> "command": "node",
> "args": ["/absolute/path/to/omnibrowse/dist/index.js"]
> }
> }
> }
> ```
Tools
| # | Tool | Description |
|---|---|---|
| 1 | `navigate` | Open 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. |
| 2 | `read_snapshot` | Re-read the current viewport of the page. |
| 3 | `scroll_read_more` | Advance to the next chunk of a long page (viewport-sized scroll). |
| 4 | `click` | Click an element by ref. Links navigate; buttons/submit inputs submit their form with all filled fields. |
| 5 | `type_text` | Type into a textbox/textarea by ref. `submit=true` submits the enclosing form afterward. |
| 6 | `select_option` | Choose option(s) in a `` by ref (values array). |
| 7 | `check` | Toggle a checkbox/radio by ref (checked true/false). |
| 8 | `go_back` | Go back one page in session history. |
| 9 | `find` | Search the current snapshot by plain text (case-insensitive) or regex (`/pattern/flags`). Returns matching lines with context. |
| 10 | `url_bar` | Return the current page URL. |
| 11 | `view_source` | Return raw HTML of the current page (post-JS if js=true was used). Byte-offset pagination supported. |
| 12 | `evaluate_js` | Run 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. |
| 13 | `wait_for` | Re-run jsdom on the current page and poll until a CSS selector appears (or timeout). Returns the new snapshot. |
| 14 | `network_requests` | List XHR/fetch/subresource requests observed during the last jsdom run. |
| 15 | `console_logs` | Dump captured console.log/error/warnings and uncaught script errors from page scripts. Filter by level (all/log/error). |
| 16 | `cookie_jar` | Inspect cookies in this private session (in-memory only, per-hostname, never persisted). |
| 17 | `route_info` | Show redirect chain, DNS resolution (via dig), transport info (curl-impersonate binary, TLS impersonation target), and security headers for the current page. |
| 18 | `inspect_element` | Return raw HTML + parsed attributes for a specific element ref. |
| 19 | `list_links` | Enumerate all links, headings, and images on the current page for fast scanning. |
| 20 | `fetch_resource` | Make 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. |
| 21 | `resource_discovery` | Auto-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. |
| 22 | `resize_viewport` | Change the snapshot window size (lines per viewport) and re-snapshot the current page from the top. |
| 23 | `permissions` | List which browser Web APIs are stubbed, granted silently, or blocked in this private browsing session. |
| 24 | `go_forward` | Go forward to the next page in session history (after using go_back). |
| 25 | `history_list` | List all pages in the browsing session history with the current page marked. |
| 26 | `press_key` | Press 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. |
| 27 | `hover` | Hover 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). |
| 28 | `file_upload` | Select 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. |
| 29 | `screenshot` | Capture a structured text "screenshot" (full-page layout dump) of the current page. Pair with view_source for raw HTML. |
| 30 | `handle_dialog` | Accept/dismiss an alert/confirm/prompt dialog raised by page JS during the last jsdom run (with optional `response` for prompts). |
| 31 | `dialog_list` | List 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:
| Scheme | Handler |
|---|---|
| `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-Type | Renderer |
|---|---|
| `image/*` | Dimensions via `file` / `identify` (ImageMagick). OCR via tesseract+imagemagick pipeline when installed. |
| `application/pdf` | Text 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
| Layer | File | Description |
|---|---|---|
| TLS/HTTP | `src/curl.ts` | Detects `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 HTTP | `src/http.ts` | `HttpClient` 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. |
| Protocols | `src/protocols.ts` | Handles 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. |
| DOM | `src/dom.ts` | `node-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 Execution | `src/jsdom.ts` | jsdom 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. |
| Content | `src/content.ts` | Non-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. |
| Session | `src/browser.ts` | `Session` 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 Server | `src/index.ts` | 31 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
Frequently asked questions
What is OmniBrowse?
OmniBrowse is Web Browser for your AI Agent.
How do I install OmniBrowse?
Open the GitHub repository and follow its README. Most MCP servers are added to your client's MCP config, then called by your agent.
Is OmniBrowse open source?
Yes — it is hosted on GitHub at https://github.com/SkillfulElectro/OmniBrowse and has 1 stars.
Related MCP tools
Model Context Protocol Servers
The Open-Source Multimodal AI Agent Stack: Connecting Cutting-Edge AI Models and Agent Infra
A MCP for Claude Desktop / Claude Code / Windsurf / Cursor to build n8n workflows for you
MCP server to provide Figma layout information to AI coding agents like Cursor
The world's best AI personal assistant for email. Open source app to help you reach inbox zero fast.
Instant is the best backend for AI-coded apps. You get auth, permissions, storage, presence, and streams — everything you need to ship apps your users will love.
Run your own MCP server? See who uses it and what to fix.
Measure it with TrackMCP