brave-real-browser-mcp-server 2.9.5 โ†’ 2.9.6

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
@@ -61,6 +61,20 @@ If you're just using this MCP server (not developing it), you don't need to run
61
61
  }
62
62
  ```
63
63
 
64
+ ```json
65
+ {
66
+ "mcpServers": {
67
+ "brave-real-browser": {
68
+ "command": "npx",
69
+ "args": ["brave-real-browser-mcp-server@latest"],
70
+ "env": {
71
+ "CHROME_PATH": "C:\\Program Files\\BraveSoftware\\Brave-Browser\\Application\\brave.exe"
72
+ }
73
+ }
74
+ }
75
+ }
76
+ ```
77
+
64
78
  **For Mac:**
65
79
  1. Open Finder and press `Cmd+Shift+G`
66
80
  2. Go to: `~/Library/Application Support/Claude/`
@@ -122,7 +136,7 @@ assistants to control a real browser, extract content, and more.
122
136
  - **Advanced configuration**: Full support for all brave-real-browser options
123
137
  - **Dynamic selector discovery**: Intelligent element finding without hardcoded selectors
124
138
  - **Random scrolling**: Tools for natural scrolling to avoid detection
125
- - **Comprehensive toolset**: 11 tools covering all browser automation needs
139
+ - **Comprehensive toolset**: 62+ professional tools covering all browser automation needs
126
140
  - **Proxy support**: Built-in proxy configuration for enhanced privacy
127
141
  - **Captcha handling**: Support for solving reCAPTCHA, hCaptcha, and Turnstile
128
142
  - **Robust error handling**: Advanced error recovery with circuit breaker pattern
@@ -528,48 +542,106 @@ AI: I'll set up the browser with your proxy configuration.
528
542
 
529
543
  ## Available Tools
530
544
 
531
- ### Core Browser Tools
532
-
533
- | Tool Name | Description | Required Parameters | Optional Parameters |
534
- |-----------|-------------|---------------------|-------------------|
535
- | `browser_init` | Initialize stealth browser with advanced options | None | `headless`, `disableXvfb`, `ignoreAllFlags`, `proxy`, `plugins`, `connectOption` |
536
- | `navigate` | Navigate to a URL | `url` | `waitUntil` |
537
- | `get_content` | Get page content (HTML or text) | None | `type`, `selector` |
538
- | `browser_close` | Close the browser instance | None | None |
539
-
540
- ### Interaction Tools
541
-
542
- | Tool Name | Description | Required Parameters | Optional Parameters |
543
- |-----------|-------------|---------------------|-------------------|
544
- | `click` | Standard click on element | `selector` | `waitForNavigation` |
545
- | `type` | Type text into input field | `selector`, `text` | `delay` |
546
- | `wait` | Wait for various conditions | `type`, `value` | `timeout` |
547
- | `find_selector` | Find CSS selector for element containing specific text | `text` | `elementType`, `exact` |
548
-
549
-
550
- ### Behavior Tools
551
-
552
- | Tool Name | Description | Required Parameters | Optional Parameters |
553
- |-----------|-------------|---------------------|-------------------|
554
- | `random_scroll` | Perform random scrolling with natural timing | None | None |
555
-
556
- ### Element Discovery Tools
557
-
558
- | Tool Name | Description | Required Parameters | Optional Parameters |
559
- |-----------|-------------|---------------------|-------------------|
560
- | `find_selector` | Find CSS selector for element containing specific text | `text` | `elementType`, `exact` |
561
-
562
- ### Content Tools
563
-
564
- | Tool Name | Description | Required Parameters | Optional Parameters |
565
- |-----------|-------------|---------------------|-------------------|
566
- | `save_content_as_markdown` | Extract page content and save it as a formatted markdown file | `filePath` | `contentType`, `selector`, `formatOptions` |
567
-
568
- ### Anti-Detection Tools
569
-
570
- | Tool Name | Description | Required Parameters | Optional Parameters |
571
- |-----------|-------------|---------------------|-------------------|
572
- | `solve_captcha` | Attempt to solve captchas | `type` | None |
545
+ ### ๐ŸŽฏ **Complete Professional Toolset - 62 Tools**
546
+
547
+ This MCP server provides **62 professional-grade tools** organized into 11 major categories:
548
+
549
+ ### ๐Ÿ”ฅ **Core Browser Management (11 Tools)**
550
+ 1. `browser_init` - Initialize stealth browser with advanced options
551
+ 2. `navigate` - Navigate to a URL
552
+ 3. `get_content` - Get page content (HTML or text)
553
+ 4. `click` - Click on elements
554
+ 5. `type` - Type text into input fields
555
+ 6. `wait` - Wait for various conditions
556
+ 7. `browser_close` - Close browser instance
557
+ 8. `solve_captcha` - Solve captchas (reCAPTCHA, hCaptcha, Turnstile)
558
+ 9. `random_scroll` - Natural scrolling behavior
559
+ 10. `find_selector` - Find CSS selectors by text content
560
+ 11. `save_content_as_markdown` - Save page content as markdown
561
+
562
+ ### ๐Ÿ“Š **Smart Data Extractors (5 Tools)**
563
+ 12. `scrape_table` - Extract structured data from HTML tables
564
+ 13. `extract_list` - Extract data from bullet and numbered lists
565
+ 14. `extract_json` - Extract embedded JSON/API data
566
+ 15. `scrape_meta_tags` - Extract SEO meta tags and Open Graph data
567
+ 16. `extract_schema` - Extract Schema.org structured data
568
+
569
+ ### ๐Ÿ”„ **Multi-Element Extractors (7 Tools)**
570
+ 17. `batch_element_scraper` - Scrape multiple similar elements in batch
571
+ 18. `nested_data_extraction` - Extract data maintaining parent-child relationships
572
+ 19. `attribute_harvester` - Collect element attributes (href, src, data-*)
573
+ 20. `image_scraper` - Extract image URLs, alt text, dimensions
574
+ 21. `link_harvester` - Collect internal/external links with classification
575
+ 22. `media_extractor` - Extract video, audio, iframe URLs and metadata
576
+ 23. `pdf_link_finder` - Find downloadable files (PDF, DOC, etc.)
577
+
578
+ ### ๐Ÿ“„ **Pagination Tools (5 Tools)**
579
+ 24. `auto_pagination` - Automatically detect and navigate through pages
580
+ 25. `infinite_scroll` - Handle lazy-loading pages with auto-scroll
581
+ 26. `multi_page_scraper` - Collect data from multiple pages
582
+ 27. `sitemap_parser` - Extract URLs from sitemap.xml
583
+ 28. `breadcrumb_navigator` - Navigate site structure using breadcrumbs
584
+
585
+ ### ๐Ÿงน **Data Processing Tools (8 Tools)**
586
+ 29. `smart_text_cleaner` - Clean and normalize text data
587
+ 30. `html_to_text` - Convert HTML to clean text
588
+ 31. `price_parser` - Extract numbers from currency strings
589
+ 32. `date_normalizer` - Convert various date formats to standard format
590
+ 33. `contact_extractor` - Detect phone numbers and email addresses
591
+ 34. `schema_validator` - Validate data against JSON schema
592
+ 35. `required_fields_checker` - Check for missing required fields
593
+ 36. `duplicate_remover` - Remove duplicate items from arrays
594
+
595
+ ### ๐Ÿค– **AI-Powered Features (5 Tools)**
596
+ 37. `smart_selector_generator` - AI-based CSS selector generation
597
+ 38. `content_classification` - Classify webpage content into categories
598
+ 39. `sentiment_analysis` - Analyze sentiment of page content
599
+ 40. `summary_generator` - Generate page content summaries using TF-IDF
600
+ 41. `translation_support` - Detect language and provide translation info
601
+
602
+ ### ๐Ÿ” **Search & Filter Tools (5 Tools)**
603
+ 42. `keyword_search` - Advanced keyword search with context
604
+ 43. `regex_pattern_matcher` - Search using regular expressions
605
+ 44. `xpath_support` - Query elements using XPath expressions
606
+ 45. `advanced_css_selectors` - Support for complex CSS selectors
607
+ 46. `visual_element_finder` - Find elements by visual properties
608
+
609
+ ### ๐Ÿ”ง **Data Quality & Validation (5 Tools)**
610
+ 47. `data_deduplication` - Advanced duplicate removal with fuzzy matching
611
+ 48. `missing_data_handler` - Detect and handle missing data
612
+ 49. `data_type_validator` - Validate data types against JSON schema
613
+ 50. `outlier_detection` - Detect outliers in numerical data
614
+ 51. `consistency_checker` - Check data consistency across fields
615
+
616
+ ### ๐Ÿ›ก๏ธ **Advanced Captcha Handling (3 Tools)**
617
+ 52. `ocr_engine` - Extract text from images using OCR
618
+ 53. `audio_captcha_solver` - Handle audio captchas
619
+ 54. `puzzle_captcha_handler` - Handle slider and puzzle captchas
620
+
621
+ ### ๐Ÿ“ธ **Screenshot & Visual Tools (5 Tools)**
622
+ 55. `full_page_screenshot` - Capture complete page screenshots
623
+ 56. `element_screenshot` - Capture screenshots of specific elements
624
+ 57. `pdf_generation` - Convert pages to PDF
625
+ 58. `video_recording` - Record browser sessions
626
+ 59. `visual_comparison` - Compare two screenshots for differences
627
+
628
+ ### ๐ŸŒ **Website API Integration (3 Tools)**
629
+ 60. `rest_api_endpoint_finder` - Discover REST API endpoints
630
+ 61. `webhook_support` - Set up and test webhooks
631
+ 62. `all_website_api_finder` - Comprehensive API discovery
632
+
633
+ ---
634
+
635
+ ### ๐Ÿ“ **Usage Examples**
636
+
637
+ | Category | Example Usage |
638
+ |----------|---------------|
639
+ | **Basic Browsing** | `browser_init` โ†’ `navigate` โ†’ `get_content` |
640
+ | **Data Extraction** | `scrape_table` โ†’ `smart_text_cleaner` โ†’ `duplicate_remover` |
641
+ | **Form Automation** | `find_selector` โ†’ `type` โ†’ `click` โ†’ `wait` |
642
+ | **Content Analysis** | `get_content` โ†’ `sentiment_analysis` โ†’ `summary_generator` |
643
+ | **Visual Capture** | `full_page_screenshot` โ†’ `element_screenshot` |
644
+ | **Quality Control** | `data_type_validator` โ†’ `consistency_checker` |
573
645
 
574
646
  ## Advanced Features
575
647
 
@@ -109,33 +109,48 @@ export function categorizeError(error) {
109
109
  // Timeout wrapper for operations that may hang
110
110
  export async function withTimeout(operation, timeoutMs, context = 'unknown') {
111
111
  return new Promise((resolve, reject) => {
112
+ let isResolved = false;
112
113
  const timer = setTimeout(() => {
113
- reject(new Error(`Operation timed out after ${timeoutMs}ms in context: ${context}`));
114
+ if (!isResolved) {
115
+ isResolved = true;
116
+ reject(new Error(`Operation timed out after ${timeoutMs}ms in context: ${context}`));
117
+ }
114
118
  }, timeoutMs);
115
119
  operation()
116
120
  .then((result) => {
117
- clearTimeout(timer);
118
- resolve(result);
121
+ if (!isResolved) {
122
+ isResolved = true;
123
+ clearTimeout(timer);
124
+ resolve(result);
125
+ }
119
126
  })
120
127
  .catch((error) => {
121
- clearTimeout(timer);
122
- reject(error);
128
+ if (!isResolved) {
129
+ isResolved = true;
130
+ clearTimeout(timer);
131
+ reject(error);
132
+ }
123
133
  });
124
134
  });
125
135
  }
126
136
  // Port availability and connection utilities for enhanced resilience
127
137
  export async function isPortAvailable(port, host = '127.0.0.1') {
128
138
  return new Promise((resolve) => {
129
- const server = net.createServer();
130
- server.listen(port, host, () => {
131
- server.once('close', () => {
132
- resolve(true);
139
+ try {
140
+ const server = net.createServer();
141
+ server.listen(port, host, () => {
142
+ server.once('close', () => {
143
+ resolve(true);
144
+ });
145
+ server.close();
133
146
  });
134
- server.close();
135
- });
136
- server.on('error', () => {
147
+ server.on('error', () => {
148
+ resolve(false);
149
+ });
150
+ }
151
+ catch (error) {
137
152
  resolve(false);
138
- });
153
+ }
139
154
  });
140
155
  }
141
156
  // Test localhost resolution and connectivity
@@ -247,57 +262,8 @@ function getWindowsBraveFromRegistry() {
247
262
  }
248
263
  return null;
249
264
  }
250
- // Windows Registry Chrome detection
251
- function getWindowsChromeFromRegistry() {
252
- if (process.platform !== 'win32')
253
- return null;
254
- try {
255
- const { execSync } = require('child_process');
256
- const registryQueries = [
257
- 'reg query "HKEY_CURRENT_USER\\Software\\Google\\Chrome\\BLBeacon" /v version 2>nul',
258
- 'reg query "HKEY_LOCAL_MACHINE\\Software\\Google\\Chrome\\BLBeacon" /v version 2>nul',
259
- 'reg query "HKEY_LOCAL_MACHINE\\Software\\WOW6432Node\\Google\\Chrome\\BLBeacon" /v version 2>nul',
260
- ];
261
- for (const query of registryQueries) {
262
- try {
263
- const result = execSync(query, { encoding: 'utf8', timeout: 5000 });
264
- if (result) {
265
- const standardPaths = [
266
- 'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe',
267
- 'C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe'
268
- ];
269
- for (const standardPath of standardPaths) {
270
- if (fs.existsSync(standardPath)) {
271
- console.error(`โœ“ Found Chrome via Registry detection: ${standardPath}`);
272
- return standardPath;
273
- }
274
- }
275
- }
276
- }
277
- catch (error) {
278
- // Continue to next registry query
279
- }
280
- }
281
- try {
282
- const installDirQuery = 'reg query "HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\chrome.exe" /ve 2>nul';
283
- const result = execSync(installDirQuery, { encoding: 'utf8', timeout: 5000 });
284
- const match = result.match(/REG_SZ\s+(.+\.exe)/);
285
- if (match && match[1] && fs.existsSync(match[1])) {
286
- console.error(`โœ“ Found Chrome via App Paths registry: ${match[1]}`);
287
- return match[1];
288
- }
289
- }
290
- catch (error) {
291
- // Registry detection failed, will fall back to file system search
292
- }
293
- }
294
- catch (error) {
295
- console.error('Windows Registry Chrome detection failed:', error instanceof Error ? error.message : String(error));
296
- }
297
- return null;
298
- }
299
265
  // Brave Browser path detection (cross-platform support)
300
- // Purely Brave-focused - no Chrome fallback needed since system works perfectly without Chrome
266
+ // Pure Brave-only detection - This project is designed specifically for Brave Browser
301
267
  export function detectBravePath() {
302
268
  const platform = process.platform;
303
269
  // PRIORITY -1: Use brave-real-launcher's professional detection (BEST METHOD)
@@ -327,20 +293,14 @@ export function detectBravePath() {
327
293
  catch (error) {
328
294
  // Config file not found or invalid, continue with other methods
329
295
  }
330
- // PRIORITY 1: Check environment variables first (BRAVE_PATH has priority)
296
+ // PRIORITY 1: Check environment variables first (BRAVE_PATH only)
331
297
  const envBravePath = process.env.BRAVE_PATH;
332
298
  if (envBravePath && fs.existsSync(envBravePath)) {
333
299
  console.error(`โœ“ Found Brave via BRAVE_PATH environment variable: ${envBravePath}`);
334
300
  return envBravePath;
335
301
  }
336
- const envChromePath = process.env.CHROME_PATH || process.env.PUPPETEER_EXECUTABLE_PATH;
337
- if (envChromePath && fs.existsSync(envChromePath)) {
338
- console.error(`โœ“ Found Chrome via environment variable: ${envChromePath}`);
339
- return envChromePath;
340
- }
341
- // PRIORITY 2: Try Brave paths FIRST (this is Brave-Real-Browser project!)
302
+ // PRIORITY 2: Brave paths detection (Brave-only project!)
342
303
  let bravePaths = [];
343
- let chromePaths = [];
344
304
  switch (platform) {
345
305
  case 'win32':
346
306
  // BRAVE PATHS (PRIORITY - Try these first!)
@@ -352,23 +312,7 @@ export function detectBravePath() {
352
312
  path.join(process.env.PROGRAMFILES || '', 'BraveSoftware\\Brave-Browser\\Application\\brave.exe'),
353
313
  path.join(process.env['PROGRAMFILES(X86)'] || '', 'BraveSoftware\\Brave-Browser\\Application\\brave.exe'),
354
314
  ];
355
- // Chrome paths (fallback)
356
- chromePaths = [
357
- 'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe',
358
- 'C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe',
359
- path.join(process.env.LOCALAPPDATA || '', 'Google\\Chrome\\Application\\chrome.exe'),
360
- path.join(process.env.USERPROFILE || '', 'AppData\\Local\\Google\\Chrome\\Application\\chrome.exe'),
361
- path.join(process.env.PROGRAMFILES || '', 'Google\\Chrome\\Application\\chrome.exe'),
362
- path.join(process.env['PROGRAMFILES(X86)'] || '', 'Google\\Chrome\\Application\\chrome.exe'),
363
- path.join(process.env.LOCALAPPDATA || '', 'Google\\Chrome SxS\\Application\\chrome.exe'),
364
- 'C:\\Program Files\\Google\\Chrome SxS\\Application\\chrome.exe',
365
- 'C:\\Users\\Public\\Desktop\\Google Chrome.exe',
366
- path.join(process.env.APPDATA || '', 'Google\\Chrome\\Application\\chrome.exe'),
367
- 'C:\\Chrome\\chrome.exe',
368
- 'C:\\google\\chrome\\chrome.exe',
369
- 'C:\\PortableApps\\GoogleChromePortable\\App\\Chrome-bin\\chrome.exe',
370
- ];
371
- // Try Brave registry first
315
+ // Try Brave registry detection
372
316
  try {
373
317
  const braveRegistryPath = getWindowsBraveFromRegistry();
374
318
  if (braveRegistryPath) {
@@ -378,16 +322,6 @@ export function detectBravePath() {
378
322
  catch (error) {
379
323
  console.error('Brave registry detection failed, continuing with file system search...');
380
324
  }
381
- // Try Chrome registry as fallback
382
- try {
383
- const chromeRegistryPath = getWindowsChromeFromRegistry();
384
- if (chromeRegistryPath) {
385
- chromePaths.unshift(chromeRegistryPath);
386
- }
387
- }
388
- catch (error) {
389
- console.error('Chrome registry detection failed, continuing with file system search...');
390
- }
391
325
  break;
392
326
  case 'darwin':
393
327
  // BRAVE PATHS (PRIORITY)
@@ -397,12 +331,6 @@ export function detectBravePath() {
397
331
  '/Applications/Brave Browser Beta.app/Contents/MacOS/Brave Browser Beta',
398
332
  '/Applications/Brave Browser Dev.app/Contents/MacOS/Brave Browser Dev',
399
333
  ];
400
- // Chrome paths (fallback)
401
- chromePaths = [
402
- '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',
403
- '/Applications/Chromium.app/Contents/MacOS/Chromium',
404
- '/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary'
405
- ];
406
334
  break;
407
335
  case 'linux':
408
336
  // BRAVE PATHS (PRIORITY)
@@ -415,16 +343,6 @@ export function detectBravePath() {
415
343
  '/opt/brave/brave-browser',
416
344
  '/usr/local/bin/brave-browser',
417
345
  ];
418
- // Chrome paths (fallback)
419
- chromePaths = [
420
- '/usr/bin/google-chrome',
421
- '/usr/bin/google-chrome-stable',
422
- '/usr/bin/chromium-browser',
423
- '/usr/bin/chromium',
424
- '/snap/bin/chromium',
425
- '/usr/bin/chrome',
426
- '/opt/google/chrome/chrome'
427
- ];
428
346
  break;
429
347
  default:
430
348
  console.error(`Platform ${platform} not explicitly supported for browser path detection`);
@@ -476,26 +394,20 @@ export function detectBravePath() {
476
394
  console.error(` - Set BRAVE_PATH environment variable if needed`);
477
395
  console.error(`\n 2. Environment Variables:`);
478
396
  console.error(` - Set BRAVE_PATH for Brave: set BRAVE_PATH="C:\\Program Files\\BraveSoftware\\Brave-Browser\\Application\\brave.exe"`);
479
- console.error(` - Or set CHROME_PATH for Chrome: set CHROME_PATH="C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe"`);
480
- console.error(` - For Cursor IDE: Add env vars to MCP configuration`);
481
- console.error(`\n 3. Alternative: Install Chrome:`);
482
- console.error(` - Download Chrome: https://www.google.com/chrome/`);
483
- console.error(` - Chrome works as fallback when Brave is not available`);
484
- console.error(`\n 4. Permissions & Security:`);
397
+ console.error(` - For Cursor IDE: Add BRAVE_PATH env var to MCP configuration`);
398
+ console.error(`\n 3. Permissions & Security:`);
485
399
  console.error(` - Run IDE/terminal as Administrator`);
