| name | js-reverse-mcp-debugging |
| description | JavaScript reverse engineering and browser debugging MCP server with anti-detection and agent-first tooling |
| triggers | ["debug javascript on this website","set a breakpoint on the encryption function","analyze websocket messages","find where this request is coming from","search for crypto functions in the page scripts","inspect the call stack at this breakpoint","list all loaded scripts on this page","capture network request initiators"] |
js-reverse-mcp-debugging
Skill by ara.so — MCP Skills collection.
Overview
js-reverse-mcp is an MCP server that gives AI agents full JavaScript debugging capabilities: breakpoints, call stacks, scope inspection, network analysis, and WebSocket message capture. Built on Patchright (CDP protocol anti-detection) with optional CloakBrowser (49 C++ fingerprint patches) for strong anti-bot sites.
Key features:
- Headful debugging — visible browser, breakpoints, step-through, call stacks
- Persistent sessions — cookies/localStorage survive restarts
- Dual anti-detection — Patchright (protocol layer) + optional CloakBrowser (binary patches)
- 21 MCP tools — script analysis, breakpoint control, network inspection, WebSocket analysis
- Zero JS injection — no
Object.defineProperty hacks that leak automation signals
Installation
NPX (Recommended)
Add to your MCP client configuration:
{
"mcpServers": {
"js-reverse": {
"command": "npx",
"args": ["js-reverse-mcp"]
}
}
}
Claude Code:
claude mcp add js-reverse npx js-reverse-mcp
Codex:
codex mcp add js-reverse -- npx js-reverse-mcp
Local Install
git clone https://github.com/zhizhuodemao/js-reverse-mcp.git
cd js-reverse-mcp
npm install
npm run build
Then configure with local path:
{
"mcpServers": {
"js-reverse": {
"command": "node",
"args": ["/path/to/js-reverse-mcp/build/src/index.js"]
}
}
}
Configuration Options
CLI flags (all optional):
--cloak — Use CloakBrowser binary with 49 C++ fingerprint patches (auto-downloads ~200MB on first run)
--isolated — Use temporary profile (no persistent cookies/localStorage)
--browserUrl, -u — Connect to existing Chrome instance (CDP endpoint, e.g. http://127.0.0.1:9222)
--logFile — Write debug logs to file (use with DEBUG=* env var)
Common Configurations
Default (System Chrome + Persistent Login):
{
"mcpServers": {
"js-reverse": {
"command": "npx",
"args": ["js-reverse-mcp"]
}
}
}
Anti-Bot Sites (Cloudflare, DataDome, FingerprintJS):
Pre-download CloakBrowser binary first (one-time, ~30-60s):
npx cloakbrowser install
Then configure:
{
"mcpServers": {
"js-reverse-cloak": {
"command": "npx",
"args": ["js-reverse-mcp", "--cloak"]
}
}
}
Dual Setup (Switch Based on Target):
{
"mcpServers": {
"js-reverse": {
"command": "npx",
"args": ["js-reverse-mcp"]
},
"js-reverse-cloak": {
"command": "npx",
"args": ["js-reverse-mcp", "--cloak"]
}
}
}
Connect to Running Chrome:
-
Launch Chrome with debugging:
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --remote-debugging-port=9222 --user-data-dir=/tmp/chrome-debug
"C:\Program Files\Google\Chrome\Application\chrome.exe" --remote-debugging-port=9222 --user-data-dir="%TEMP%\chrome-debug"
-
Configure MCP:
{
"mcpServers": {
"js-reverse": {
"command": "npx",
"args": ["js-reverse-mcp", "--browserUrl", "http://127.0.0.1:9222"]
}
}
}
MCP Tools (21)
Page & Navigation
| Tool | Purpose |
|---|
select_page | List open pages or switch debugging context by index |
new_page | Create new page and navigate to URL |
navigate_page | Navigate, back, forward, or refresh |
select_frame | List/select iframe execution context |
take_screenshot | Capture page screenshot |
Script Analysis
| Tool | Purpose |
|---|
list_scripts | List all loaded JavaScript files |
get_script_source | Fetch script source (supports line ranges, character offsets) |
save_script_source | Save full script to local file (large/minified/WASM) |
search_in_sources | Search all scripts for string/regex |
Breakpoints & Execution
| Tool | Purpose |
|---|
set_breakpoint_on_text | Set breakpoint by searching code text (works in minified code) |
break_on_xhr | Set XHR/Fetch breakpoint by URL pattern |
remove_breakpoint | Remove by ID, URL, or all; auto-resumes execution |
list_breakpoints | List all active breakpoints |
get_paused_info | Get pause state, call stack, scope variables |
pause_or_resume | Toggle pause/resume |
step | Step over/into/out, returns location + source context |
Network & WebSocket
| Tool | Purpose |
|---|
list_network_requests | List requests or get single request details by reqid |
get_request_initiator | Get JavaScript call stack for network request |
get_websocket_messages | List connections, analyze message patterns, get message details |
Inspection
| Tool | Purpose |
|---|
evaluate_script | Execute JavaScript (supports breakpoint context, main world, save results/binary to file) |
list_console_messages | List console messages or get single message by msgid |
Common Workflows
1. Basic Reverse Engineering
await use_mcp_tool("js-reverse", "new_page", {
url: "https://example.com"
});
const searchResults = await use_mcp_tool("js-reverse", "search_in_sources", {
query: "encrypt|crypto|AES|cipher",
isRegex: true
});
await use_mcp_tool("js-reverse", "set_breakpoint_on_text", {
searchText: "function encrypt(data)",
scriptUrl: searchResults[0].url
});
const pausedInfo = await use_mcp_tool("js-reverse", "get_paused_info", {});
const params = await use_mcp_tool("js-reverse", "evaluate_script", {
expression: "data",
returnByValue:
});
(, , {
:
});
2. Network Request Analysis
const requests = await use_mcp_tool("js-reverse", "list_network_requests", {});
const apiRequest = requests.find(r => r.url.includes("/api/user"));
const initiator = await use_mcp_tool("js-reverse", "get_request_initiator", {
reqid: apiRequest.reqid
});
await use_mcp_tool("js-reverse", "set_breakpoint_on_text", {
searchText: initiator.callFrames[0].functionName,
scriptUrl: initiator.callFrames[0].url
});
3. XHR/Fetch Interception
await use_mcp_tool("js-reverse", "break_on_xhr", {
urlPattern: "*/api/encrypt*"
});
const pausedInfo = await use_mcp_tool("js-reverse", "get_paused_info", {});
const payload = await use_mcp_tool("js-reverse", "evaluate_script", {
expression: "arguments[0]",
returnByValue: true
});
4. WebSocket Protocol Analysis
const wsData = await use_mcp_tool("js-reverse", "get_websocket_messages", {
action: "list"
});
const analysis = await use_mcp_tool("js-reverse", "get_websocket_messages", {
action: "analyze",
wsid: wsData.connections[0].wsid
});
const message = await use_mcp_tool("js-reverse", "get_websocket_messages", {
action: "get",
wsid: wsData.connections[0].wsid,
msgid: "msg_123"
});
5. Minified Code Debugging
const results = await use_mcp_tool("js-reverse", "search_in_sources", {
query: "validate.*password",
isRegex: true
});
const source = await use_mcp_tool("js-reverse", "get_script_source", {
scriptId: results[0].scriptId,
startOffset: results[0].match.offset - 200,
endOffset: results[0].match.offset + 200
});
await use_mcp_tool("js-reverse", "set_breakpoint_on_text", {
searchText: results[0].match.line.trim(),
scriptUrl: results[0].url,
condition: "password.length > 0"
});
6. Scope Variable Inspection
const pausedInfo = await use_mcp_tool("js-reverse", "get_paused_info", {});
const result = await use_mcp_tool("js-reverse", "evaluate_script", {
expression: "Object.keys(this).filter(k => k.startsWith('_'))",
callFrameId: pausedInfo.callFrames[0].callFrameId,
returnByValue: true
});
7. Save Large Script Sources
const scripts = await use_mcp_tool("js-reverse", "list_scripts", {});
const targetScript = scripts.find(s => s.url.includes("bundle.min.js"));
await use_mcp_tool("js-reverse", "save_script_source", {
scriptId: targetScript.scriptId,
outputPath: "/tmp/bundle.min.js"
});
const matches = await use_mcp_tool("js-reverse", "search_in_sources", {
query: "apiKey.*=.*['\"]([^'\"]+)['\"]",
isRegex: true,
scriptId: targetScript.scriptId
});
8. Multi-Page Debugging
const pages = await use_mcp_tool("js-reverse", "select_page", {});
await use_mcp_tool("js-reverse", "select_page", {
index: 0
});
await use_mcp_tool("js-reverse", "set_breakpoint_on_text", {
searchText: "submitLogin"
});
const updatedPages = await use_mcp_tool("js-reverse", "select_page", {});
await use_mcp_tool("js-reverse", "select_page", {
index: updatedPages.length - 1
});
const scripts = await use_mcp_tool("js-reverse", "list_scripts", {});
Troubleshooting
Bot Detection / Access Denied
Symptoms: Site returns 403, Cloudflare challenge loops, Zhihu 40362 error
Solution 1: Try isolated profile first (rules out state pollution)
"args": ["js-reverse-mcp", "--isolated"]
Solution 2: Enable CloakBrowser (49 fingerprint patches)
Pre-download binary:
npx cloakbrowser install
Configure:
"args": ["js-reverse-mcp", "--cloak"]
Solution 3: Clear persistent profile (loses login state)
rm -rf ~/.cache/chrome-devtools-mcp/chrome-profile
rm -rf ~/.cache/chrome-devtools-mcp/cloak-profile
Breakpoint Not Hitting
-
Check if script is loaded:
const scripts = await use_mcp_tool("js-reverse", "list_scripts", {});
-
Use text-based breakpoint (works in minified code):
await use_mcp_tool("js-reverse", "set_breakpoint_on_text", {
searchText: "unique_code_snippet",
scriptUrl: "target.js"
});
-
List active breakpoints:
const breakpoints = await use_mcp_tool("js-reverse", "list_breakpoints", {});
-
Check if execution is paused elsewhere:
const pausedInfo = await use_mcp_tool("js-reverse", "get_paused_info", {});
Cannot Find Script
If dynamic/lazy-loaded scripts don't appear:
-
Navigate to trigger script load:
await use_mcp_tool("js-reverse", "navigate_page", {
action: "goto",
url: "https://example.com/trigger-page"
});
-
Wait for script load, then list:
await new Promise(resolve => setTimeout(resolve, 2000));
const scripts = await use_mcp_tool("js-reverse", "list_scripts", {});
-
Search across all sources:
const results = await use_mcp_tool("js-reverse", "search_in_sources", {
query: "function_name"
});
WebSocket Messages Not Captured
If get_websocket_messages returns empty:
-
Ensure page is loaded and WebSocket is connected:
const wsData = await use_mcp_tool("js-reverse", "get_websocket_messages", {
action: "list"
});
-
Trigger WebSocket traffic in browser (message capture is passive)
-
List connections includes lifecycle events; messages are captured automatically once connection is established
Evaluate Script Fails
Common issues:
-
Execution context invalid — Make sure you're evaluating in the right frame:
const frames = await use_mcp_tool("js-reverse", "select_frame", {});
await use_mcp_tool("js-reverse", "select_frame", {
index: 1
});
await use_mcp_tool("js-reverse", "evaluate_script", {
expression: "window.secretVar"
});
-
Paused in wrong call frame — Specify callFrameId:
const pausedInfo = await use_mcp_tool("js-reverse", "get_paused_info", {});
await use_mcp_tool("js-reverse", "evaluate_script", {
expression: "localVar",
callFrameId: pausedInfo.callFrames[0].callFrameId
});
-
Reference error — Variable not in scope; check scopeChain:
const pausedInfo = await use_mcp_tool("js-reverse", "get_paused_info", {});
Anti-Detection Layer Details
Protocol Layer (Always Active):
- Patchright removes
Runtime.enable, Console.enable CDP calls
- Script evaluation in isolated world
- Automation launch flags stripped
Binary Layer (With --cloak):
- 49 C++ patches:
navigator.webdriver, canvas, WebGL, audio, GPU, fonts, screen, WebRTC, TLS
- Custom Chromium build (no Google services, no Web Store)
- Persistent fingerprint identity per profile
Navigation Layer (Always Active):
- Silent CDP navigation (no early
Network.enable/Debugger.enable)
- Google referer on
new_page
- Real viewport (no fake 1280×720)
When to use --cloak: Only when protocol-layer evasion fails. See project docs for details.
Best Practices
- Start simple: Use default mode; only add
--cloak if blocked
- Persistent sessions: Default profile saves login state (use
--isolated for clean state)
- Text-based breakpoints: More reliable than line numbers in minified/dynamic code
- Save large sources: Use
save_script_source instead of get_script_source for big files
- Scope inspection: Always check
get_paused_info().scopeChain before evaluating variables
- Network initiators: Use
get_request_initiator to find where requests originate
- WebSocket analysis: Use
analyze action first to understand message patterns before diving into individual messages
Security Warning
This tool exposes browser content to MCP clients with full inspection/modification capabilities. Do not use on pages with sensitive information (passwords, payment details, private data).