brave-real-browser-mcp-server 2.19.8 → 2.19.9
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/dist/browser-manager.js +23 -23
- package/dist/core-infrastructure.js +8 -8
- package/dist/handlers/advanced-tools.js +1 -1
- package/dist/handlers/interaction-handlers.js +5 -5
- package/dist/handlers/navigation-handlers.js +7 -7
- package/dist/index.js +1 -1
- package/dist/self-healing-locators.js +5 -5
- package/dist/system-utils.js +2 -2
- package/package.json +2 -2
package/dist/browser-manager.js
CHANGED
|
@@ -154,7 +154,7 @@ export async function testHostConnectivity() {
|
|
|
154
154
|
};
|
|
155
155
|
}
|
|
156
156
|
catch (error) {
|
|
157
|
-
console.
|
|
157
|
+
// console.('Host connectivity test failed:', error);
|
|
158
158
|
return {
|
|
159
159
|
localhost: false,
|
|
160
160
|
ipv4: true,
|
|
@@ -177,7 +177,7 @@ export function updateCircuitBreakerOnFailure() {
|
|
|
177
177
|
browserCircuitBreaker.lastFailureTime = Date.now();
|
|
178
178
|
if (browserCircuitBreaker.failureCount >= CIRCUIT_BREAKER_THRESHOLD) {
|
|
179
179
|
browserCircuitBreaker.state = 'open';
|
|
180
|
-
console.
|
|
180
|
+
// console.(`Circuit breaker opened after ${browserCircuitBreaker.failureCount} failures`);
|
|
181
181
|
}
|
|
182
182
|
}
|
|
183
183
|
export function updateCircuitBreakerOnSuccess() {
|
|
@@ -192,7 +192,7 @@ export function isCircuitBreakerOpen() {
|
|
|
192
192
|
const timeSinceLastFailure = Date.now() - browserCircuitBreaker.lastFailureTime;
|
|
193
193
|
if (timeSinceLastFailure > CIRCUIT_BREAKER_TIMEOUT) {
|
|
194
194
|
browserCircuitBreaker.state = 'half-open';
|
|
195
|
-
console.
|
|
195
|
+
// console.('Circuit breaker entering half-open state');
|
|
196
196
|
return false;
|
|
197
197
|
}
|
|
198
198
|
return true;
|
|
@@ -204,7 +204,7 @@ export function isCircuitBreakerOpen() {
|
|
|
204
204
|
// Session validation utility
|
|
205
205
|
export async function validateSession() {
|
|
206
206
|
if (sessionValidationInProgress) {
|
|
207
|
-
console.
|
|
207
|
+
// console.('Session validation already in progress, skipping duplicate validation');
|
|
208
208
|
return false;
|
|
209
209
|
}
|
|
210
210
|
if (!browserInstance || !pageInstance) {
|
|
@@ -219,7 +219,7 @@ export async function validateSession() {
|
|
|
219
219
|
return true;
|
|
220
220
|
}
|
|
221
221
|
catch (error) {
|
|
222
|
-
console.
|
|
222
|
+
// console.('Session validation failed:', error);
|
|
223
223
|
return false;
|
|
224
224
|
}
|
|
225
225
|
finally {
|
|
@@ -279,12 +279,12 @@ export async function initializeBrowser(options) {
|
|
|
279
279
|
return { browser: browserInstance, page: pageInstance };
|
|
280
280
|
}
|
|
281
281
|
else {
|
|
282
|
-
console.
|
|
282
|
+
// console.('Existing session is invalid, reinitializing browser...');
|
|
283
283
|
await closeBrowser();
|
|
284
284
|
}
|
|
285
285
|
}
|
|
286
|
-
console.
|
|
287
|
-
console.
|
|
286
|
+
// console.('🦁 Launching Brave Browser...');
|
|
287
|
+
// console.(' brave-real-browser handles auto-detection, uBlock Origin, and Stealth mode');
|
|
288
288
|
// Determine headless mode from:
|
|
289
289
|
// 1. Tool argument (highest priority)
|
|
290
290
|
// 2. Environment variable HEADLESS
|
|
@@ -292,10 +292,10 @@ export async function initializeBrowser(options) {
|
|
|
292
292
|
const envHeadless = process.env.HEADLESS?.toLowerCase() === 'true';
|
|
293
293
|
const headlessMode = options?.headless ?? envHeadless;
|
|
294
294
|
if (headlessMode) {
|
|
295
|
-
console.
|
|
295
|
+
// console.(' Mode: HEADLESS (from ' + (options?.headless !== undefined ? 'tool argument' : 'environment variable') + ')');
|
|
296
296
|
}
|
|
297
297
|
else {
|
|
298
|
-
console.
|
|
298
|
+
// console.(' Mode: GUI (visible browser)');
|
|
299
299
|
}
|
|
300
300
|
// Brave-real-browser handles everything automatically
|
|
301
301
|
// Simply pass-through user options without any manual args/flags
|
|
@@ -315,19 +315,19 @@ export async function initializeBrowser(options) {
|
|
|
315
315
|
const { browser, page } = result;
|
|
316
316
|
browserInstance = browser;
|
|
317
317
|
pageInstance = page;
|
|
318
|
-
console.
|
|
319
|
-
console.
|
|
318
|
+
// console.('✅ Brave Browser initialized successfully');
|
|
319
|
+
// console.(' Features: uBlock Origin (built-in), Stealth Mode, Auto-Detection');
|
|
320
320
|
updateCircuitBreakerOnSuccess();
|
|
321
321
|
return { browser, page };
|
|
322
322
|
}
|
|
323
323
|
catch (error) {
|
|
324
324
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
325
|
-
console.
|
|
326
|
-
console.
|
|
327
|
-
console.
|
|
328
|
-
console.
|
|
329
|
-
console.
|
|
330
|
-
console.
|
|
325
|
+
// console.(`❌ Brave Browser launch failed: ${errorMessage}`);
|
|
326
|
+
// console.('');
|
|
327
|
+
// console.('🔧 Troubleshooting:');
|
|
328
|
+
// console.(' 1. Ensure Brave Browser is installed');
|
|
329
|
+
// console.(' 2. Set BRAVE_PATH environment variable if auto-detection fails');
|
|
330
|
+
// console.(' 3. Check if another Brave instance is running');
|
|
331
331
|
updateCircuitBreakerOnFailure();
|
|
332
332
|
throw error;
|
|
333
333
|
}
|
|
@@ -346,7 +346,7 @@ export async function closeBrowser() {
|
|
|
346
346
|
await page.close();
|
|
347
347
|
}
|
|
348
348
|
catch (error) {
|
|
349
|
-
console.
|
|
349
|
+
// console.('Error closing page:', error);
|
|
350
350
|
}
|
|
351
351
|
}
|
|
352
352
|
await browserInstance.close();
|
|
@@ -359,18 +359,18 @@ export async function closeBrowser() {
|
|
|
359
359
|
}
|
|
360
360
|
}
|
|
361
361
|
catch (error) {
|
|
362
|
-
console.
|
|
362
|
+
// console.('Error force-killing browser process:', error);
|
|
363
363
|
}
|
|
364
364
|
}
|
|
365
365
|
}
|
|
366
366
|
catch (error) {
|
|
367
|
-
console.
|
|
367
|
+
// console.('Error closing browser:', error);
|
|
368
368
|
if (browserInstance && browserInstance.process() != null) {
|
|
369
369
|
try {
|
|
370
370
|
browserInstance.process().kill('SIGKILL');
|
|
371
371
|
}
|
|
372
372
|
catch (killError) {
|
|
373
|
-
console.
|
|
373
|
+
// console.('Error force-killing browser process with SIGKILL:', killError);
|
|
374
374
|
}
|
|
375
375
|
}
|
|
376
376
|
}
|
|
@@ -393,7 +393,7 @@ export async function forceKillAllBraveProcesses() {
|
|
|
393
393
|
}
|
|
394
394
|
}
|
|
395
395
|
catch (error) {
|
|
396
|
-
console.
|
|
396
|
+
// console.('Error force-killing Brave processes:', error);
|
|
397
397
|
}
|
|
398
398
|
}
|
|
399
399
|
// Legacy function name for compatibility
|
|
@@ -25,7 +25,7 @@ export async function withBrowserRetry(operation, maxRetries = 3, delay = 1000,
|
|
|
25
25
|
catch (error) {
|
|
26
26
|
lastError = error instanceof Error ? error : new Error(String(error));
|
|
27
27
|
const errorType = categorizeError(lastError);
|
|
28
|
-
|
|
28
|
+
// Silent for MCP compatibility
|
|
29
29
|
// Check if this is a recoverable error that might need browser cleanup
|
|
30
30
|
const recoverableErrors = [
|
|
31
31
|
BrowserErrorType.FRAME_DETACHED,
|
|
@@ -39,12 +39,12 @@ export async function withBrowserRetry(operation, maxRetries = 3, delay = 1000,
|
|
|
39
39
|
if (errorType === BrowserErrorType.SESSION_CLOSED ||
|
|
40
40
|
errorType === BrowserErrorType.TARGET_CLOSED ||
|
|
41
41
|
errorType === BrowserErrorType.FRAME_DETACHED) {
|
|
42
|
-
|
|
42
|
+
// Silent for MCP compatibility
|
|
43
43
|
try {
|
|
44
44
|
await closeBrowser();
|
|
45
45
|
}
|
|
46
46
|
catch (cleanupError) {
|
|
47
|
-
|
|
47
|
+
// Silent for MCP compatibility
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
50
|
if (!isRecoverable || attempt === maxRetries) {
|
|
@@ -159,24 +159,24 @@ export const MCP_SERVER_CONFIG = {
|
|
|
159
159
|
export function setupProcessCleanup(cleanupCallback) {
|
|
160
160
|
// Handle process termination gracefully
|
|
161
161
|
const cleanup = async () => {
|
|
162
|
-
|
|
162
|
+
// Silent for MCP compatibility
|
|
163
163
|
try {
|
|
164
164
|
await cleanupCallback();
|
|
165
|
-
|
|
165
|
+
// Silent for MCP compatibility
|
|
166
166
|
}
|
|
167
167
|
catch (error) {
|
|
168
|
-
|
|
168
|
+
// Silent for MCP compatibility
|
|
169
169
|
}
|
|
170
170
|
process.exit(0);
|
|
171
171
|
};
|
|
172
172
|
process.on('SIGINT', cleanup);
|
|
173
173
|
process.on('SIGTERM', cleanup);
|
|
174
174
|
process.on('uncaughtException', async (error) => {
|
|
175
|
-
|
|
175
|
+
// Silent for MCP compatibility
|
|
176
176
|
await cleanup();
|
|
177
177
|
});
|
|
178
178
|
process.on('unhandledRejection', async (reason) => {
|
|
179
|
-
|
|
179
|
+
// Silent for MCP compatibility
|
|
180
180
|
await cleanup();
|
|
181
181
|
});
|
|
182
182
|
}
|
|
@@ -394,7 +394,7 @@ export async function handleProgressTracker(_page, args) {
|
|
|
394
394
|
status = 'started';
|
|
395
395
|
if (args.currentStep >= args.totalSteps)
|
|
396
396
|
status = 'completed';
|
|
397
|
-
console.
|
|
397
|
+
// console.(`[Progress] ${args.taskName}: ${progress}% (${args.currentStep}/${args.totalSteps}) - ${args.message || ''}`);
|
|
398
398
|
return {
|
|
399
399
|
taskName: args.taskName,
|
|
400
400
|
progress,
|
|
@@ -32,7 +32,7 @@ export async function handleClick(args) {
|
|
|
32
32
|
let strategyMessage = '';
|
|
33
33
|
if (strategy !== 'primary') {
|
|
34
34
|
strategyMessage = `\n🔄 Self-healing: Used ${strategy} fallback selector: ${usedSelector}`;
|
|
35
|
-
console.
|
|
35
|
+
// console.(`Self-healing click: Primary selector '${selector}' failed, used '${usedSelector}' (${strategy})`);
|
|
36
36
|
}
|
|
37
37
|
try {
|
|
38
38
|
// Wait for element to be ready
|
|
@@ -40,7 +40,7 @@ export async function handleClick(args) {
|
|
|
40
40
|
// Check element visibility and interaction options
|
|
41
41
|
const boundingBox = await element.boundingBox();
|
|
42
42
|
if (!boundingBox) {
|
|
43
|
-
console.
|
|
43
|
+
// console.(`Element ${usedSelector} has no bounding box, attempting JavaScript click`);
|
|
44
44
|
await pageInstance.$eval(usedSelector, (el) => el.click());
|
|
45
45
|
}
|
|
46
46
|
else {
|
|
@@ -111,7 +111,7 @@ export async function handleType(args) {
|
|
|
111
111
|
let strategyMessage = '';
|
|
112
112
|
if (strategy !== 'primary') {
|
|
113
113
|
strategyMessage = `\n🔄 Self-healing: Used ${strategy} fallback selector: ${usedSelector}`;
|
|
114
|
-
console.
|
|
114
|
+
// console.(`Self-healing type: Primary selector '${selector}' failed, used '${usedSelector}' (${strategy})`);
|
|
115
115
|
}
|
|
116
116
|
try {
|
|
117
117
|
// Wait for element to be ready and interactable
|
|
@@ -176,7 +176,7 @@ export async function handleSolveCaptcha(args) {
|
|
|
176
176
|
const { type } = args;
|
|
177
177
|
// Note: This is a placeholder implementation
|
|
178
178
|
// The actual captcha solving would depend on the specific service/API used
|
|
179
|
-
console.
|
|
179
|
+
// console.(`🔄 Attempting to solve ${type} captcha...`);
|
|
180
180
|
return {
|
|
181
181
|
content: [
|
|
182
182
|
{
|
|
@@ -258,6 +258,6 @@ async function randomScroll(page) {
|
|
|
258
258
|
});
|
|
259
259
|
}
|
|
260
260
|
catch (error) {
|
|
261
|
-
console.
|
|
261
|
+
// console.('Random scroll failed (non-fatal):', error);
|
|
262
262
|
}
|
|
263
263
|
}
|
|
@@ -10,7 +10,7 @@ export async function handleNavigate(args) {
|
|
|
10
10
|
throw new Error('Browser not initialized. Call browser_init first.');
|
|
11
11
|
}
|
|
12
12
|
const { url, waitUntil = 'domcontentloaded' } = args;
|
|
13
|
-
console.
|
|
13
|
+
// console.(`🔄 Navigating to: ${url}`);
|
|
14
14
|
// Navigate with retry logic
|
|
15
15
|
let lastError = null;
|
|
16
16
|
let success = false;
|
|
@@ -23,16 +23,16 @@ export async function handleNavigate(args) {
|
|
|
23
23
|
timeout: 60000
|
|
24
24
|
});
|
|
25
25
|
}, 60000, 'page-navigation');
|
|
26
|
-
console.
|
|
26
|
+
// console.(`✅ Navigation successful to: ${url}`);
|
|
27
27
|
success = true;
|
|
28
28
|
break;
|
|
29
29
|
}
|
|
30
30
|
catch (error) {
|
|
31
31
|
lastError = error instanceof Error ? error : new Error(String(error));
|
|
32
|
-
console.
|
|
32
|
+
// console.(`❌ Navigation attempt ${attempt}/${maxRetries} failed:`, lastError.message);
|
|
33
33
|
if (attempt < maxRetries) {
|
|
34
34
|
const delay = 1000 * Math.pow(2, attempt - 1);
|
|
35
|
-
console.
|
|
35
|
+
// console.(`⏳ Waiting ${delay}ms before retry...`);
|
|
36
36
|
await new Promise(resolve => setTimeout(resolve, delay));
|
|
37
37
|
}
|
|
38
38
|
}
|
|
@@ -70,7 +70,7 @@ export async function handleWait(args) {
|
|
|
70
70
|
throw new Error('Timeout parameter must be a positive number');
|
|
71
71
|
}
|
|
72
72
|
const startTime = Date.now();
|
|
73
|
-
console.
|
|
73
|
+
// console.(`⏳ Waiting for ${type}: ${value} (timeout: ${timeout}ms)`);
|
|
74
74
|
try {
|
|
75
75
|
switch (type) {
|
|
76
76
|
case 'selector':
|
|
@@ -96,7 +96,7 @@ export async function handleWait(args) {
|
|
|
96
96
|
throw new Error(`Unsupported wait type: ${type}`);
|
|
97
97
|
}
|
|
98
98
|
const duration = Date.now() - startTime;
|
|
99
|
-
console.
|
|
99
|
+
// console.(`✅ Wait completed in ${duration}ms`);
|
|
100
100
|
return {
|
|
101
101
|
content: [
|
|
102
102
|
{
|
|
@@ -108,7 +108,7 @@ export async function handleWait(args) {
|
|
|
108
108
|
}
|
|
109
109
|
catch (error) {
|
|
110
110
|
const duration = Date.now() - startTime;
|
|
111
|
-
console.
|
|
111
|
+
// console.(`❌ Wait failed after ${duration}ms:`, error);
|
|
112
112
|
throw error;
|
|
113
113
|
}
|
|
114
114
|
}, 'Wait operation failed');
|
package/dist/index.js
CHANGED
|
@@ -277,7 +277,7 @@ async function main() {
|
|
|
277
277
|
debug('Attempting to connect server to transport...');
|
|
278
278
|
await server.connect(transport);
|
|
279
279
|
debug('Server connected to transport successfully');
|
|
280
|
-
// Startup messages
|
|
280
|
+
// Startup messages
|
|
281
281
|
console.error('🚀 Brave Real Browser MCP Server started successfully');
|
|
282
282
|
console.error('📋 Available tools:', TOOLS.map(t => t.name).join(', '));
|
|
283
283
|
console.error('🔧 Workflow validation: Active');
|
|
@@ -51,7 +51,7 @@ export class SelfHealingLocators {
|
|
|
51
51
|
return sortedFallbacks;
|
|
52
52
|
}
|
|
53
53
|
catch (error) {
|
|
54
|
-
console.
|
|
54
|
+
// console.('Fallback generation failed:', error);
|
|
55
55
|
return [];
|
|
56
56
|
}
|
|
57
57
|
}
|
|
@@ -86,7 +86,7 @@ export class SelfHealingLocators {
|
|
|
86
86
|
continue; // Skip this fallback if text doesn't match
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
|
-
console.
|
|
89
|
+
// console.(`Self-healing: Found element using fallback selector '${fallback.selector}' (${fallback.type}, confidence: ${fallback.confidence})`);
|
|
90
90
|
return {
|
|
91
91
|
element,
|
|
92
92
|
usedSelector: fallback.selector,
|
|
@@ -159,7 +159,7 @@ export class SelfHealingLocators {
|
|
|
159
159
|
return analysis;
|
|
160
160
|
}
|
|
161
161
|
catch (error) {
|
|
162
|
-
console.
|
|
162
|
+
// console.('Selector analysis failed:', error);
|
|
163
163
|
return null;
|
|
164
164
|
}
|
|
165
165
|
}
|
|
@@ -443,7 +443,7 @@ export class SelfHealingLocators {
|
|
|
443
443
|
}
|
|
444
444
|
}
|
|
445
445
|
catch (error) {
|
|
446
|
-
console.
|
|
446
|
+
// console.('Exploratory fallback generation failed:', error);
|
|
447
447
|
}
|
|
448
448
|
return fallbacks;
|
|
449
449
|
}
|
|
@@ -515,7 +515,7 @@ export class SelfHealingLocators {
|
|
|
515
515
|
}
|
|
516
516
|
}
|
|
517
517
|
catch (error) {
|
|
518
|
-
console.
|
|
518
|
+
// console.('Text-based search failed:', error);
|
|
519
519
|
}
|
|
520
520
|
return fallbacks;
|
|
521
521
|
}
|
package/dist/system-utils.js
CHANGED
|
@@ -5,7 +5,7 @@ export async function withErrorHandling(operation, errorMessage) {
|
|
|
5
5
|
return await operation();
|
|
6
6
|
}
|
|
7
7
|
catch (error) {
|
|
8
|
-
console.
|
|
8
|
+
// console.(`${errorMessage}:`, error);
|
|
9
9
|
throw new Error(`${errorMessage}: ${error instanceof Error ? error.message : String(error)}`);
|
|
10
10
|
}
|
|
11
11
|
}
|
|
@@ -19,7 +19,7 @@ export async function withRetry(operation, options = {}) {
|
|
|
19
19
|
}
|
|
20
20
|
catch (error) {
|
|
21
21
|
lastError = error instanceof Error ? error : new Error(String(error));
|
|
22
|
-
console.
|
|
22
|
+
// console.(`Attempt ${attempt}/${maxRetries} failed in context ${context}:`, lastError.message);
|
|
23
23
|
// Check if we should retry this error
|
|
24
24
|
if (!shouldRetry(lastError, attempt) || attempt === maxRetries) {
|
|
25
25
|
break;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "brave-real-browser-mcp-server",
|
|
3
|
-
"version": "2.19.
|
|
3
|
+
"version": "2.19.9",
|
|
4
4
|
"description": "🦁 MCP server for Brave Real Browser - NPM Workspaces Monorepo with anti-detection features",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"@modelcontextprotocol/sdk": "latest",
|
|
41
41
|
"@types/turndown": "latest",
|
|
42
|
-
"brave-real-browser": "^2.1.
|
|
42
|
+
"brave-real-browser": "^2.1.9",
|
|
43
43
|
"turndown": "latest"
|
|
44
44
|
},
|
|
45
45
|
"peerDependencies": {
|