486
- console.error(` - Add browser to Windows Defender exclusions`);
487
- console.error(`\n 5. Custom Configuration:`);
488
- console.error(` - Use customConfig.chromePath parameter in browser_init`);
489
- console.error(` - Works with both Brave and Chrome`);
400
+ console.error(` - Add Brave browser to Windows Defender exclusions`);
401
+ console.error(`\n 4. Custom Configuration:`);
402
+ console.error(` - Use customConfig.chromePath parameter in browser_init (with Brave path)`);
403
+ console.error(` - This project is optimized specifically for Brave Browser`);
490
404
  }
491
405
  else {
492
- console.error(`โŒ Neither Brave nor Chrome found at any expected paths for platform: ${platform}`);
406
+ console.error(`โŒ Brave Browser not found at any expected paths for platform: ${platform}`);
493
407
  console.error(`\n ๐Ÿฆ Brave paths checked:`);
494
408
  bravePaths.forEach(p => console.error(` - ${p}`));
495
- console.error(`\n ๐ŸŒ Chrome paths checked:`);
496
- chromePaths.forEach(p => console.error(` - ${p}`));
497
- console.error(`\n ๐Ÿ’ก Install Brave Browser (recommended): https://brave.com/download/`);
498
- console.error(` ๐Ÿ’ก Or install Chrome as fallback: https://www.google.com/chrome/`);
409
+ console.error(`\n ๐Ÿ’ก Install Brave Browser: https://brave.com/download/`);
410
+ console.error(` ๐Ÿ’ก This project is specifically designed for Brave Browser`);
499
411
  }
