Skip to main content
Glama
LowOrbitLab

chromiumfish_mcp

by LowOrbitLab

chromiumfish_mcp

chromiumfish_mcp is an independent Model Context Protocol (MCP) server for ChromiumFish. It lets Claude Code, Claude Desktop, Cursor, and other MCP clients drive a ChromiumFish browser through structured tools.

It uses the official ChromiumFish npm package and ships no Chromium source or binaries — on the first tool call that needs a page, the upstream SDK downloads and caches the matching browser build. See docs/USAGE.md for detailed tool usage.

Requirements

  • Node.js 20 or later.

  • An OS and architecture supported by ChromiumFish.

  • Network access for the initial browser download. If no prebuilt asset matches your platform, build ChromiumFish locally and point to it with --chrome-path or CHROME_BIN.

Related MCP server: mcp-chrome-server

Install

npm install --global github:LowOrbitLab/chromiumfish_mcp
chromiumfish_mcp --persona-seed alice

Or run without installing: npx --yes github:LowOrbitLab/chromiumfish_mcp --persona-seed alice.

Configure

Add the server to your MCP client config:

{
  "mcpServers": {
    "chromiumfish": {
      "command": "chromiumfish_mcp",
      "args": ["--persona-seed", "alice"]
    }
  }
}

To run from GitHub instead of a global install, set "command": "npx" and prepend "--yes", "github:LowOrbitLab/chromiumfish_mcp" to args. On Windows, use npx.cmd if your client cannot resolve npx.

Tools

Tool

Purpose

list_pages, open_page, select_page, close_page

Manage pages by stable pageId

navigate, navigate_back, navigate_forward, reload

Navigate and use page history

snapshot

List visible interactive elements with e1/e2 references

get_text, take_screenshot

Retrieve page or frame content; take_screenshot crops to one element with target

click, hover, type_text, select_option, set_checked, press_key, scroll, wait_for

Interact with the page

drag

Drag onto another element or by a pixel offset, with a human-like path

handle_dialog

Arm the answer for the next alert/confirm/prompt/beforeunload

upload_file

Attach local files to a file input — requires --upload-dir

list_downloads

Report what was downloaded and where it landed — requires --download-dir

click_at

Click absolute coordinates (for widgets snapshot cannot see)

list_frames

List frames/iframes with stable IDs

find_challenge, solve_challenge

Detect and clear interstitial / framed challenges; the result says whether one was observed, interacted with, and verified

evaluate

Run arbitrary JavaScript — requires --allow-eval

run_task

Native ChromiumFish agent — requires --allow-native-agent

A JavaScript dialog is answered the instant it opens, because a page left waiting on one freezes and no later call could finish. Unarmed the answer is dismiss — which is what Playwright already did silently — so a click that only raised confirm("Delete?") did not delete, and the action result now says so under dialogs. Call handle_dialog to arm the next answer, then repeat the action. The four navigation tools also report the HTTP status, since a 404 or a 500 loads like any other page.

Every navigation and interaction tool reports the resulting url, title, navigated, and any newPages, so a client only needs a follow-up snapshot when the page actually changed; returnSnapshot: true returns the action result and a fresh snapshot in one call. An action that navigates waits for the new document before reporting, so those fields describe the page it arrived on; one whose navigation is still in flight after ten seconds reports navigationPending: true rather than describing the page being left as though nothing happened, and one whose navigation was cancelled outright — blocked by --allowed-host, an unresolvable host — reports navigationFailed with the browser's own reason instead of waiting out that bound for a page that is never coming. Reference numbers are never reused, so one held across a snapshot fails with an error instead of acting on a different element; snapshot also reports ARIA roles, so role=button[name="Submit"] works in any target field as a re-render-proof alternative. The server ships MCP instructions describing this workflow, reference lifetime, and the challenge sequence.

Snapshot references, frame-aware interaction, waiting, and the cross-origin challenge workflow are covered in docs/USAGE.md.

