brave-real-browser-mcp-server 2.17.11 → 2.17.13

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.
@@ -237,17 +237,33 @@ export const TOOLS = [
237
237
  },
238
238
  {
239
239
  name: 'solve_captcha',
240
- description: 'Attempt to solve CAPTCHAs (if supported)',
240
+ description: 'Solve various types of CAPTCHAs (Auto-detect, OCR, Audio, Puzzle). Routes to appropriate solver based on arguments.',
241
241
  inputSchema: {
242
242
  type: 'object',
243
243
  properties: {
244
- type: {
244
+ strategy: {
245
245
  type: 'string',
246
- enum: ['recaptcha', 'hCaptcha', 'turnstile'],
247
- description: 'Type of captcha to solve',
246
+ enum: ['auto', 'ocr', 'audio', 'puzzle', 'recaptcha', 'hCaptcha', 'turnstile'],
247
+ description: 'Strategy to use. "auto" attempts to infer based on provided arguments.',
248
+ default: 'auto'
248
249
  },
250
+ // Shared
251
+ url: { type: 'string' },
252
+ // OCR
253
+ selector: { type: 'string' },
254
+ imageUrl: { type: 'string' },
255
+ imageBuffer: { type: 'string' },
256
+ language: { type: 'string' },
257
+ // Audio
258
+ audioSelector: { type: 'string' },
259
+ audioUrl: { type: 'string' },
260
+ downloadPath: { type: 'string' },
261
+ // Puzzle
262
+ puzzleSelector: { type: 'string' },
263
+ sliderSelector: { type: 'string' },
264
+ method: { type: 'string' },
249
265
  },
250
- required: ['type'],
266
+ required: [],
251
267
  },
252
268
  },
253
269
  {
@@ -451,115 +467,60 @@ export const TOOLS = [
451
467
  },
452
468
  },
453
469
  // Search & Filter Tools (5 tools)
470
+ // Search & Filter Tools (Consolidated)
454
471
  {
455
- name: 'keyword_search',
456
- description: 'Advanced keyword search in page content',
472
+ name: 'search_content',
473
+ description: 'Search content using keywords or regex patterns.',
457
474
  inputSchema: {
458
475
  type: 'object',
459
476
  properties: {
477
+ query: { type: 'string', description: 'Keyword or Regex pattern' },
478
+ type: { type: 'string', enum: ['text', 'regex'], default: 'text' },
460
479
  url: { type: 'string' },
461
- keywords: { type: 'array', items: { type: 'string' } },
480
+ // Text options
462
481
  caseSensitive: { type: 'boolean', default: false },
463
482
  wholeWord: { type: 'boolean', default: false },
464
483
  context: { type: 'number', default: 50 },
465
- },
466
- required: ['keywords'],
467
- },
468
- },
469
- {
470
- name: 'regex_pattern_matcher',
471
- description: 'Search using regular expressions',
472
- inputSchema: {
473
- type: 'object',
474
- properties: {
475
- url: { type: 'string' },
476
- pattern: { type: 'string', description: 'Regular expression pattern' },
484
+ // Regex options
477
485
  flags: { type: 'string', default: 'g' },
478
- selector: { type: 'string' },
486
+ selector: { type: 'string', description: 'Limit search to specific element' },
479
487
  },
480
- required: ['pattern'],
488
+ required: ['query'],
481
489
  },
482
490
  },
483
491
  {
484
- name: 'xpath_support',
485
- description: 'Query elements using XPath',
492
+ name: 'find_element_advanced',
493
+ description: 'Find elements using XPath or Advanced CSS selectors.',
486
494
  inputSchema: {
487
495
  type: 'object',
488
496
  properties: {
497
+ query: { type: 'string', description: 'Selector or XPath expression' },
498
+ type: { type: 'string', enum: ['css', 'xpath'], default: 'css' },
489
499
  url: { type: 'string' },
490
- xpath: { type: 'string', description: 'XPath expression' },
491
- returnType: { type: 'string', default: 'elements' },
492
- },
493
- required: ['xpath'],
494
- },
495
- },
496
- {
497
- name: 'advanced_css_selectors',
498
- description: 'Support for complex CSS selectors',
499
- inputSchema: {
500
- type: 'object',
501
- properties: {
502
- url: { type: 'string' },
503
- selector: { type: 'string' },
500
+ // CSS options
504
501
  operation: { type: 'string', enum: ['query', 'closest', 'matches'], default: 'query' },
505
- returnType: { type: 'string', default: 'elements' },
502
+ // Shared
503
+ returnType: { type: 'string', enum: ['elements', 'styles', 'html'], default: 'elements' },
506
504
  },
507
- required: ['selector'],
505
+ required: ['query'],
508
506
  },
509
507
  },
510
508
  // Data Quality & Validation (5 tools)
509
+ // Deep Analysis Tool -- Trace Recording
511
510
  {
512
- name: 'data_type_validator',
513
- description: 'Validate data types against JSON schema',
514
- inputSchema: {
515
- type: 'object',
516
- properties: {
517
- data: { description: 'Data to validate' },
518
- schema: { type: 'object', description: 'JSON Schema' },
519
- },
520
- required: ['data', 'schema'],
521
- },
522
- },
523
- // Advanced Captcha Handling (3 tools)
524
- {
525
- name: 'ocr_engine',
526
- description: 'Extract text from captcha images using OCR',
527
- inputSchema: {
528
- type: 'object',
529
- properties: {
530
- url: { type: 'string' },
531
- selector: { type: 'string' },
532
- imageUrl: { type: 'string' },
533
- imageBuffer: { type: 'string', description: 'Base64 encoded image' },
534
- language: { type: 'string', default: 'eng' },
535
- },
536
- },
537
- },
538
- {
539
- name: 'audio_captcha_solver',
540
- description: 'Handle audio captchas',
511
+ name: 'deep_analysis',
512
+ description: 'Perform a deep analysis of the page including network traces, console logs, DOM snapshot, and screenshot. Equivalent to a trace recording.',
541
513
  inputSchema: {
542
514
  type: 'object',
543
515
  properties: {
544
516
  url: { type: 'string' },
545
- audioSelector: { type: 'string' },
546
- audioUrl: { type: 'string' },
547
- downloadPath: { type: 'string' },
548
- },
549
- },
550
- },
551
- {
552
- name: 'puzzle_captcha_handler',
553
- description: 'Handle slider and puzzle captchas',
554
- inputSchema: {
555
- type: 'object',
556
- properties: {
557
- url: { type: 'string' },
558
- puzzleSelector: { type: 'string' },
559
- sliderSelector: { type: 'string' },
560
- method: { type: 'string', enum: ['auto', 'manual'], default: 'auto' },
561
- },
562
- },
517
+ duration: { type: 'number', default: 5000, description: 'Duration to record (ms)' },
518
+ screenshots: { type: 'boolean', default: true },
519
+ network: { type: 'boolean', default: true },
520
+ logs: { type: 'boolean', default: true },
521
+ dom: { type: 'boolean', default: true }
522
+ }
523
+ }
563
524
  },