500
412
  return null;
501
413
  }
@@ -813,7 +725,7 @@ export async function initializeBrowser(options) {
813
725
  }
814
726
  throw connectionError;
815
727
  }
816
- }, platform === 'win32' ? 180000 : 150000, `browser-connection-${strategyName.toLowerCase().replace(/\s+/g, '-')}`);
728
+ }, platform === 'win32' ? 30000 : 25000, `browser-connection-${strategyName.toLowerCase().replace(/\s+/g, '-')}`);
817
729
  const { browser, page } = result;
818
730
  browserInstance = browser;
819
731
  pageInstance = page;
@@ -954,31 +866,25 @@ export async function closeBrowser() {
954
866
  }
955
867
  }
956
868
  }
957
- // Force kill all Brave and Chrome browser processes system-wide
869
+ // Force kill all Brave browser processes system-wide
958
870
  export async function forceKillBraveProcesses() {
959
871
  try {
960
872
  const { spawn } = await import('child_process');
961
873
  if (process.platform !== 'win32') {
962
- // Kill Brave processes (priority)
874
+ // Kill Brave processes on Unix-like systems
963
875
  spawn('pkill', ['-f', 'Brave Browser'], { stdio: 'ignore' });
964
876
  spawn('pkill', ['-f', 'brave'], { stdio: 'ignore' });
965
- // Kill Chrome processes (fallback)
966
- spawn('pkill', ['-f', 'Google Chrome'], { stdio: 'ignore' });
967
- spawn('pkill', ['-f', 'chrome'], { stdio: 'ignore' });
968
877
  }
969
878
  else {
970
- // Windows: Kill Brave processes (priority)
879
+ // Windows: Kill Brave processes
971
880
  spawn('taskkill', ['/F', '/IM', 'brave.exe'], { stdio: 'ignore' });
972
- // Windows: Kill Chrome processes (fallback)
973
- spawn('taskkill', ['/F', '/IM', 'chrome.exe'], { stdio: 'ignore' });
974
- spawn('taskkill', ['/F', '/IM', 'GoogleChrome.exe'], { stdio: 'ignore' });
975
881
  }
976
882
  }
977
883
  catch (error) {
978
- console.error('Error force-killing browser processes:', error);
884
+ console.error('Error force-killing Brave browser processes:', error);
979
885
  }
980
886
  }
