js-reverse-mcp-debugging

v2026.09.25

JavaScript reverse engineering and browser debugging MCP server with anti-detection and agent-first tooling

GitHub
安装命令
npx skhub add reason-machines/js-reverse-mcp-debugging
Markdown
SKILL.md

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:

  1. Launch Chrome with debugging:

    # macOS
    /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --remote-debugging-port=9222 --user-data-dir=/tmp/chrome-debug
    
    # Windows
    "C:\Program Files\Google\Chrome\Application\chrome.exe" --remote-debugging-port=9222 --user-data-dir="%TEMP%\chrome-debug"
    
  2. Configure MCP:

    {
      "mcpServers": {
        "js-reverse": {
          "command": "npx",
          "args": ["js-reverse-mcp", "--browserUrl", "http://127.0.0.1:9222"]
        }
      }
    }
    

MCP Tools (21)

Page & Navigation

ToolPurpose
select_pageList open pages or switch debugging context by index
new_pageCreate new page and navigate to URL
navigate_pageNavigate, back, forward, or refresh
select_frameList/select iframe execution context
take_screenshotCapture page screenshot

Script Analysis

ToolPurpose
list_scriptsList all loaded JavaScript files
get_script_sourceFetch script source (supports line ranges, character offsets)
save_script_sourceSave full script to local file (large/minified/WASM)
search_in_sourcesSearch all scripts for string/regex

Breakpoints & Execution

ToolPurpose
set_breakpoint_on_textSet breakpoint by searching code text (works in minified code)
break_on_xhrSet XHR/Fetch breakpoint by URL pattern
remove_breakpointRemove by ID, URL, or all; auto-resumes execution
list_breakpointsList all active breakpoints
get_paused_infoGet pause state, call stack, scope variables
pause_or_resumeToggle pause/resume
stepStep over/into/out, returns location + source context

Network & WebSocket

ToolPurpose
list_network_requestsList requests or get single request details by reqid
get_request_initiatorGet JavaScript call stack for network request
get_websocket_messagesList connections, analyze message patterns, get message details

Inspection

ToolPurpose
evaluate_scriptExecute JavaScript (supports breakpoint context, main world, save results/binary to file)
list_console_messagesList console messages or get single message by msgid

Common Workflows

1. Basic Reverse Engineering

// User: "Debug the encryption on example.com"

// Step 1: Open target page
await use_mcp_tool("js-reverse", "new_page", {
  url: "https://example.com"
});

// Step 2: Find encryption functions
const searchResults = await use_mcp_tool("js-reverse", "search_in_sources", {
  query: "encrypt|crypto|AES|cipher",
  isRegex: true
});

// Step 3: Set breakpoint on encryption function
await use_mcp_tool("js-reverse", "set_breakpoint_on_text", {
  searchText: "function encrypt(data)",
  scriptUrl: searchResults[0].url
});

// Step 4: Trigger action (user does this in browser or via evaluate_script)
// ... breakpoint hits ...

// Step 5: Inspect paused state
const pausedInfo = await use_mcp_tool("js-reverse", "get_paused_info", {});
// Returns: call stack, scope variables, current location

// Step 6: Evaluate in breakpoint context
const params = await use_mcp_tool("js-reverse", "evaluate_script", {
  expression: "data",
  returnByValue: true
});

// Step 7: Step through execution
await use_mcp_tool("js-reverse", "step", {
  action: "into"  // or "over", "out"
});

2. Network Request Analysis

// User: "Find where this API request is initiated"

// Step 1: List network requests
const requests = await use_mcp_tool("js-reverse", "list_network_requests", {});

// Step 2: Find target request
const apiRequest = requests.find(r => r.url.includes("/api/user"));

// Step 3: Get JavaScript call stack
const initiator = await use_mcp_tool("js-reverse", "get_request_initiator", {
  reqid: apiRequest.reqid
});
// Returns: full JS stack trace from initiation point

// Step 4: Set breakpoint at initiation
await use_mcp_tool("js-reverse", "set_breakpoint_on_text", {
  searchText: initiator.callFrames[0].functionName,
  scriptUrl: initiator.callFrames[0].url
});

3. XHR/Fetch Interception

// User: "Break on all requests to /api/encrypt"

// Set XHR breakpoint with URL pattern
await use_mcp_tool("js-reverse", "break_on_xhr", {
  urlPattern: "*/api/encrypt*"
});

// Execution will pause before matching XHR/fetch
// Then inspect request body, headers, call stack
const pausedInfo = await use_mcp_tool("js-reverse", "get_paused_info", {});

// Evaluate request payload
const payload = await use_mcp_tool("js-reverse", "evaluate_script", {
  expression: "arguments[0]",  // xhr.send() argument
  returnByValue: true
});

4. WebSocket Protocol Analysis

// User: "Analyze the WebSocket messages for this trading site"

// Step 1: List WebSocket connections
const wsData = await use_mcp_tool("js-reverse", "get_websocket_messages", {
  action: "list"
});

// Step 2: Analyze message patterns
const analysis = await use_mcp_tool("js-reverse", "get_websocket_messages", {
  action: "analyze",
  wsid: wsData.connections[0].wsid
});
// Returns: message type distribution, size stats, timing patterns

