real-browser-mcp-server 1.3.1 → 1.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -15,7 +15,7 @@ This server is **100% compatible with all major AI IDEs** (Cursor, VS Code, Clin
15
15
 
16
16
  * **Undetected Browser Engine**: Powered by **Patchright Chromium**, bypassing modern fingerprinting checks (does not expose automation indicators or Webdriver/BiDi flags).
17
17
  * **Integrated Ad & Tracker Blocker**: Utilizes `@ghostery/adblocker-playwright` with asynchronous pre-compiled filter caching to `adblocker.bin`, blocking ads and speed-bumps completely offline.
18
- * **Human-like Interactions**: Integrates **playwright-ghost** (Bézier curves auto-hooking) to transparently simulate human mouse movements, velocity, and natural hover-before-click behaviors.
18
+ * **Human-like Interactions**: Integrates **ghost-cursor-patchright** (Bézier curves) to transparently simulate human mouse movements, velocity, and natural hover-before-click behaviors.
19
19
  * **Turnstile Auto-Solver**: Seamlessly detects and bypasses Cloudflare Turnstile widgets.
20
20
  * **Anti-Race Condition Guards**: Robust state-guards ensure popup blockers, shims, and adblockers attach exactly once per page, preventing context destruction.
21
21
 
package/lib/cjs/index.js CHANGED
@@ -1,9 +1,8 @@
1
1
  const { PlaywrightBlocker } = require("@ghostery/adblocker-playwright");
2
2
  const { pageController } = require("./module/pageController.js");
3
3
 
4
- // Dynamically load pure ESM playwright-ghost to be fully compatible with CommonJS
5
- const playwrightGhostPromise = import("playwright-ghost/patchright");
6
- const recommendedPromise = import("playwright-ghost/plugins/recommended");
4
+ const { chromium } = require("patchright");
5
+ const { createCursor } = require("ghost-cursor-patchright");
7
6
  const fs = require('fs');
8
7
  const path = require('path');
9
8
 
@@ -72,7 +71,7 @@ function getDefaultHeadless() {
72
71
  return envHeadless === 'true';
73
72
  }
74
73
 
75
- function applyPuppeteerShims(browser, page) {
74
+ function applyBrowserShims(browser, page) {
76
75
  if (page._shimsApplied) return page;
77
76
  page._shimsApplied = true;
78
77
 
@@ -87,7 +86,7 @@ function applyPuppeteerShims(browser, page) {
87
86
  });
88
87
  }
89
88
 
90
- // Cookie shims (Puppeteer Playwright context)
89
+ // Cookie shims (Compatibility adapter for Playwright context)
91
90
  if (!page.cookies) {
92
91
  page.cookies = async (urls) => {
93
92
  return await page.context().cookies(urls ? (Array.isArray(urls) ? urls : [urls]) : []);
@@ -133,21 +132,43 @@ function applyPuppeteerShims(browser, page) {
133
132
  };
134
133
  }
135
134
 
136
- // Ghost Cursor integration via playwright-ghost auto-hooking
135
+ // Ghost Cursor integration via ghost-cursor-patchright
136
+ const cursorPromise = createCursor(page).catch(err => {
137
+ console.error("Failed to create cursor:", err);
138
+ return null;
139
+ });
140
+
137
141
  page.realCursor = {
138
142
  move: async (selector, options = {}) => {
139
143
  try {
140
- await page.hover(selector, options);
144
+ const cursor = await cursorPromise;
145
+ if (cursor) {
146
+ await cursor.move(selector, options);
147
+ } else {
148
+ await page.hover(selector, options);
149
+ }
141
150
  } catch (e) {
142
151
  // Silently fallback if element is not found
152
+ try {
153
+ await page.hover(selector, options);
154
+ } catch (err) {}
143
155
  }
144
156
  }
145
157
  };
146
158
  page.realClick = async (selector, options = {}) => {
147
- await page.click(selector, options);
159
+ try {
160
+ const cursor = await cursorPromise;
161
+ if (cursor) {
162
+ await cursor.click(selector, options);
163
+ } else {
164
+ await page.click(selector, options);
165
+ }
166
+ } catch (e) {
167
+ await page.click(selector, options);
168
+ }
148
169
  };
149
170
 
150
- // Mouse wheel shim (Puppeteer object Playwright positional args)
171
+ // Mouse wheel shim (Adapter for Playwright positional args)
151
172
  if (page.mouse && page.mouse.wheel) {
152
173
  const originalWheel = page.mouse.wheel.bind(page.mouse);
153
174
  page.mouse.wheel = async (x, y) => {
@@ -215,16 +236,10 @@ async function connect({
215
236
  ...args
216
237
  ];
217
238
 
218
- // Load the dynamic ES Module imports
219
- const { default: playwright } = await playwrightGhostPromise;
220
- const { default: recommended } = await recommendedPromise;
221
- const { chromium } = playwright;
222
-
223
239
  const browser = await chromium.launch({
224
240
  headless,
225
241
  args: chromiumArgs,
226
- proxy: playwrightProxy,
227
- plugins: [recommended()]
242
+ proxy: playwrightProxy
228
243
  });
229
244
 
230
245
  if (xvfbInstance) {
@@ -255,7 +270,7 @@ async function connect({
255
270
 
256
271
  let page = await context.newPage();
257
272
 
258
- applyPuppeteerShims(browser, page);
273
+ applyBrowserShims(browser, page);
259
274
 
260
275
  page = await pageController({
261
276
  browser,
@@ -265,7 +280,7 @@ async function connect({
265
280
  });
266
281
 
267
282
  context.on('page', async (newPage) => {
268
- applyPuppeteerShims(browser, newPage);
283
+ applyBrowserShims(browser, newPage);
269
284
  await pageController({
270
285
  browser,
271
286
  page: newPage,
package/lib/esm/index.mjs CHANGED
@@ -1,6 +1,5 @@
1
- import playwright from "playwright-ghost/patchright";
2
- import recommended from "playwright-ghost/plugins/recommended";
3
- const { chromium } = playwright;
1
+ import { chromium } from "patchright";
2
+ import { createCursor } from "ghost-cursor-patchright";
4
3
  import { PlaywrightBlocker } from "@ghostery/adblocker-playwright";
5
4
  import { pageController } from "./module/pageController.mjs";
6
5
  import { fileURLToPath } from 'url';
@@ -76,7 +75,7 @@ function getDefaultHeadless() {
76
75
  return envHeadless === 'true';
77
76
  }
78
77
 
79
- function applyPuppeteerShims(browser, page) {
78
+ function applyBrowserShims(browser, page) {
80
79
  if (page._shimsApplied) return page;
81
80
  page._shimsApplied = true;
82
81
 
@@ -91,7 +90,7 @@ function applyPuppeteerShims(browser, page) {
91
90
  });
92
91
  }
93
92
 
94
- // Cookie shims (Puppeteer Playwright context)
93
+ // Cookie shims (Compatibility adapter for Playwright context)
95
94
  if (!page.cookies) {
96
95
  page.cookies = async (urls) => {
97
96
  return await page.context().cookies(urls ? (Array.isArray(urls) ? urls : [urls]) : []);
@@ -137,21 +136,43 @@ function applyPuppeteerShims(browser, page) {
137
136
  };
138
137
  }
139
138
 
140
- // Ghost Cursor integration via playwright-ghost auto-hooking
139
+ // Ghost Cursor integration via ghost-cursor-patchright
140
+ const cursorPromise = createCursor(page).catch(err => {
141
+ console.error("Failed to create cursor:", err);
142
+ return null;
143
+ });
144
+
141
145
  page.realCursor = {
142
146
  move: async (selector, options = {}) => {
143
147
  try {
144
- await page.hover(selector, options);
148
+ const cursor = await cursorPromise;
149
+ if (cursor) {
150
+ await cursor.move(selector, options);
151
+ } else {
152
+ await page.hover(selector, options);
153
+ }
145
154
  } catch (e) {
146
155
  // Silently fallback if element is not found
156
+ try {
157
+ await page.hover(selector, options);
158
+ } catch (err) {}
147
159
  }
148
160
  }
149
161
  };
150
162
  page.realClick = async (selector, options = {}) => {
151
- await page.click(selector, options);
163
+ try {
164
+ const cursor = await cursorPromise;
165
+ if (cursor) {
166
+ await cursor.click(selector, options);
167
+ } else {
168
+ await page.click(selector, options);
169
+ }
170
+ } catch (e) {
171
+ await page.click(selector, options);
172
+ }
152
173
  };
153
174
 
154
- // Mouse wheel shim (Puppeteer object Playwright positional args)
175
+ // Mouse wheel shim (Adapter for Playwright positional args)
155
176
  if (page.mouse && page.mouse.wheel) {
156
177
  const originalWheel = page.mouse.wheel.bind(page.mouse);
157
178
  page.mouse.wheel = async (x, y) => {
@@ -221,8 +242,7 @@ export async function connect({
221
242
  const browser = await chromium.launch({
222
243
  headless,
223
244
  args: chromiumArgs,
224
- proxy: playwrightProxy,
225
- plugins: [recommended()]
245
+ proxy: playwrightProxy
226
246
  });
227
247
 
228
248
  if (xvfbInstance) {
@@ -253,7 +273,7 @@ export async function connect({
253
273
 
254
274
  let page = await context.newPage();
255
275
 
256
- applyPuppeteerShims(browser, page);
276
+ applyBrowserShims(browser, page);
257
277
 
258
278
  page = await pageController({
259
279
  browser,
@@ -263,7 +283,7 @@ export async function connect({
263
283
  });
264
284
 
265
285
  context.on('page', async (newPage) => {
266
- applyPuppeteerShims(browser, newPage);
286
+ applyBrowserShims(browser, newPage);
267
287
  await pageController({
268
288
  browser,
269
289
  page: newPage,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "real-browser-mcp-server",
3
- "version": "1.3.1",
3
+ "version": "1.3.2",
4
4
  "description": "MCP Server for Real Browser - Patchright (undetected Playwright fork) with Stealth Mode, Ad Blocker, and Turnstile Auto-Solver for undetectable web automation.",
5
5
  "main": "lib/cjs/index.js",
6
6
  "module": "lib/esm/index.mjs",
@@ -46,7 +46,7 @@
46
46
  "@ghostery/adblocker-playwright": "latest",
47
47
  "@modelcontextprotocol/sdk": "latest",
48
48
  "patchright": "latest",
49
- "playwright-ghost": "latest",
49
+ "ghost-cursor-patchright": "file:../ghost-cursor",
50
50
  "xvfb": "latest"
51
51
  }
52
52
  }
@@ -595,7 +595,7 @@ const handlers = {
595
595
  // ═══════════════════════════════════════════════════════════════
596
596
  // INJECTED SCRIPT - Silent Handling of Popups
597
597
  // Override window.confirm/alert to handle them inside the page context
598
- // Note: Using evaluateOnNewDocument (Puppeteer) instead of addInitScript (Playwright)
598
+ // Note: Using evaluateOnNewDocument shim instead of raw addInitScript
599
599
  // ═══════════════════════════════════════════════════════════════
600
600
  await pageInstance.evaluateOnNewDocument(() => {
601
601
  window.originalConfirm = window.confirm;
package/src/mcp/server.js CHANGED
@@ -7,7 +7,7 @@
7
7
 
8
8
  // CRITICAL: Redirect ALL console.log to STDERR before ANY imports
9
9
  // MCP uses STDIO transport — STDOUT must contain ONLY JSON-RPC messages.
10
- // Any console.log from this code or ANY dependency (puppeteer, blocker, etc.)
10
+ // Any console.log from this code or ANY dependency (browser, blocker, etc.)
11
11
  // will corrupt the JSON-RPC stream and cause parsing errors.
12
12
  const _originalConsoleLog = console.log;
13
13
  console.log = function (...args) {
package/typings.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- declare module "brave-real-browser-mcp-server" {
2
- import type { Browser, Page } from "brave-real-puppeteer-core";
3
- import type { GhostCursor } from "ghost-cursor";
1
+ declare module "real-browser-mcp-server" {
2
+ import type { Browser, Page } from "patchright";
3
+ import type { GhostCursor } from "ghost-cursor-patchright";
4
4
 
5
5
  export function connect(options?: Options): Promise<ConnectResult>;
6
6
 
@@ -19,12 +19,12 @@ declare module "brave-real-browser-mcp-server" {
19
19
  interface Options {
20
20
  args?: string[];
21
21
  headless?: boolean;
22
- customConfig?: import("brave-real-launcher").Options;
22
+ customConfig?: any;
23
23
  proxy?: ProxyOptions;
24
24
  turnstile?: boolean;
25
- connectOption?: import("brave-real-puppeteer-core").ConnectOptions;
25
+ connectOption?: any;
26
26
  disableXvfb?: boolean;
27
- plugins?: import("puppeteer-extra").PuppeteerExtraPlugin[];
27
+ plugins?: any[];
28
28
  ignoreAllFlags?: boolean;
29
29
  /** Enable blocker on all pages (default: true) */
30
30
  enableBlocker?: boolean;
@@ -1,46 +0,0 @@
1
- import playwright from "playwright-ghost/patchright";
2
- import recommended from "playwright-ghost/plugins/recommended";
3
-
4
- console.log("🚀 Starting Option 2 Demonstration...");
5
-
6
- try {
7
- // Launch browser with playwright-ghost overlay & recommended stealth/humanize plugins
8
- console.log("Launching browser with Option 2 (playwright-ghost overlay & recommended plugins)...");
9
- const browser = await playwright.chromium.launch({
10
- headless: false, // Set to false so you can see it if run locally, but works in headless too
11
- plugins: [recommended()]
12
- });
13
- console.log("✅ Browser launched successfully!");
14
-
15
- const context = await browser.newContext();
16
- const page = await context.newPage();
17
- console.log("✅ Page created!");
18
-
19
- // Go to DrissionPage Detector
20
- console.log("Navigating to DrissionPage Detector page...");
21
- await page.goto("https://web.archive.org/web/20240913054632/https://drissionpage.pages.dev/", { timeout: 60000 });
22
- console.log("✅ Page loaded successfully!");
23
-
24
- console.log("Triggering normal, standard page.click('#detector')!");
25
- console.log("👉 Option 2 will intercept this click, calculate a Bézier curve path, scroll it into view, move the cursor humanly, and then click!");
26
-
27
- const startTime = Date.now();
28
- await page.click("#detector");
29
- console.log(`✅ Standard click intercepted and completed in ${(Date.now() - startTime) / 1000}s!`);
30
-
31
- // Verify the detector says "not a bot"
32
- const isNotBot = await page.evaluate(() => {
33
- return document.querySelector('#isBot span').textContent.includes("not");
34
- });
35
-
36
- if (isNotBot) {
37
- console.log("🎉 SUCCESS! The detector passed: 'not a bot'.");
38
- } else {
39
- console.log("❌ FAILED! Detected as bot.");
40
- }
41
-
42
- await browser.close();
43
- console.log("🏁 Browser closed. Demonstration completed successfully.");
44
- } catch (error) {
45
- console.error("❌ An error occurred during the demonstration:", error);
46
- }
@@ -1,30 +0,0 @@
1
- import playwright from "playwright-ghost/patchright";
2
- import recommended from "playwright-ghost/plugins/recommended";
3
-
4
- console.log("🚀 Testing playwright-ghost integration...");
5
-
6
- try {
7
- const browser = await playwright.chromium.launch({
8
- headless: true,
9
- plugins: [recommended()]
10
- });
11
- console.log("✅ Browser launched successfully with playwright-ghost!");
12
-
13
- const context = await browser.newContext();
14
- const page = await context.newPage();
15
- console.log("✅ Context and page created!");
16
-
17
- console.log("Navigating to simple website...");
18
- await page.goto("https://example.com");
19
- console.log("✅ Navigated successfully!");
20
-
21
- console.log("Attempting humanized click on link...");
22
- const link = page.locator("a");
23
- await link.click();
24
- console.log("✅ Clicked successfully!");
25
-
26
- await browser.close();
27
- console.log("🎉 Test completed successfully!");
28
- } catch (error) {
29
- console.error("❌ Test failed:", error);
30
- }