981
- // Alias for backward compatibility
887
+ // Aliases for backward compatibility (now all point to Brave-only function)
982
888
  export const forceKillChromeProcesses = forceKillBraveProcesses;
983
889
  export const forceKillAllChromeProcesses = forceKillBraveProcesses;
984
890
  // Getters for browser instances
@@ -5,7 +5,7 @@
5
5
  * - AAA Pattern (Arrange-Act-Assert)
6
6
  * - Behavior-focused testing with proper mocking
7
7
  * - Error categorization and circuit breaker testing
8
- * - Chrome detection and network utilities testing
8
+ * - Brave detection and network utilities testing
9
9
  */
10
10
  import { describe, it, expect, beforeEach, vi } from 'vitest';
11
11
  import { categorizeError, BrowserErrorType, withTimeout, isPortAvailable, testHostConnectivity, findAvailablePort, updateCircuitBreakerOnFailure, updateCircuitBreakerOnSuccess, isCircuitBreakerOpen, detectBravePath, validateSession, findAuthElements, getContentPriorityConfig, updateContentPriorityConfig, getBrowserInstance, getPageInstance, forceKillBraveProcesses } from './browser-manager.js';
@@ -110,8 +110,8 @@ describe('Browser Manager', () => {
110
110
  });
111
111
  describe('Timeout Wrapper', () => {
112
112
  it('should resolve when operation completes within timeout', async () => {
113
- // Arrange: Create operation that resolves quickly
114
- const operation = vi.fn().mockResolvedValue('success');
113
+ // Arrange: Create operation that resolves immediately
114
+ const operation = vi.fn().mockImplementation(() => Promise.resolve('success'));
115
115
  // Act: Execute with timeout
116
116
  const result = await withTimeout(operation, 1000, 'test-context');
117
117
  // Assert: Should return operation result
@@ -127,21 +127,22 @@ describe('Browser Manager', () => {
127
127
  expect(operation).toHaveBeenCalledOnce();
128
128
  });
129
129
  it('should reject when operation throws error', async () => {
130
- // Arrange: Create operation that throws
131
- const operation = vi.fn().mockRejectedValue(new Error('operation failed'));
130
+ // Arrange: Create operation that throws immediately
131
+ const operation = vi.fn().mockImplementation(() => Promise.reject(new Error('operation failed')));
132
132
  // Act & Assert: Should propagate operation error
133
133
  await expect(withTimeout(operation, 1000, 'test-context'))
134
134
  .rejects.toThrow('operation failed');
135
135
  expect(operation).toHaveBeenCalledOnce();
136
136
  });
137
137
  it('should clear timeout when operation completes', async () => {
138
- // Arrange: Create operation that resolves
139
- const operation = vi.fn().mockResolvedValue('success');
138
+ // Arrange: Create operation that resolves immediately
139
+ const operation = vi.fn().mockImplementation(() => Promise.resolve('success'));
140
140
  const clearTimeoutSpy = vi.spyOn(global, 'clearTimeout');
141
141
  // Act: Execute with timeout
142
142
  await withTimeout(operation, 1000, 'test-context');
143
143
  // Assert: Should clear timeout
144
144
  expect(clearTimeoutSpy).toHaveBeenCalled();
145
+ clearTimeoutSpy.mockRestore();
145
146
  });
146
147
  });
147
148
  describe('Port Availability', () => {
@@ -46,7 +46,7 @@ export async function handleRESTAPIEndpointFinder(args) {
46
46
  await page.goto(url, { waitUntil: 'networkidle2', timeout: 30000 });
47
47
  }
48
48
  // Wait for additional requests
49
- await page.waitForTimeout(scanDuration);
49
+ await new Promise(resolve => setTimeout(resolve, scanDuration));
50
50
  page.off('request', requestHandler);
51
51
  }
52
52
  // Also scan page content for API endpoints
@@ -207,7 +207,7 @@ export async function handlePuzzleCaptchaHandler(args) {
207
207
  const stepSize = targetDistance / steps;
208
208
  for (let i = 0; i < steps; i++) {
209
209
  await page.mouse.move(box.x + box.width / 2 + (stepSize * i), box.y + box.height / 2, { steps: 5 });
210
- await page.waitForTimeout(50 + Math.random() * 50); // Random delay for human-like behavior
210
+ await new Promise(resolve => setTimeout(resolve, 50 + Math.random() * 50)); // Random delay for human-like behavior
211
211
  }
212
212
  await page.mouse.up();
213
213
  result.attemptedSolve = true;
@@ -1,7 +1,7 @@
1
1
  // Pagination & Navigation Tools
2
2
  // Auto pagination, infinite scroll, multi-page scraping, sitemap parser
3
3
  // @ts-nocheck
4
- import { getCurrentPage } from '../browser-manager.js';
4
+ import { getPageInstance } from '../browser-manager.js';
5
5
  import { validateWorkflow } from '../workflow-validation.js';
6
6
  import { withErrorHandling } from '../system-utils.js';
7
7
  import * as xml2js from 'xml2js';
@@ -14,7 +14,10 @@ export async function handleAutoPagination(args) {
14
14
  requireBrowser: true,
15
15
  requirePage: true,
16
16
  });
17
- const page = getCurrentPage();
17
+ const page = getPageInstance();
18
+ if (!page) {
19
+ throw new Error('Browser not initialized. Call browser_init first.');
20
+ }
18
21
  const nextButtonSelector = args.nextButtonSelector || 'a[rel="next"], button:contains("Next"), .next, .pagination-next';
19
22
  const maxPages = args.maxPages || 10;
20
23
  const dataSelector = args.dataSelector;
@@ -51,14 +54,14 @@ export async function handleAutoPagination(args) {
51
54
  }
52
55
  // Click next button
53
56
  await nextButton.click();
54
- await page.waitForTimeout(waitBetweenPages);
57
+ await new Promise(resolve => setTimeout(resolve, waitBetweenPages));
55
58
  // Wait for navigation or content load
56
59
  try {
57
60
  await page.waitForNavigation({ timeout: 5000, waitUntil: 'domcontentloaded' });
58
61
  }
59
62
  catch (e) {
60
63
  // No navigation occurred, content loaded dynamically
61
- await page.waitForTimeout(1000);
64
+ await new Promise(resolve => setTimeout(resolve, 1000));
62
65
  }
63
66
  currentPage++;
64
67
  }
@@ -81,7 +84,10 @@ export async function handleInfiniteScroll(args) {
81
84
  requireBrowser: true,
82
85
  requirePage: true,
83
86
  });
84
- const page = getCurrentPage();
87
+ const page = getPageInstance();
88
+ if (!page) {
89
+ throw new Error('Browser not initialized. Call browser_init first.');
90
+ }
85
91
  const maxScrolls = args.maxScrolls || 10;
86
92
  const scrollDelay = args.scrollDelay || 1000;
87
93
  const dataSelector = args.dataSelector;
@@ -114,7 +120,7 @@ export async function handleInfiniteScroll(args) {
114
120
  window.scrollTo(0, document.body.scrollHeight);
115
121
  });
