Private stealth fork of ChromeDevTools/chrome-devtools-mcp
ghostframe-mcp
Private stealth browser-automation MCP server. Forked from chrome-devtools-mcp; default-on stealth posture for driving bot-managed sites. Coexists with upstream chrome-devtools-mcp on the same machine.
Not published to npm ("private": true in package.json). Local install only.
Differences from upstream
Stealth mode (--stealth, default true)
When on:
- The chrome-devtools-frontend
Universeis not initialised. The Universe forcesRuntime.enable+Debugger.enableon every page, which is the largest CDP-side fingerprint and is what theconsole.groupEndProxy-trap family of detectors looks for. - Page
console/pageerror/Runtime.exceptionThrownlisteners are not subscribed (those implicitly enableRuntime). - Patchright-shape DOM polyfills are injected on every navigation in every page:
chrome.runtime/chrome.loadTimes()/chrome.csi()stubs.Notification.permission↔navigator.permissions.query({name:'notifications'})coherence.- WebGL
UNMASKED_VENDOR_WEBGL/UNMASKED_RENDERER_WEBGLspoof (Intel Inc./Intel Iris OpenGL Engineinstead ofGoogle Inc. (Google)/SwiftShader). Function.prototype.toStringProxy preserving[native code]for the polyfilled functions.
- Mouse, hover, type, key-press, and drag go through humanisers:
- Cubic-bezier mouse paths with 8–24
mouseMovedevents, 8–30ms non-uniform gap. - 40–180ms mouse-down/up dwell.
- Lognormal keystroke flight (mean ~110ms, p10 55ms, p90 220ms), 50–150ms dwell, 350–600ms thinking pauses every 8–25 chars.
- Cubic-bezier mouse paths with 8–24
- Geolocation defaults to no override (instead of
{lat:0,lon:0}Null Island). - The in-page tools state global is
window[Symbol.for('dtmcp')]instead ofwindow.__dtmcp.
Trade-off: list_console_messages and get_console_message return empty under stealth, and the ConsoleFormatter falls back to its non-Universe-detailed mode. Pass --no-stealth to restore upstream behaviour.
Chrome launch flags
--enable-automationstripped from default args (zerosnavigator.webdriver).--disable-blink-features=AutomationControlledadded.- Hardcoded
--screen-info=3840x2160removed. - Default user-data-dir is
~/.cache/ghostframe-mcp/..., distinct from upstream's~/.cache/chrome-devtools-mcp/...so cookies, Cloudflare reputation, and the profile lock don't collide. pipe: trueis kept (over the detectable--remote-debugging-port).
Tool changes
Added: set_blocked_urls (CDP Network.setBlockedURLs).
Schema additions on existing tools:
evaluate_scriptand slimevaluateacceptworld: 'isolated' | 'main'. Default isisolatedfor stealth, except whenargs(element UIDs) are passed, in which case it falls back tomain(element handles can only be evaluated in the realm that created them).emulateacceptsuserAgentMetadata(JSON-encoded UA Client-Hints),locale, andtimezone, and routes UA/locale/timezone overrides through raw CDPEmulation.setUserAgentOverride+setLocaleOverride+setTimezoneOverride+Network.setExtraHTTPHeaderssonavigator.userAgent,Sec-CH-UA-*, andAccept-Languagestay coherent.
Removed: lighthouse_audit, take_memory_snapshot, load_memory_snapshot, get_memory_snapshot_details, performance_start_trace, performance_stop_trace, performance_analyze_insight. The lighthouse npm dep, the chrome-devtools-frontend heap-snapshot worker bundle, and the trace-processing/ module are also gone. Use upstream chrome-devtools-mcp for these.
Other
--usage-statisticsdefaults tofalse. Sending stealth-config telemetry to Google's Clearcut endpoint contradicts the fork posture.--proxy-serveraccepts authenticated proxies — see Proxy.- Package marked private; npm name is
ghostframe-mcp; bin entries areghostframe-mcp(server) andghostframe(CLI). Names are distinct from upstreamchrome-devtools-mcp/chrome-devtoolsso a global install never shadows upstream.
Setup
git clone <fork-url> ~/Documents/ghostframe-mcp
cd ~/Documents/ghostframe-mcp
npm install
npm run build
Register with Claude Code (user-scoped):
claude mcp add -s user ghostframe -- \
node /absolute/path/to/ghostframe-mcp/build/src/bin/ghostframe-mcp.js
Or as JSON in your MCP client config:
{
"mcpServers": {
"ghostframe": {
"command": "node",
"args": [
"/absolute/path/to/ghostframe-mcp/build/src/bin/ghostframe-mcp.js"
]
}
}
}
After pulling new commits, run npm run build. The MCP config does not change.
Requirements: Node.js v20.19+, Chrome stable (or another channel via --channel).
Side-by-side with upstream
The fork's npm name, bin entries, and default user-data-dir are all distinct from upstream so both packages can be installed and registered with the same MCP client at once. Add both servers to your client config:
{
"mcpServers": {
"chrome-devtools": {
"command": "npx",
"args": ["-y", "chrome-devtools-mcp@latest"]
},
"ghostframe": {
"command": "node",
"args": [
"/absolute/path/to/ghostframe-mcp/build/src/bin/ghostframe-mcp.js"
]
}
}
}
Pick which to invoke per task:
ghostframe— sites with bot management (Cloudflare, DataDome, AXS-style ticketing), anything wherenavigator.webdriver=truewould block, work that benefits from clean per-session state.chrome-devtools(upstream) — Lighthouse audits, performance tracing, heap snapshots, accessibility audits, trusted local pages.
Proxy
Proxies are off by default. Pass one with --proxy-server:
--proxy-server=203.0.113.7:8888 no auth
--proxy-server=203.0.113.7:8888:user:pass with basic auth (proxy-list format)
--proxy-server=http://203.0.113.7:8888 no auth, explicit scheme
--proxy-server=http://user:pass@203.0.113.7:8888 URL form with embedded auth
--proxy-server=socks5://proxy.example.com:1080 SOCKS5
--proxy-server=socks5://user:pass@proxy.example.com:1080 SOCKS5 with auth
Authenticated proxies use Puppeteer's page.authenticate() to answer the 407 challenge — Chrome strips inline user:pass@ from --proxy-server for security, so credentials are applied at the page-event layer rather than on the command line. Authentication is registered for every existing and future page in the browser.
To bake a proxy into the global MCP config, register a separate variant alongside the default:
claude mcp add -s user ghostframe-proxied -- \
node /absolute/path/to/ghostframe-mcp/build/src/bin/ghostframe-mcp.js \
--proxy-server=203.0.113.7:8888:user:pass
Then you have both ghostframe (no proxy) and ghostframe-proxied registered, and pick which to invoke per task. Credential rotation requires re-running claude mcp add; consider this trade-off before baking creds into the config.
Tools
- Input automation (9 tools)
- Navigation automation (6 tools)
- Emulation (2 tools)
- Network (3 tools)
- Debugging (5 tools)
- Extensions (5 tools)
Full schemas: docs/tool-reference.md. Slim mode (3 tools): docs/slim-tool-reference.md.
Configuration
-
--autoConnect/--auto-connectIf specified, automatically connects to a browser (Chrome 144+) running locally from the user data directory identified by the channel param (default channel is stable). Requires the remote debugging server to be started in the Chrome instance via chrome://inspect/#remote-debugging.- Type: boolean
- Default:
false
-
--browserUrl/--browser-url,-uConnect to a running, debuggable Chrome instance (e.g.http://127.0.0.1:9222). See README "Connecting to a running Chrome instance".- Type: string
-
--wsEndpoint/--ws-endpoint,-wWebSocket endpoint to connect to a running Chrome instance (e.g.,ws://127.0.0.1:9222/devtools/browser/{ID}). Alternative to --browserUrl.- Type: string
-
--wsHeaders/--ws-headersCustom headers for WebSocket connection in JSON format (e.g., '{"Authorization":"Bearer token"}'). Only works with --wsEndpoint.- Type: string
-
--headlessWhether to run in headless (no UI) mode.- Type: boolean
- Default:
false
-
--executablePath/--executable-path,-ePath to custom Chrome executable.- Type: string
-
--isolatedIf specified, creates a temporary user-data-dir that is automatically cleaned up after the browser is closed. Defaults to false.- Type: boolean
-
--userDataDir/--user-data-dirPath to the user data directory for Chrome. Default is $HOME/.cache/ghostframe-mcp/chrome-profile$CHANNEL_SUFFIX_IF_NON_STABLE.- Type: string
-
--channelSpecify a different Chrome channel that should be used. The default is the stable channel version.- Type: string
- Choices:
canary,dev,beta,stable
-
--logFile/--log-filePath to a file to write debug logs to. Set the env variableDEBUGto*to enable verbose logs. Useful for submitting bug reports.- Type: string
-
--viewportInitial viewport size for the Chrome instances started by the server. For example,1280x720. In headless mode, max size is 3840x2160px.- Type: string
-
--proxyServer/--proxy-serverProxy server for Chrome to route all browser traffic through. Accepts:host:port(no auth),host:port:user:pass(with basic auth — common proxy-list format),http://host:port,http://user:pass@host:port,socks5://host:port, orsocks5://user:pass@host:port. Authenticated proxies use Puppeteer's page.authenticate() to answer the 407 challenge — Chrome strips inline credentials from --proxy-server for security, so credentials are applied at the page-event layer, not on the command line.- Type: string
-
--acceptInsecureCerts/--accept-insecure-certsIf enabled, ignores errors relative to self-signed and expired certificates. Use with caution.- Type: boolean
-
--experimentalVision/--experimental-visionWhether to enable coordinate-based tools such as click_at(x,y). Usually requires a computer-use model able to produce accurate coordinates by looking at screenshots.- Type: boolean
-
--experimentalScreencast/--experimental-screencastExposes experimental screencast tools (requires ffmpeg). Install ffmpeg from https://www.ffmpeg.org/download.html and ensure it is on the MCP server PATH.- Type: boolean
-
--experimentalFfmpegPath/--experimental-ffmpeg-pathPath to ffmpeg executable for screencast recording.- Type: string
-
--experimentalWebmcp/--experimental-webmcpSet to true to enable debugging WebMCP tools. Requires Chrome 149+ with the following flags:--enable-features=WebMCPTesting,DevToolsWebMCPSupport- Type: boolean
-
--chromeArg/--chrome-argAdditional arguments for Chrome. Only applies when Chrome is launched by ghostframe-mcp.- Type: array
-
--ignoreDefaultChromeArg/--ignore-default-chrome-argExplicitly disable default arguments for Chrome. Only applies when Chrome is launched by ghostframe-mcp.- Type: array
-
--categoryEmulation/--category-emulationSet to false to exclude tools related to emulation.- Type: boolean
- Default:
true
-
--categoryPerformance/--category-performanceSet to false to exclude tools related to performance.- Type: boolean
- Default:
true
-
--categoryNetwork/--category-networkSet to false to exclude tools related to network.- Type: boolean
- Default:
true
-
--categoryExtensions/--category-extensionsSet to true to include tools related to extensions. Note: This feature is currently only supported with a pipe connection. autoConnect, browserUrl, and wsEndpoint are not supported with this feature until 149 will be released.- Type: boolean
- Default:
false
-
--stealthStealth posture (default: true). Skips initialization of the chrome-devtools-frontend Universe (which forces Runtime.enable + Debugger.enable on every page and is the single largest CDP fingerprint) and the page console / pageerror / Runtime.exceptionThrown listeners that implicitly enable Runtime. Trade-off: list_console_messages and get_console_message return empty results, and the ConsoleFormatter degrades to its non-DevTools-detailed mode. Set to false to restore the upstream chrome-devtools-mcp behavior.- Type: boolean
- Default:
true
-
--usageStatistics/--usage-statisticsSend usage statistics to Google Clearcut. Off by default in this stealth fork (sending stealth-config telemetry to Google contradicts the fork posture). Set to true to opt back in. Also disabled ifCHROME_DEVTOOLS_MCP_NO_USAGE_STATISTICSorCIenv variables are set.- Type: boolean
- Default:
false
-
--slimExposes a "slim" set of 3 tools covering navigation, script execution and screenshots only. Useful for basic browser tasks.- Type: boolean
-
--redactNetworkHeaders/--redact-network-headersIf true, redacts some of the network headers considered senstive before returning to the client.- Type: boolean
- Default:
false
Pass options via the args array in the MCP JSON config. Run node build/src/bin/ghostframe-mcp.js --help to print the full list.
Connecting to a running Chrome instance
Same as upstream — useful when you want manual and agent-driven sessions to share state, or when the agent runs inside a sandbox. Two paths:
--auto-connect(Chrome 144+) — connect to a Chrome instance you started yourself. In Chrome, navigate tochrome://inspect/#remote-debuggingto enable remote debugging, then start the MCP server with--auto-connect.--browser-url=http://127.0.0.1:9222— connect to a Chrome started with--remote-debugging-port=9222. Chrome requires a non-default--user-data-dirwhen--remote-debugging-portis set.
When connecting to a running Chrome, the fork does not launch its own browser, and the launch-time stealth flags (--enable-automation strip, polyfill injection, etc.) do not apply — the connected Chrome is whatever it was when started. The Universe gate, console-listener gate, and humanizers still apply because they live in the McpContext / tool layers.
Docs and skills
docs/detection-signals.md— six-layer detection map (CDP / launch / DOM / fingerprint / behavioral / network) with citations.docs/stealth-configuration.md— flag posture, Universe gate trade-off, isolated-world routing, persona bundling, polyfill list.docs/design-principles.md,docs/cli.md,docs/troubleshooting.md— adapted from upstream for stealth scope.skills/stealth-launch/— pre-flight checklist before driving a stealth-protected site.skills/detection-testing/— sweep workflow forbot.sannysoft.com,arh.antoinevastel.com,creepjs,pixelscan.skills/diagnose-bot-block/— six-layer walk for "blocked but detectors pass".skills/borrow-stealth-feature/— port workflow for borrowing primitives fromvibheksoni/stealth-browser-mcpandnodriver.skills/humanized-input/— humanisation distributions and persona-coherence callouts.skills/ghostframe/,skills/ghostframe-cli/,skills/troubleshooting/— adapted from upstream.
Disclaimer
This fork exposes browser content to MCP clients. Don't share sensitive or personal information you wouldn't share with an MCP-connected agent. Intended for personal use against sites you own or have authorisation to test.