// Step 3: Inspect specific message
const message = await use_mcp_tool("js-reverse", "get_websocket_messages", {
  action: "get",
  wsid: wsData.connections[0].wsid,
  msgid: "msg_123"
});
// Returns: full payload, timestamp, direction (sent/received)

5. Minified Code Debugging

// User: "Set breakpoint on the obfuscated validation function"

// Step 1: Search for function signature in minified code
const results = await use_mcp_tool("js-reverse", "search_in_sources", {
  query: "validate.*password",
  isRegex: true
});

// Step 2: Get context around match
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
});

// Step 3: Set breakpoint by text match (works in minified code)
await use_mcp_tool("js-reverse", "set_breakpoint_on_text", {
  searchText: results[0].match.line.trim(),
  scriptUrl: results[0].url,
  condition: "password.length > 0"  // optional conditional breakpoint
});

6. Scope Variable Inspection

// After hitting breakpoint, inspect all accessible variables

const pausedInfo = await use_mcp_tool("js-reverse", "get_paused_info", {});

// pausedInfo.scopeChain contains:
// - local variables
// - closure variables
// - global scope

// Evaluate complex expressions in current scope
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

// User: "Save this 5MB minified bundle for analysis"

const scripts = await use_mcp_tool("js-reverse", "list_scripts", {});
const targetScript = scripts.find(s => s.url.includes("bundle.min.js"));

// Save to local file (more reliable than get_script_source for large files)
await use_mcp_tool("js-reverse", "save_script_source", {
  scriptId: targetScript.scriptId,
  outputPath: "/tmp/bundle.min.js"
});

// Now analyze with external tools or search within it
const matches = await use_mcp_tool("js-reverse", "search_in_sources", {
  query: "apiKey.*=.*['\"]([^'\"]+)['\"]",
  isRegex: true,
  scriptId: targetScript.scriptId
});

8. Multi-Page Debugging

// User: "Debug login flow across multiple redirects"

// Step 1: List all open pages
const pages = await use_mcp_tool("js-reverse", "select_page", {});

// Step 2: Switch to login page
await use_mcp_tool("js-reverse", "select_page", {
  index: 0
});

// Step 3: Set breakpoint on form submit
await use_mcp_tool("js-reverse", "set_breakpoint_on_text", {
  searchText: "submitLogin"
});

// Step 4: After redirect, switch to new page
const updatedPages = await use_mcp_tool("js-reverse", "select_page", {});
await use_mcp_tool("js-reverse", "select_page", {
  index: updatedPages.length - 1
});

// Step 5: Continue debugging in new context
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
# or for cloak mode:
rm -rf ~/.cache/chrome-devtools-mcp/cloak-profile

Breakpoint Not Hitting

  1. Check if script is loaded:

    const scripts = await use_mcp_tool("js-reverse", "list_scripts", {});
    // Verify target script is in list
    
  2. 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"
    });
    
  3. List active breakpoints:

    const breakpoints = await use_mcp_tool("js-reverse", "list_breakpoints", {});
    
  4. 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:

  1. Navigate to trigger script load:

    await use_mcp_tool("js-reverse", "navigate_page", {
      action: "goto",
      url: "https://example.com/trigger-page"
    });
    
  2. Wait for script load, then list:

    // Give page time to load
    await new Promise(resolve => setTimeout(resolve, 2000));
    const scripts = await use_mcp_tool("js-reverse", "list_scripts", {});
    
  3. 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:

  1. Ensure page is loaded and WebSocket is connected:

    const wsData = await use_mcp_tool("js-reverse", "get_websocket_messages", {
      action: "list"
    });
    // Check if connections array is populated
    
  2. Trigger WebSocket traffic in browser (message capture is passive)

  3. List connections includes lifecycle events; messages are captured automatically once connection is established

Evaluate Script Fails

Common issues:

  1. Execution context invalid — Make sure you're evaluating in the right frame:

    // List frames first
    const frames = await use_mcp_tool("js-reverse", "select_frame", {});
    
    // Select target frame
    await use_mcp_tool("js-reverse", "select_frame", {
      index: 1  // switch to iframe
    });
    
    // Now evaluate
    await use_mcp_tool("js-reverse", "evaluate_script", {
      expression: "window.secretVar"
    });
    
  2. 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
    });
    
  3. Reference error — Variable not in scope; check scopeChain:

    const pausedInfo = await use_mcp_tool("js-reverse", "get_paused_info", {});
    // Inspect pausedInfo.scopeChain to see available variables
    

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

  1. Start simple: Use default mode; only add --cloak if blocked
  2. Persistent sessions: Default profile saves login state (use --isolated for clean state)
  3. Text-based breakpoints: More reliable than line numbers in minified/dynamic code
  4. Save large sources: Use save_script_source instead of get_script_source for big files
  5. Scope inspection: Always check get_paused_info().scopeChain before evaluating variables
  6. Network initiators: Use get_request_initiator to find where requests originate
  7. 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).

发现
标签

此技能尚未发布标签。

版本
最新版本元数据

版本

v2026.09.25

发布时间

2026年9月25日

分类

未分类

许可证

NOASSERTION

源路径

skills/js-reverse-mcp-debugging

默认分支

main

最新提交

329e67c

Tree SHA

01fd22f