real-browser-mcp-server 1.0.6 → 1.0.7

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
@@ -11,6 +11,26 @@ This server is **100% compatible with all major AI IDEs** (Cursor, VS Code, Clin
11
11
 
12
12
  ---
13
13
 
14
+ ## ⚙️ Installation & Setup
15
+
16
+ To install and run the server locally, clone the repository, install NPM dependencies, and configure the undetected browser binary using **Patchright**:
17
+
18
+ ```bash
19
+ # 1. Clone the repository
20
+ git clone https://github.com/codeiva4u/Real-Browser-Mcp-Server.git
21
+
22
+ # 2. Navigate to the project directory
23
+ cd Real-Browser-Mcp-Server
24
+
25
+ # 3. Install dependencies
26
+ npm install
27
+
28
+ # 4. Install Chromium-Driver for Patchright (Undetected Browser binary)
29
+ npx patchright install chromium
30
+ ```
31
+
32
+ ---
33
+
14
34
  ## 🚀 Key Evasion & Stealth Features
15
35
 
16
36
  * **Undetected Browser Engine**: Powered by **Patchright Chromium**, bypassing modern fingerprinting checks (does not expose automation indicators or Webdriver/BiDi flags).
package/lib/cjs/index.js CHANGED
@@ -70,10 +70,13 @@ function getDefaultHeadless() {
70
70
  return envHeadless === 'true';
71
71
  }
72
72
 
73
- function setupRealPage(browser, page) {
73
+ function setupRealPage(browser, page, options = {}) {
74
74
  if (page._setupApplied) return page;
75
75
  page._setupApplied = true;
76
76
 
77
+ const headless = options.headless !== undefined ? options.headless : getDefaultHeadless();
78
+ const showCursor = options.showCursor !== undefined ? options.showCursor : !headless;
79
+
77
80
  // Enable ad blocker
78
81
  if (adBlockerInstance) {
79
82
  adBlockerInstance.enableBlockingInPage(page).catch(() => {});
@@ -87,11 +90,13 @@ function setupRealPage(browser, page) {
87
90
 
88
91
  // Ghost Cursor integration - Bézier curve human-like mouse movement
89
92
  try {
90
- const cursor = createCursor(page);
93
+ // 5th parameter controls visual cursor (installMouseHelper under the hood)
94
+ const cursorPromise = createCursor(page, undefined, false, {}, showCursor);
91
95
  page.realCursor = {
92
96
  move: async (selector, options = {}) => {
93
97
  try {
94
- await cursor.actions.move(selector, options);
98
+ const cursor = await cursorPromise;
99
+ await cursor.move(selector, options);
95
100
  } catch (e) {
96
101
  // Fallback to native hover if ghost-cursor fails
97
102
  try { await page.hover(selector); } catch (_) {}
@@ -100,7 +105,8 @@ function setupRealPage(browser, page) {
100
105
  };
101
106
  page.realClick = async (selector, options = {}) => {
102
107
  try {
103
- await cursor.actions.click({ target: selector, ...options });
108
+ const cursor = await cursorPromise;
109
+ await cursor.click(selector, options);
104
110
  } catch (e) {
105
111
  // Fallback to native click if ghost-cursor fails
106
112
  await page.click(selector, options);
@@ -228,6 +234,7 @@ async function connect({
228
234
  proxy = {},
229
235
  turnstile = false,
230
236
  executablePath = undefined,
237
+ visualCursor = undefined,
231
238
  } = {}) {
232
239
  let playwrightProxy = undefined;
233
240
  if (proxy && proxy.host && proxy.port) {
@@ -328,7 +335,9 @@ async function connect({
328
335
 
329
336
  await applyUserAgentOverride(page, modifiedUa, userAgentMetadata);
330
337
 
331
- setupRealPage(browser, page);
338
+ const showCursor = visualCursor !== undefined ? visualCursor : !headless;
339
+
340
+ setupRealPage(browser, page, { headless, showCursor });
332
341
 
333
342
  page = await pageController({
334
343
  browser,
@@ -339,7 +348,7 @@ async function connect({
339
348
 
340
349
  context.on('page', async (newPage) => {
341
350
  await applyUserAgentOverride(newPage, modifiedUa, userAgentMetadata);
342
- setupRealPage(browser, newPage);
351
+ setupRealPage(browser, newPage, { headless, showCursor });
343
352
  await pageController({
344
353
  browser,
345
354
  page: newPage,
package/lib/esm/index.mjs CHANGED
@@ -75,10 +75,13 @@ function getDefaultHeadless() {
75
75
  return envHeadless === 'true';
76
76
  }
77
77
 
78
- function setupRealPage(browser, page) {
78
+ function setupRealPage(browser, page, options = {}) {
79
79
  if (page._setupApplied) return page;
80
80
  page._setupApplied = true;
81
81
 
82
+ const headless = options.headless !== undefined ? options.headless : getDefaultHeadless();
83
+ const showCursor = options.showCursor !== undefined ? options.showCursor : !headless;
84
+
82
85
  // Enable ad blocker
83
86
  if (adBlockerInstance) {
84
87
  adBlockerInstance.enableBlockingInPage(page).catch(() => {});
@@ -92,11 +95,13 @@ function setupRealPage(browser, page) {
92
95
 
93
96
  // Ghost Cursor integration - Bézier curve human-like mouse movement
94
97
  try {
95
- const cursor = createCursor(page);
98
+ // 5th parameter controls visual cursor (installMouseHelper under the hood)
99
+ const cursorPromise = createCursor(page, undefined, false, {}, showCursor);
96
100
  page.realCursor = {
97
101
  move: async (selector, options = {}) => {
98
102
  try {
99
- await cursor.actions.move(selector, options);
103
+ const cursor = await cursorPromise;
104
+ await cursor.move(selector, options);
100
105
  } catch (e) {
101
106
  // Fallback to native hover if ghost-cursor fails
102
107
  try { await page.hover(selector); } catch (_) {}
@@ -105,7 +110,8 @@ function setupRealPage(browser, page) {
105
110
  };
106
111
  page.realClick = async (selector, options = {}) => {
107
112
  try {
108
- await cursor.actions.click({ target: selector, ...options });
113
+ const cursor = await cursorPromise;
114
+ await cursor.click(selector, options);
109
115
  } catch (e) {
110
116
  // Fallback to native click if ghost-cursor fails
111
117
  await page.click(selector, options);
@@ -232,6 +238,7 @@ export async function connect({
232
238
  proxy = {},
233
239
  turnstile = false,
234
240
  executablePath = undefined,
241
+ visualCursor = undefined,
235
242
  } = {}) {
236
243
  let playwrightProxy = undefined;
237
244
  if (proxy && proxy.host && proxy.port) {
@@ -332,7 +339,9 @@ export async function connect({
332
339
 
333
340
  await applyUserAgentOverride(page, modifiedUa, userAgentMetadata);
334
341
 
335
- setupRealPage(browser, page);
342
+ const showCursor = visualCursor !== undefined ? visualCursor : !headless;
343
+
344
+ setupRealPage(browser, page, { headless, showCursor });
336
345
 
337
346
  page = await pageController({
338
347
  browser,
@@ -343,7 +352,7 @@ export async function connect({
343
352
 
344
353
  context.on('page', async (newPage) => {
345
354
  await applyUserAgentOverride(newPage, modifiedUa, userAgentMetadata);
346
- setupRealPage(browser, newPage);
355
+ setupRealPage(browser, newPage, { headless, showCursor });
347
356
  await pageController({
348
357
  browser,
349
358
  page: newPage,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "real-browser-mcp-server",
3
- "version": "1.0.6",
3
+ "version": "1.0.7",
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",
@@ -1239,20 +1239,23 @@ const handlers = {
1239
1239
  notifyProgress('click', 'progress', 'Used force click (JS)');
1240
1240
  } else if (humanLike) {
1241
1241
  try {
1242
- const { createCursor } = require('ghost-cursor-patchright');
1243
- const cursor = createCursor(page);
1244
-
1245
1242
  if (context !== page) {
1246
1243
  const element = await context.$(selector);
1247
1244
  if (element) {
1248
1245
  const box = await element.boundingBox();
1249
1246
  if (box) {
1250
- await cursor.moveTo({ x: box.x + box.width / 2, y: box.y + box.height / 2 });
1247
+ if (page.realCursor) {
1248
+ await page.realCursor.move({ x: box.x + box.width / 2, y: box.y + box.height / 2 });
1249
+ }
1251
1250
  await page.mouse.click(box.x + box.width / 2, box.y + box.height / 2, { clickCount, delay });
1252
1251
  }
1253
1252
  }
1254
1253
  } else {
1255
- await cursor.click(selector);
1254
+ if (page.realClick) {
1255
+ await page.realClick(selector);
1256
+ } else {
1257
+ await context.click(selector, { clickCount, delay });
1258
+ }
1256
1259
  }
1257
1260
  notifyProgress('click', 'progress', 'Used human-like cursor movement');
1258
1261
  } catch (e) {
package/typings.d.ts CHANGED
@@ -31,6 +31,8 @@ declare module "real-browser-mcp-server" {
31
31
  enableBlocker?: boolean;
32
32
  /** Blocker configuration options */
33
33
  blockerOptions?: BlockerOptions;
34
+ /** Enable visual cursor arrow overlay (defaults to true in headed/visible mode, false in headless mode) */
35
+ visualCursor?: boolean;
34
36
  }
35
37
 
36
38
  interface ProxyOptions {