564
525
  // Screenshot & Visual Tools (5 tools)
565
526
  {
@@ -745,17 +706,17 @@ export const TOOL_NAMES = {
745
706
  SMART_SELECTOR_GENERATOR: 'smart_selector_generator',
746
707
  CONTENT_CLASSIFICATION: 'content_classification',
747
708
  // Phase 3: Media & Video
748
- // Search & Filter Tools
749
- KEYWORD_SEARCH: 'keyword_search',
750
- REGEX_PATTERN_MATCHER: 'regex_pattern_matcher',
751
- XPATH_SUPPORT: 'xpath_support',
752
- ADVANCED_CSS_SELECTORS: 'advanced_css_selectors',
709
+ // Search & Filter (Consolidated)
710
+ SEARCH_CONTENT: 'search_content',
711
+ FIND_ELEMENT_ADVANCED: 'find_element_advanced',
712
+ // Deep Analysis
713
+ DEEP_ANALYSIS: 'deep_analysis',
753
714
  // Data Quality & Validation
754
- DATA_TYPE_VALIDATOR: 'data_type_validator',
755
- // Advanced Captcha Handling
756
- OCR_ENGINE: 'ocr_engine',
757
- AUDIO_CAPTCHA_SOLVER: 'audio_captcha_solver',
758
- PUZZLE_CAPTCHA_HANDLER: 'puzzle_captcha_handler',
715
+ // (Removed DATA_TYPE_VALIDATOR)
716
+ // Advanced Captcha Handling (Consolidated)
717
+ // OCR_ENGINE: 'ocr_engine', // Merged into solve_captcha
718
+ // AUDIO_CAPTCHA_SOLVER: 'audio_captcha_solver', // Merged
719
+ // PUZZLE_CAPTCHA_HANDLER: 'puzzle_captcha_handler', // Merged
759
720
  // Screenshot & Visual Tools
760
721
  ELEMENT_SCREENSHOT: 'element_screenshot',
761
722
  VIDEO_RECORDING: 'video_recording',
@@ -3,7 +3,7 @@ import { handleNavigate } from '../handlers/navigation-handlers.js';
3
3
  import { handleAdProtectionDetector, handleAdvancedVideoExtraction } from '../handlers/advanced-extraction-handlers.js';
4
4
  import { handleSmartSelectorGenerator } from '../handlers/ai-powered-handlers.js';
5
5
  import { handleNetworkRecorder, handleApiFinder } from '../handlers/smart-data-extractors.js';
6
- import { handleRegexPatternMatcher } from '../handlers/search-filter-handlers.js';
6
+ import { handleSearchContent } from '../handlers/unified-search-handler.js';
7
7
  import { handleRandomScroll } from '../handlers/interaction-handlers.js';
8
8
  async function main() {
9
9
  const targetUrl = "https://multimovies.golf/movies/120-bahadur/";
@@ -70,7 +70,7 @@ async function main() {
70
70
  ];
71
71
  report.infrastructure.patterns = [];
72
72
  for (const check of regexChecks) {
73
- const match = await handleRegexPatternMatcher({ pattern: check.pattern });
73
+ const match = await handleSearchContent({ query: check.pattern, type: 'regex' });
74
74
  if (match && match.content) {
75
75
  report.infrastructure.patterns.push({ type: check.name, result: match.content });
76
76
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "brave-real-browser-mcp-server",
3
- "version": "2.17.11",
3
+ "version": "2.17.13",
4
4
  "description": "Universal AI IDE MCP Server - Auto-detects and supports all AI IDEs (Claude Desktop, Cursor, Windsurf, Cline, Zed, VSCode, Qoder AI, etc.) with Brave browser automation",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -1,257 +0,0 @@
1
- // @ts-nocheck
2
- import { getPageInstance } from '../browser-manager.js';
3
- import Tesseract from 'tesseract.js';
4
- import { sleep } from '../system-utils.js';
5
- /**
6
- * OCR Engine - Extract text from captcha images using OCR
7
- */
8
- export async function handleOCREngine(args) {
9
- const { url, selector, imageUrl, imageBuffer, language = 'eng' } = args;
10
- try {
11
- let imageSource;
12
- if (imageBuffer) {
13
- imageSource = Buffer.from(imageBuffer, 'base64');
14
- }
15
- else if (imageUrl) {
16
- imageSource = imageUrl;
17
- }
18
- else if (selector) {
19
- const page = getPageInstance();
20
- if (!page) {
21
- throw new Error('Browser not initialized. Call browser_init first.');
22
- }
23
- if (url && page.url() !== url) {
24
- await page.goto(url, { waitUntil: 'networkidle2', timeout: 30000 });
25
- }
26
- // Get image element and take screenshot
27
- const element = await page.$(selector);
28
- if (!element) {
29
- throw new Error(`Element not found: ${selector}`);
30
- }
31
- const screenshot = await element.screenshot({ encoding: 'base64' });
32
- imageSource = Buffer.from(screenshot, 'base64');
33
- }
34
- else {
35
- throw new Error('No image source provided');
36
- }
37
- // Perform OCR
38
- const result = await Tesseract.recognize(imageSource, language, {
39
- logger: () => { } // Suppress logs
40
- });
41
- // Clean and process text
42
- const text = result.data.text.trim();
43
- const confidence = result.data.confidence;
44
- // Extract words with their confidence
45
- const words = result.data.words.map(word => ({
46
- text: word.text,
47
- confidence: word.confidence,
48
- bbox: word.bbox
49
- }));
50
- return {
51
- content: [
52
- {
53
- type: "text",
54
- text: `OCR Results:\n- Extracted Text: ${text}\n- Confidence: ${confidence.toFixed(2)}%\n- Words Found: ${words.length}\n- Lines: ${result.data.lines.length}\n- Language: ${language}\n\nWords Detail:\n${words.map((w) => ` "${w.text}" (confidence: ${w.confidence.toFixed(2)}%)`).join('\n')}`
55
- }
56
- ]
57
- };
58
- }
59
- catch (error) {
60
- return {
61
- content: [
62
- {
63
- type: "text",
64
- text: `OCR Engine Error: ${error.message}`
65
- }
66
- ],
67
- isError: true
68
- };
69
- }
70
- }
71
- /**
72
- * Audio Captcha Solver - Handle audio captchas
73
- */
74
- export async function handleAudioCaptchaSolver(args) {
75
- const { url, audioSelector, audioUrl, downloadPath } = args;
76
- try {
77
- const page = getPageInstance();
78
- if (!page) {
79
- throw new Error('Browser not initialized. Call browser_init first.');
80
- }
81
- if (url && page.url() !== url) {
82
- await page.goto(url, { waitUntil: 'networkidle2', timeout: 30000 });
83
- }
84
- let audioSource = audioUrl;
85
- // If selector provided, extract audio URL
86
- if (audioSelector && !audioUrl) {
87
- audioSource = await page.evaluate((sel) => {
88
- const element = document.querySelector(sel);
89
- if (!element)
90
- return null;
91
- if (element.tagName === 'AUDIO') {
92
- return element.src || element.currentSrc;
93
- }
94
- else if (element.tagName === 'SOURCE') {
95
- return element.src;
96
- }
97
- return element.getAttribute('src') || element.getAttribute('data-src');
98
- }, audioSelector);
99
- }
100
- if (!audioSource) {
101
- throw new Error('No audio source found');
102
- }
103
- // Download audio if path provided
104
- let downloaded = false;
105
- if (downloadPath) {
106
- const response = await page.goto(audioSource);
107
- if (response) {
108
- const fs = await import('fs/promises');
109
- const buffer = await response.buffer();
110
- await fs.writeFile(downloadPath, buffer);
111
- downloaded = true;
112
- }
113
- }
114
- return {
115
- content: [
116
- {
117
- type: "text",
118
- text: `Audio Captcha Analysis:\n- Audio URL: ${audioSource}\n- Downloaded: ${downloaded ? 'Yes' : 'No'}${downloaded ? `\n- Download Path: ${downloadPath}` : ''}\n\nNote: Audio captcha solving requires external speech-to-text API (Google Speech, AWS Transcribe, etc.)`
119
- }
120
- ]
121
- };
122
- }
123
- catch (error) {
124
- return {
125
- content: [
126
- {
127
- type: "text",
128
- text: `Audio Captcha Solver Error: ${error.message}`
129
- }
130
- ],
131
- isError: true
132
- };
133
- }
134
- }
135
- /**
136
- * Puzzle Captcha Handler - Handle slider and puzzle captchas
137
- */
138
- export async function handlePuzzleCaptchaHandler(args) {
139
- const { url, puzzleSelector, sliderSelector, method = 'auto' } = args;
140
- try {
141
- const page = getPageInstance();
142
- if (!page) {
143
- throw new Error('Browser not initialized. Call browser_init first.');
144
- }
145
- if (url && page.url() !== url) {
146
- await page.goto(url, { waitUntil: 'networkidle2', timeout: 30000 });
147
- }
148
- const result = await page.evaluate(async (puzzleSel, sliderSel, meth) => {
149
- const puzzleElement = puzzleSel ? document.querySelector(puzzleSel) : null;
150
- const sliderElement = sliderSel ? document.querySelector(sliderSel) : null;
151
- if (!puzzleElement && !sliderElement) {
152
- throw new Error('No puzzle or slider element found');
153
- }
154
- const info = {
155
- puzzleFound: !!puzzleElement,
156
- sliderFound: !!sliderElement
157
- };
158
- // Get puzzle dimensions if exists
159
- if (puzzleElement) {
160
- const rect = puzzleElement.getBoundingClientRect();
161
- info.puzzle = {
162
- width: rect.width,
163
- height: rect.height,
164
- top: rect.top,
165
- left: rect.left,
166
- visible: rect.width > 0 && rect.height > 0
167
- };
168
- // Check for puzzle piece
169
- const puzzlePiece = puzzleElement.querySelector('.puzzle-piece, [class*="piece"], [class*="puzzle"]');
170
- if (puzzlePiece) {
171
- const pieceRect = puzzlePiece.getBoundingClientRect();
172
- info.puzzlePiece = {
173
- width: pieceRect.width,
174
- height: pieceRect.height,
175
- top: pieceRect.top,
176
- left: pieceRect.left
177
- };
178
- }
179
- }
180
- // Get slider info if exists
181
- if (sliderElement) {
182
- const rect = sliderElement.getBoundingClientRect();
183
- info.slider = {
184
- width: rect.width,
185
- height: rect.height,
186
- top: rect.top,
187
- left: rect.left,
188
- visible: rect.width > 0 && rect.height > 0,
189
- tagName: sliderElement.tagName.toLowerCase()
190
- };
191
- }
192
- return info;
193
- }, puzzleSelector || '', sliderSelector || '', method);
194
- // If auto method, attempt to solve
195
- if (method === 'auto' && sliderSelector) {
196
- try {
197
- const sliderElement = await page.$(sliderSelector);
198
- if (sliderElement) {
199
- const box = await sliderElement.boundingBox();
200
- if (box) {
201
- // Simulate drag - this is a basic implementation
202
- // Real puzzle solving would need image analysis
203
- await page.mouse.move(box.x + box.width / 2, box.y + box.height / 2);
204
- await page.mouse.down();
205
- // Move in small increments
206
- const targetDistance = result.puzzle?.width || 300;
207
- const steps = 20;
208
- const stepSize = targetDistance / steps;
209
- for (let i = 0; i < steps; i++) {
210
- await page.mouse.move(box.x + box.width / 2 + (stepSize * i), box.y + box.height / 2, { steps: 5 });
211
- await sleep(50 + Math.random() * 50); // Random delay for human-like behavior
212
- }
213
- await page.mouse.up();
214
- result.attemptedSolve = true;
215
- result.method = 'automated_drag';
216
- }
217
- }
218
- }
219
- catch (solveError) {
220
- result.solveError = solveError.message;
221
- }
222
- }
223
- let summary = `Puzzle Captcha Analysis:\n- Puzzle Found: ${result.puzzleFound ? 'Yes' : 'No'}\n- Slider Found: ${result.sliderFound ? 'Yes' : 'No'}`;
224
- if (result.puzzle) {
225
- summary += `\n\nPuzzle Details:\n- Dimensions: ${result.puzzle.width}x${result.puzzle.height}\n- Position: (${result.puzzle.left}, ${result.puzzle.top})\n- Visible: ${result.puzzle.visible ? 'Yes' : 'No'}`;
226
- }
227
- if (result.puzzlePiece) {
228
- summary += `\n\nPuzzle Piece:\n- Dimensions: ${result.puzzlePiece.width}x${result.puzzlePiece.height}\n- Position: (${result.puzzlePiece.left}, ${result.puzzlePiece.top})`;
229
- }
230
- if (result.slider) {
231
- summary += `\n\nSlider Details:\n- Dimensions: ${result.slider.width}x${result.slider.height}\n- Position: (${result.slider.left}, ${result.slider.top})\n- Visible: ${result.slider.visible ? 'Yes' : 'No'}\n- Tag: ${result.slider.tagName}`;
232
- }
233
- if (result.attemptedSolve) {
234
- summary += `\n\nSolve Attempt:\n- Method: ${result.method}\n- Status: ${result.solveError ? 'Failed' : 'Completed'}${result.solveError ? `\n- Error: ${result.solveError}` : ''}`;
235
- }
236
- summary += `\n\nNote: Advanced puzzle solving requires computer vision libraries (OpenCV, TensorFlow)`;
237
- return {
238
- content: [
239
- {
240
- type: "text",
241
- text: summary
242
- }
243
- ]
244
- };
245
- }
246
- catch (error) {
247
- return {
248
- content: [
249
- {
250
- type: "text",
251
- text: `Puzzle Captcha Handler Error: ${error.message}`
252
- }
253
- ],
254
- isError: true
255
- };
256
- }
257
- }
@@ -1,82 +0,0 @@
1
- // @ts-nocheck
2
- import Ajv from 'ajv/dist/2020.js';
3
- const ajv = new Ajv();
4
- /**
5
- * Data Deduplication - Remove duplicate entries from scraped data
6
- */
7
- /**
8
- * Missing Data Handler - Detect and handle missing data
9
- */
10
- /**
11
- * Data Type Validator - Validate data types against schema
12
- */
13
- export async function handleDataTypeValidator(args) {
14
- const { data, schema } = args;
15
- try {
16
- if (!schema) {
17
- throw new Error('Schema is required');
18
- }
19
- const validate = ajv.compile(schema);
20
- const validItems = [];
21
- const invalidItems = [];
22
- if (Array.isArray(data)) {
23
- data.forEach((item, index) => {
24
- const valid = validate(item);
25
- if (valid) {
26
- validItems.push(item);
27
- }
28
- else {
29
- invalidItems.push({
30
- item,
31
- index,
32
- errors: validate.errors
33
- });
34
- }
35
- });
36
- }
37
- else {
38
- const valid = validate(data);
39
- if (valid) {
40
- validItems.push(data);
41
- }
42
- else {
43
- invalidItems.push({
44
- item: data,
45
- errors: validate.errors
46
- });
47
- }
48
- }
49
- const total = Array.isArray(data) ? data.length : 1;
50
- const validationRate = ((validItems.length / total) * 100).toFixed(2);
51
- let summary = `Data Type Validation Results:\n\nStatistics:\n- Total Items: ${total}\n- Valid Items: ${validItems.length}\n- Invalid Items: ${invalidItems.length}\n- Validation Rate: ${validationRate}%`;
52
- if (invalidItems.length > 0) {
53
- summary += `\n\nInvalid Items (Top 5):\n${invalidItems.slice(0, 5).map((inv, i) => {
54
- const errorMsgs = inv.errors?.map((e) => `${e.instancePath || 'root'}: ${e.message}`).join(', ') || 'Unknown error';
55
- return `${i + 1}. Index ${inv.index || 'N/A'}:\n Errors: ${errorMsgs}`;
56
- }).join('\n')}`;
57
- }
58
- summary += `\n\nSchema: ${JSON.stringify(schema, null, 2).substring(0, 200)}${JSON.stringify(schema).length > 200 ? '...' : ''}`;
59
- return {
60
- content: [
61
- {
62
- type: "text",
63
- text: summary
64
- }
65
- ]
66
- };
67
- }
68
- catch (error) {
69
- return {
70
- content: [
71
- {
72
- type: "text",
73
- text: `Data Type Validator Error: ${error.message}`
74
- }
75
- ],
76
- isError: true
77
- };
78
- }
79
- }
80
- /**
81
- * Consistency Checker - Check data consistency across fields
82
- */