116
122
  // Wait for new content to load
117
- await page.waitForTimeout(scrollDelay);
123
+ await new Promise(resolve => setTimeout(resolve, scrollDelay));
118
124
  scrollCount++;
119
125
  }
120
126
  return {
@@ -136,7 +142,10 @@ export async function handleMultiPageScraper(args) {
136
142
  requireBrowser: true,
137
143
  requirePage: true,
138
144
  });
139
- const page = getCurrentPage();
145
+ const page = getPageInstance();
146
+ if (!page) {
147
+ throw new Error('Browser not initialized. Call browser_init first.');
148
+ }
140
149
  const urls = args.urls;
141
150
  const dataSelector = args.dataSelector;
142
151
  const waitBetweenPages = args.waitBetweenPages || 1000;
@@ -145,7 +154,7 @@ export async function handleMultiPageScraper(args) {
145
154
  const url = urls[i];
146
155
  try {
147
156
  await page.goto(url, { waitUntil: 'domcontentloaded' });
148
- await page.waitForTimeout(waitBetweenPages);
157
+ await new Promise(resolve => setTimeout(resolve, waitBetweenPages));
149
158
  const pageData = await page.evaluate((selector) => {
150
159
  const elements = document.querySelectorAll(selector);
151
160
  return Array.from(elements).map((el) => ({
@@ -187,7 +196,10 @@ export async function handleSitemapParser(args) {
187
196
  requireBrowser: true,
188
197
  requirePage: true,
189
198
  });
190
- const page = getCurrentPage();
199
+ const page = getPageInstance();
200
+ if (!page) {
201
+ throw new Error('Browser not initialized. Call browser_init first.');
202
+ }
191
203
  const currentUrl = page.url();
192
204
  const baseUrl = new URL(currentUrl).origin;
193
205
  const sitemapUrl = args.sitemapUrl || `${baseUrl}/sitemap.xml`;
@@ -255,7 +267,10 @@ export async function handleBreadcrumbNavigator(args) {
255
267
  requireBrowser: true,
256
268
  requirePage: true,
257
269
  });
258
- const page = getCurrentPage();
270
+ const page = getPageInstance();
271
+ if (!page) {
272
+ throw new Error('Browser not initialized. Call browser_init first.');
273
+ }
259
274
  const breadcrumbSelector = args.breadcrumbSelector || '.breadcrumb, nav[aria-label="breadcrumb"], .breadcrumbs';
260
275
  const followLinks = args.followLinks || false;
261
276
  const breadcrumbData = await page.evaluate((selector) => {
@@ -236,7 +236,7 @@ export async function handleVideoRecording(args) {
236
236
  const framePath = path.join(framesDir, `frame_${i.toString().padStart(4, '0')}.png`);
237
237
  await page.screenshot({ path: framePath });
238
238
  frames.push(framePath);
239
- await page.waitForTimeout(frameDelay);
239
+ await new Promise(resolve => setTimeout(resolve, frameDelay));
240
240
  }
241
241
  }
242
242
  return {
package/dist/index.js CHANGED
@@ -13,7 +13,7 @@ import { TOOLS, SERVER_INFO, CAPABILITIES, TOOL_NAMES } from './tool-definitions
13
13
  console.error('๐Ÿ” [DEBUG] Loading system utils...');
14
14
  import { withErrorHandling } from './system-utils.js';
15
15
  console.error('๐Ÿ” [DEBUG] Loading browser manager...');
16
- import { closeBrowser, forceKillAllChromeProcesses } from './browser-manager.js';
16
+ import { closeBrowser, forceKillBraveProcesses } from './browser-manager.js';
17
17
  console.error('๐Ÿ” [DEBUG] Loading core infrastructure...');
18
18
  import { setupProcessCleanup } from './core-infrastructure.js';
19
19
  // Import handlers
@@ -266,7 +266,7 @@ async function main() {
266
266
  setupProcessCleanup(async () => {
267
267
  console.error('๐Ÿ” [DEBUG] Process cleanup triggered');
268
268
  await closeBrowser();
269
- await forceKillAllChromeProcesses();
269
+ await forceKillBraveProcesses();
270
270
  });
271
271
  // Create and start the server transport
272
272
  console.error('๐Ÿ” [DEBUG] Creating StdioServerTransport...');
@@ -25,7 +25,7 @@ export const DEFAULT_CONTENT_PRIORITY_CONFIG = {
25
25
  export const TOOLS = [
26
26
  {
27
27
  name: 'browser_init',
28
- description: 'Initialize a new browser instance with anti-detection features and automatic Chrome path detection',
28
+ description: 'Initialize a new browser instance with anti-detection features and automatic Brave Browser path detection',
29
29
  inputSchema: {
30
30
  type: 'object',
31
31
  properties: {
@@ -41,7 +41,7 @@ export const TOOLS = [
41
41
  },
42
42
  ignoreAllFlags: {
43
43
  type: 'boolean',
44
- description: 'Ignore all Chrome flags (recommended: true for clean startup without --no-sandbox)',
44
+ description: 'Ignore all browser flags (recommended: true for clean startup without --no-sandbox)',
45
45
  default: true,
46
46
  },
47
47
  proxy: {
@@ -62,11 +62,11 @@ export const TOOLS = [
62
62
  },
63
63
  customConfig: {
64
64
  type: 'object',
65
- description: 'Custom configuration for Chrome launcher. Use chromePath to specify custom Chrome executable path',
65
+ description: 'Custom configuration for Brave launcher. Use chromePath to specify custom Brave executable path',
66
66
  properties: {
67
67
  chromePath: {
68
68
  type: 'string',
69
- description: 'Custom path to Chrome executable (auto-detected if not specified)',
69
+ description: 'Custom path to Brave executable (auto-detected if not specified)',
70
70
  },
71
71
  },
72
72
  additionalProperties: true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "brave-real-browser-mcp-server",
3
- "version": "2.9.5",
3
+ "version": "2.9.6",
4
4
  "description": "MCP server for brave-real-browser",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -34,13 +34,14 @@
34
34
  },
35
35
  "dependencies": {
36
36
  "@modelcontextprotocol/sdk": "^1.20.0",
37
+ "@types/pngjs": "^6.0.5",
37
38
  "@types/turndown": "^5.0.5",
38
39
  "ajv": "^8.12.0",
39
- "axios": "^1.6.5",
40
+ "axios": "^1.12.2",
40
41
  "brave-real-browser": "^1.5.102",
41
42
  "brave-real-launcher": "^1.2.16",
42
- "brave-real-playwright-core": "^1.55.1-patch.1",
43
- "brave-real-puppeteer-core": "^24.23.0-patch.1",
43
+ "brave-real-playwright-core": "^1.56.0",
44
+ "brave-real-puppeteer-core": "^24.24.0",
44
45
  "cheerio": "^1.0.0-rc.12",
45
46
  "chrono-node": "^2.7.0",
46
47
  "compromise": "^14.13.0",