brave-real-browser-mcp-server 2.41.12 → 2.41.14
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/package.json +2 -2
- package/packages/brave-real-blocker/package.json +2 -2
- package/packages/brave-real-launcher/package.json +2 -2
- package/packages/brave-real-playwright-core/package.json +1 -1
- package/packages/brave-real-puppeteer-core/package.json +14 -6
- package/src/mcp/handlers.js +119 -14
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "brave-real-browser-mcp-server",
|
|
3
|
-
"version": "2.41.
|
|
3
|
+
"version": "2.41.14",
|
|
4
4
|
"description": "MCP Server for Brave Real Browser - Puppeteer with Brave Browser, 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",
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
"license": "ISC",
|
|
75
75
|
"dependencies": {
|
|
76
76
|
"@modelcontextprotocol/sdk": "^1.25.3",
|
|
77
|
-
"brave-real-puppeteer-core": "^24.37.
|
|
77
|
+
"brave-real-puppeteer-core": "^24.37.2-brave.2",
|
|
78
78
|
"ghost-cursor": "^1.4.2",
|
|
79
79
|
"puppeteer-extra": "^3.3.6",
|
|
80
80
|
"puppeteer-extra-plugin-stealth": "^2.11.2",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "brave-real-blocker",
|
|
3
|
-
"version": "1.17.
|
|
3
|
+
"version": "1.17.14",
|
|
4
4
|
"description": "Advanced uBlock Origin management and stealth features for Brave Real Browser",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
"@types/adm-zip": "^0.5.5",
|
|
65
65
|
"@types/fs-extra": "^11.0.4",
|
|
66
66
|
"@types/node": "^20.0.0",
|
|
67
|
-
"brave-real-puppeteer-core": "^24.37.
|
|
67
|
+
"brave-real-puppeteer-core": "^24.37.2-brave.2",
|
|
68
68
|
"mocha": "^10.4.0",
|
|
69
69
|
"puppeteer-core": ">=24.0.0",
|
|
70
70
|
"sinon": "^17.0.1",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "brave-real-launcher",
|
|
3
|
-
"version": "1.23.
|
|
3
|
+
"version": "1.23.14",
|
|
4
4
|
"description": "Launch Brave Browser with ease from node. Based on chrome-launcher with Brave-specific support.",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"typescript": "^5.0.0"
|
|
55
55
|
},
|
|
56
56
|
"dependencies": {
|
|
57
|
-
"brave-real-blocker": "^1.17.
|
|
57
|
+
"brave-real-blocker": "^1.17.14",
|
|
58
58
|
"escape-string-regexp": "^5.0.0",
|
|
59
59
|
"is-wsl": "^3.1.0",
|
|
60
60
|
"which": "^6.0.0"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "brave-real-puppeteer-core",
|
|
3
|
-
"version": "24.37.
|
|
3
|
+
"version": "24.37.2-brave.2",
|
|
4
4
|
"description": "🦁 Brave Real-World Optimized Puppeteer & Playwright Core with 1-5ms ultra-fast timing, 50+ professional stealth features, intelligent browser auto-detection, and 100% bot detection bypass. Features cross-platform Brave browser integration, comprehensive anti-detection, and breakthrough performance improvements.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"automation",
|
|
@@ -134,13 +134,20 @@
|
|
|
134
134
|
"test-version": "node ./scripts/test-version-management.js"
|
|
135
135
|
},
|
|
136
136
|
"dependencies": {
|
|
137
|
-
"
|
|
137
|
+
"@puppeteer/browsers": "2.12.0",
|
|
138
|
+
"brave-real-launcher": "^1.23.14",
|
|
139
|
+
"chromium-bidi": "13.1.1",
|
|
140
|
+
"debug": "^4.4.3",
|
|
141
|
+
"devtools-protocol": "0.0.1566079",
|
|
138
142
|
"get-east-asian-width": "^1.4.0",
|
|
143
|
+
"typed-query-selector": "^2.12.0",
|
|
144
|
+
"webdriver-bidi-protocol": "0.4.0",
|
|
145
|
+
"ws": "^8.19.0",
|
|
139
146
|
"yargs": "^18.0.0"
|
|
140
147
|
},
|
|
141
148
|
"optionalDependencies": {
|
|
142
|
-
"playwright-core": "^1.58.
|
|
143
|
-
"puppeteer-core": "^24.37.
|
|
149
|
+
"playwright-core": "^1.58.2",
|
|
150
|
+
"puppeteer-core": "^24.37.2"
|
|
144
151
|
},
|
|
145
152
|
"devDependencies": {
|
|
146
153
|
"test": "^3.3.0"
|
|
@@ -148,7 +155,7 @@
|
|
|
148
155
|
"brave": {
|
|
149
156
|
"optimized": true,
|
|
150
157
|
"basedOn": {
|
|
151
|
-
"puppeteer-core": "24.
|
|
158
|
+
"puppeteer-core": "24.37.2"
|
|
152
159
|
},
|
|
153
160
|
"features": [
|
|
154
161
|
"stealth-injection",
|
|
@@ -157,6 +164,7 @@
|
|
|
157
164
|
"fingerprint-spoofing",
|
|
158
165
|
"ultra-fast-timing"
|
|
159
166
|
],
|
|
160
|
-
"versionScheme": "upstream-aligned"
|
|
167
|
+
"versionScheme": "upstream-aligned",
|
|
168
|
+
"patchedVersion": "24.37.2-brave.1"
|
|
161
169
|
}
|
|
162
170
|
}
|
package/src/mcp/handlers.js
CHANGED
|
@@ -240,6 +240,67 @@ const decoders = {
|
|
|
240
240
|
* Tool Handlers Object
|
|
241
241
|
*/
|
|
242
242
|
const handlers = {
|
|
243
|
+
// ═══════════════════════════════════════════════════════════════
|
|
244
|
+
// HELPER: Auto-Close Blocking Modals/Popups
|
|
245
|
+
// ═══════════════════════════════════════════════════════════════
|
|
246
|
+
async _handleBlockingModals(page) {
|
|
247
|
+
try {
|
|
248
|
+
const closed = await page.evaluate(() => {
|
|
249
|
+
// Selectors for common modal close buttons
|
|
250
|
+
const closeSelectors = [
|
|
251
|
+
// Bootstrap/Standard Modals
|
|
252
|
+
'.modal.show .btn-close',
|
|
253
|
+
'.modal.show .close',
|
|
254
|
+
'.modal.in .close',
|
|
255
|
+
'.modal-footer .btn-primary', // "OK" button usually
|
|
256
|
+
'.modal-footer .btn-secondary', // "Close" button
|
|
257
|
+
// Custom Overlays
|
|
258
|
+
'#modal-close',
|
|
259
|
+
'.popup-close',
|
|
260
|
+
'.overlay-close',
|
|
261
|
+
// Generic "X" buttons in overlays
|
|
262
|
+
'div[role="dialog"] button[aria-label="Close"]',
|
|
263
|
+
'div[role="dialog"] .close',
|
|
264
|
+
// SweetAlert / specific libraries
|
|
265
|
+
'.swal2-confirm',
|
|
266
|
+
'.swal2-cancel',
|
|
267
|
+
'.ui-dialog-titlebar-close',
|
|
268
|
+
// eCourts specific if known (generic fallback)
|
|
269
|
+
'.modal-header .close',
|
|
270
|
+
'button[data-dismiss="modal"]'
|
|
271
|
+
];
|
|
272
|
+
|
|
273
|
+
let clicked = false;
|
|
274
|
+
// Check if any modal is visible (display block/flex and opacity > 0)
|
|
275
|
+
const modals = document.querySelectorAll('.modal, .popup, .overlay, .dialog, [role="dialog"]');
|
|
276
|
+
for (const modal of modals) {
|
|
277
|
+
const style = window.getComputedStyle(modal);
|
|
278
|
+
if (style.display !== 'none' && style.visibility !== 'hidden' && style.opacity !== '0') {
|
|
279
|
+
// Modal is visible, find a close button inside
|
|
280
|
+
for (const selector of closeSelectors) {
|
|
281
|
+
const btn = modal.querySelector(selector);
|
|
282
|
+
if (btn && btn.offsetParent !== null) { // Visible button
|
|
283
|
+
btn.click();
|
|
284
|
+
clicked = true;
|
|
285
|
+
break; // Clicked one, break inner loop
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
if (clicked) break; // Handled one modal, break outer loop
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
return clicked;
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
if (closed) {
|
|
295
|
+
// notifyProgress('helper', 'progress', '🧹 Auto-closed a blocking modal/popup');
|
|
296
|
+
await new Promise(r => setTimeout(r, 500)); // Wait for animation
|
|
297
|
+
}
|
|
298
|
+
return closed;
|
|
299
|
+
} catch (e) {
|
|
300
|
+
return false;
|
|
301
|
+
}
|
|
302
|
+
},
|
|
303
|
+
|
|
243
304
|
// ═══════════════════════════════════════════════════════════════
|
|
244
305
|
// HELPER: Full Page Analyzer - Detect ALL inputs on page
|
|
245
306
|
// ═══════════════════════════════════════════════════════════════
|
|
@@ -305,7 +366,7 @@ const handlers = {
|
|
|
305
366
|
const unfilledFields = [];
|
|
306
367
|
|
|
307
368
|
// First, analyze the full page
|
|
308
|
-
const pageInfo = await
|
|
369
|
+
const pageInfo = await handlers._analyzeFullPage(page);
|
|
309
370
|
notifyProgress('solve_captcha', 'progress', `🔍 Page analyzed: ${pageInfo.totalInputs} inputs found`);
|
|
310
371
|
|
|
311
372
|
for (const [field, value] of Object.entries(formData || {})) {
|
|
@@ -504,25 +565,63 @@ const handlers = {
|
|
|
504
565
|
blockerInstance = result.blocker;
|
|
505
566
|
|
|
506
567
|
// ═══════════════════════════════════════════════════════════════
|
|
507
|
-
// GLOBAL DIALOG HANDLER - Auto-
|
|
508
|
-
//
|
|
568
|
+
// GLOBAL DIALOG HANDLER - Auto-handle dialogs
|
|
569
|
+
// Logic: BLOCK redirects to external sites, ACCEPT everything else
|
|
509
570
|
// ═══════════════════════════════════════════════════════════════
|
|
510
571
|
pageInstance.on('dialog', async (dialog) => {
|
|
511
572
|
const dialogType = dialog.type();
|
|
512
|
-
const
|
|
573
|
+
const msg = dialog.message().toLowerCase();
|
|
513
574
|
|
|
514
575
|
notifyProgress('browser_init', 'progress',
|
|
515
|
-
`🔔
|
|
576
|
+
`🔔 Handling dialog: ${dialogType} - ${dialog.message().substring(0, 100)}...`);
|
|
516
577
|
|
|
517
578
|
try {
|
|
518
|
-
|
|
519
|
-
|
|
579
|
+
// Critical Fix: BLOCK redirects to external sites (e.g., eCommittee)
|
|
580
|
+
// These redirects take the user away from the search page
|
|
581
|
+
if (msg.includes('redirect') || msg.includes('external') || msg.includes('leaving')) {
|
|
582
|
+
console.log('🚫 Blocking redirect dialog (Dismiss)');
|
|
583
|
+
await dialog.dismiss(); // Simulate clicking 'Cancel'
|
|
584
|
+
} else {
|
|
585
|
+
// Auto-accept other dialogs (like alerts or simple confirmations)
|
|
586
|
+
await dialog.accept(); // Simulate clicking 'OK'
|
|
587
|
+
}
|
|
520
588
|
} catch (e) {
|
|
521
|
-
//
|
|
522
|
-
console.error(`Dialog handling error: ${e.message}`);
|
|
589
|
+
// Ignore errors (dialog might be closed by injected script)
|
|
523
590
|
}
|
|
524
591
|
});
|
|
525
592
|
|
|
593
|
+
// ═══════════════════════════════════════════════════════════════
|
|
594
|
+
// INJECTED SCRIPT - Silent Handling of Popups
|
|
595
|
+
// Override window.confirm/alert to handle them inside the page context
|
|
596
|
+
// Note: Using evaluateOnNewDocument (Puppeteer) instead of addInitScript (Playwright)
|
|
597
|
+
// ═══════════════════════════════════════════════════════════════
|
|
598
|
+
await pageInstance.evaluateOnNewDocument(() => {
|
|
599
|
+
window.originalConfirm = window.confirm;
|
|
600
|
+
window.originalAlert = window.alert;
|
|
601
|
+
|
|
602
|
+
// Smart Confirm Handler
|
|
603
|
+
window.confirm = (msg) => {
|
|
604
|
+
console.log('Intercepted Confirm Dialog:', msg);
|
|
605
|
+
if (msg && (msg.toLowerCase().includes('redirect') || msg.toLowerCase().includes('external'))) {
|
|
606
|
+
console.log('🚫 Blocking redirect confirmation inside page');
|
|
607
|
+
return false; // Return FALSE = Click Cancel
|
|
608
|
+
}
|
|
609
|
+
return true; // Return TRUE = Click OK
|
|
610
|
+
};
|
|
611
|
+
|
|
612
|
+
// Silently ignore alerts (always OK)
|
|
613
|
+
window.alert = (msg) => {
|
|
614
|
+
console.log('Blocked Alert Dialog:', msg);
|
|
615
|
+
return true;
|
|
616
|
+
};
|
|
617
|
+
|
|
618
|
+
// Silently return null for prompts
|
|
619
|
+
window.prompt = (msg) => {
|
|
620
|
+
console.log('Blocked Prompt Dialog:', msg);
|
|
621
|
+
return null;
|
|
622
|
+
};
|
|
623
|
+
});
|
|
624
|
+
|
|
526
625
|
const pid = browserInstance.process()?.pid;
|
|
527
626
|
|
|
528
627
|
notifyProgress('browser_init', 'completed', `Browser started (PID: ${pid})`, {
|
|
@@ -701,6 +800,9 @@ const handlers = {
|
|
|
701
800
|
|
|
702
801
|
notifyProgress('click', 'started', `Clicking: ${selector}`);
|
|
703
802
|
|
|
803
|
+
// Auto-close any blocking modals before clicking
|
|
804
|
+
await handlers._handleBlockingModals(page);
|
|
805
|
+
|
|
704
806
|
// Auto-handle dialogs (alerts, confirms, prompts) to prevent blocking
|
|
705
807
|
let dialogHandled = false;
|
|
706
808
|
const dialogHandler = async (dialog) => {
|
|
@@ -754,6 +856,9 @@ const handlers = {
|
|
|
754
856
|
|
|
755
857
|
notifyProgress('type', 'started', `Typing ${text.length} characters into ${selector}`);
|
|
756
858
|
|
|
859
|
+
// Auto-close any blocking modals before typing
|
|
860
|
+
await handlers._handleBlockingModals(page);
|
|
861
|
+
|
|
757
862
|
if (clear) {
|
|
758
863
|
await page.click(selector, { clickCount: 3 });
|
|
759
864
|
await page.keyboard.press('Backspace');
|
|
@@ -825,7 +930,7 @@ const handlers = {
|
|
|
825
930
|
let formResult = null;
|
|
826
931
|
if (formData && Object.keys(formData).length > 0) {
|
|
827
932
|
notifyProgress('solve_captcha', 'started', `📋 Smart Form + Captcha Mode: Filling ${Object.keys(formData).length} fields...`);
|
|
828
|
-
formResult = await
|
|
933
|
+
formResult = await handlers._fillFormFields(page, formData, formSelector, humanLike, aiMatch);
|
|
829
934
|
} else {
|
|
830
935
|
notifyProgress('solve_captcha', 'started', `🎯 100% Accuracy Mode: Solving ${type} captcha...`);
|
|
831
936
|
}
|
|
@@ -1028,7 +1133,7 @@ const handlers = {
|
|
|
1028
1133
|
// MERGED: Handle form submission if requested
|
|
1029
1134
|
if (submit) {
|
|
1030
1135
|
notifyProgress('solve_captcha', 'progress', '🚀 Submitting form...');
|
|
1031
|
-
const submitResult = await
|
|
1136
|
+
const submitResult = await handlers._submitForm(page);
|
|
1032
1137
|
return {
|
|
1033
1138
|
success: true,
|
|
1034
1139
|
type: 'ocr',
|
|
@@ -1111,7 +1216,7 @@ const handlers = {
|
|
|
1111
1216
|
// MERGED: Handle form submission if requested
|
|
1112
1217
|
if (submit) {
|
|
1113
1218
|
notifyProgress('solve_captcha', 'progress', '🚀 Submitting form...');
|
|
1114
|
-
const submitResult = await
|
|
1219
|
+
const submitResult = await handlers._submitForm(page);
|
|
1115
1220
|
return {
|
|
1116
1221
|
success: true,
|
|
1117
1222
|
type: 'turnstile',
|
|
@@ -1141,7 +1246,7 @@ const handlers = {
|
|
|
1141
1246
|
try {
|
|
1142
1247
|
// Pre-submit validation
|
|
1143
1248
|
if (validateFirst) {
|
|
1144
|
-
const validation = await
|
|
1249
|
+
const validation = await handlers._validateBeforeSubmit(page);
|
|
1145
1250
|
if (!validation.valid) {
|
|
1146
1251
|
notifyProgress('solve_captcha', 'warn', `⚠️ Validation failed: ${validation.errors.length} issue(s)`);
|
|
1147
1252
|
return { success: false, message: 'Pre-submit validation failed', errors: validation.errors };
|
|
@@ -1187,7 +1292,7 @@ const handlers = {
|
|
|
1187
1292
|
return { success: true, message: 'Form submitted and navigation complete', navigated: true };
|
|
1188
1293
|
} catch (e) {
|
|
1189
1294
|
// No navigation - check for errors on same page
|
|
1190
|
-
const postErrors = await
|
|
1295
|
+
const postErrors = await handlers._detectPostSubmitErrors(page);
|
|
1191
1296
|
|
|
1192
1297
|
if (postErrors.hasErrors) {
|
|
1193
1298
|
notifyProgress('solve_captcha', 'warn', `⚠️ Submit detected errors: ${postErrors.errors[0]}`);
|