Command-line options

--persona-seed VALUE       Use a stable browser fingerprint persona
--chrome-path PATH         Use a local ChromiumFish executable
--browser-version VERSION  Select an upstream ChromiumFish build version (rejected with --chrome-path)
--headed                   Show the browser window
--window-size WIDTHxHEIGHT Set the browser window size
--timezone ZONE            Use an IANA time zone, auto, or system (default: auto)
--proxy URL                Route browser traffic through a proxy
--allowed-host HOST        Allow top-level navigation to a bare host and its subdomains; repeatable
--max-text-chars N         Set the hard limit for text and snapshot output
--upload-dir PATH          Allow upload_file to read this directory; repeatable
--download-dir PATH        Save downloads here; without it they are discarded
--allow-eval               Enable arbitrary JavaScript execution
--allow-native-agent       Enable the native ChromiumFish browser agent

Proxy credentials can be embedded in the proxy URL, but are then exposed in the client config. Never commit config files containing proxy passwords, cookies, or API keys.

Security

  • stdio only — do not expose the Chromium DevTools endpoint to the public internet.

  • evaluate and the native agent are disabled by default; enable them only in trusted environments.

  • --allowed-host example.com restricts top-level HTTP/HTTPS navigation (redirects, links, form posts, popups) to a host and its subdomains. Give it a bare host name: matching is on the host alone, so a scheme, path, port, leading dot, or wildcard is rejected at startup rather than quietly matching nothing. Third-party subframes and page assets remain reachable — it is a navigation guard, not a network egress filter. A blocked navigation is reported as navigationFailed with reason net::ERR_BLOCKED_BY_CLIENT, rather than as a click that appeared to do nothing. Enabling it also turns on request interception, which disables the browser's HTTP cache for the session: expect slower asset-heavy pages, and note that a browser re-fetching everything on a repeat visit is itself a signal to sites that profile behavior.

  • upload_file sends host files to whatever origin the page posts to, so it is unregistered until --upload-dir names at least one directory, and every path must resolve inside one. Both the path and the roots are resolved through symlinks first, so a link planted inside a root cannot reach outside it. Scope the roots to the files a task actually needs — a page can influence which file the model picks.

  • Downloads are written only when --download-dir names a directory; without it the transfer still runs (so the page's own flow is unchanged) but nothing is kept, and the action result says discarded. The file name comes from the remote server's Content-Disposition, so it is reduced to a bare base name and the resolved path is checked against the root before anything is written.

  • A page can raise confirm() to guard a destructive action. Unarmed dialogs are dismissed, so that guard holds by default; handle_dialog with accept: true deliberately answers the next one. Keep human confirmation in front of it for anything irreversible.

  • Clients can click and type with real side effects. Keep human confirmation for purchases, publishing, deletion, and permission changes.

  • solve_challenge returns ok: true whenever the page is not blocked, including on pages that were never challenged. Read challengeObserved, interactionPerformed, and clearanceVerified before recording or reporting that a challenge was cleared — ok alone will overstate what happened.

  • Each process runs an independent browser context; this is not a shared multi-tenant service.

Development

npm ci
npm test
node dist/index.js --help

The suite uses an in-memory MCP transport to verify tool discovery, dangerous-tool opt-in, and results. It does not download or launch a browser.

License

MIT. ChromiumFish code and trademarks belong to their respective contributors; see NOTICE for attribution. This is an independent wrapper, not an official ChromiumFish release.

Install Server
A
license - permissive license
A
quality
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

View all related MCP servers

Related MCP Connectors

  • Hosted real Google Chrome MCP with per-user persistent state. Navigate, click, type, screenshot.

  • Access Kernel's cloud-based browsers and app actions via MCP (remote HTTP + OAuth).

  • Browser MCP for logged-in tasks. Uses your Chrome — credentials stay local. Zero-token replay.

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/LowOrbitLab/chromiumfish_mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server