brave-real-browser-mcp-server 2.14.6 → 2.14.8

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.
@@ -5,7 +5,12 @@ import * as net from 'net';
5
5
  import { execSync, spawn } from 'child_process';
6
6
  import { config as dotenvConfig } from 'dotenv';
7
7
  // Load environment variables from .env file
8
+ // Silence dotenv output
9
+ const originalWrite = process.stdout.write;
10
+ // @ts-ignore
11
+ process.stdout.write = () => true;
8
12
  dotenvConfig();
13
+ process.stdout.write = originalWrite;
9
14
  // Browser error categorization
10
15
  export var BrowserErrorType;
11
16
  (function (BrowserErrorType) {
@@ -32,7 +32,7 @@ export async function handleUNIVERSAL_TOOL_TEMPLATE(args) {
32
32
  if (shouldCache) {
33
33
  const cached = globalCache.get(cacheKey);
34
34
  if (cached) {
35
- console.log(`[${toolName}] Cache hit for key: ${cacheKey}`);
35
+ console.error(`[${toolName}] Cache hit for key: ${cacheKey}`);
36
36
  return {
37
37
  content: [
38
38
  {
@@ -87,7 +87,7 @@ export async function handleUNIVERSAL_TOOL_TEMPLATE(args) {
87
87
  // Cleanup and metrics
88
88
  const duration = globalMetrics.end(toolName);
89
89
  globalToolStatus.recordExecution(toolName, duration);
90
- console.log(`[${toolName}] Execution time: ${duration}ms`);
90
+ console.error(`[${toolName}] Execution time: ${duration}ms`);
91
91
  }
92
92
  }
93
93
  // ============================================================================
@@ -580,7 +580,7 @@ export async function handleNetworkRecordingFinder(args) {
580
580
  const contentType = response.headers()['content-type'] || '';
581
581
  const resourceType = response.request().resourceType();
582
582
  if (verbose && totalResponses % 10 === 0) {
583
- console.log(`[Network Recording] Processed ${totalResponses} responses, ${matchedResponses} matched`);
583
+ console.error(`[Network Recording] Processed ${totalResponses} responses, ${matchedResponses} matched`);
584
584
  }
585
585
  let shouldRecord = false;
586
586
  const urlLower = url.toLowerCase();
@@ -603,7 +603,7 @@ export async function handleNetworkRecordingFinder(args) {
603
603
  if (shouldRecord) {
604
604
  matchedResponses++;
605
605
  if (verbose) {
606
- console.log(`[Network Recording] ✅ Matched ${filterType}: ${url.substring(0, 100)}`);
606
+ console.error(`[Network Recording] ✅ Matched ${filterType}: ${url.substring(0, 100)}`);
607
607
  }
608
608
  try {
609
609
  const buffer = await response.buffer();
@@ -629,21 +629,21 @@ export async function handleNetworkRecordingFinder(args) {
629
629
  // Ignore individual response errors
630
630
  }
631
631
  };
632
- console.log(`[Network Recording] 🎬 Starting monitoring for ${filterType} (${duration}ms)${navigateTo ? ` + navigating to ${navigateTo}` : ''}`);
632
+ console.error(`[Network Recording] 🎬 Starting monitoring for ${filterType} (${duration}ms)${navigateTo ? ` + navigating to ${navigateTo}` : ''}`);
633
633
  page.on('response', responseHandler);
634
634
  // If navigateTo is provided, navigate first, then wait
635
635
  if (navigateTo) {
636
636
  try {
637
637
  await page.goto(navigateTo, { waitUntil: 'networkidle2', timeout: 30000 });
638
- console.log(`[Network Recording] ✅ Navigation complete, continuing monitoring...`);
638
+ console.error(`[Network Recording] ✅ Navigation complete, continuing monitoring...`);
639
639
  }
640
640
  catch (e) {
641
- console.log(`[Network Recording] ⚠️ Navigation error (continuing anyway): ${e}`);
641
+ console.error(`[Network Recording] ⚠️ Navigation error (continuing anyway): ${e}`);
642
642
  }
643
643
  }
644
644
  await sleep(duration);
645
645
  page.off('response', responseHandler);
646
- console.log(`[Network Recording] 🛑 Monitoring stopped. Total: ${totalResponses}, Matched: ${matchedResponses}, Recorded: ${recordings.length}`);
646
+ console.error(`[Network Recording] 🛑 Monitoring stopped. Total: ${totalResponses}, Matched: ${matchedResponses}, Recorded: ${recordings.length}`);
647
647
  if (recordings.length === 0) {
648
648
  return {
649
649
  content: [{
@@ -717,7 +717,7 @@ export async function handleNetworkRecordingExtractors(args) {
717
717
  (contentType.includes('application/octet-stream') && url.includes('video'));
718
718
  if (isVideoFile || isVideoAPI) {
719
719
  if (verbose)
720
- console.log(`[Extractor] 🎥 Video found: ${url.substring(0, 80)}`);
720
+ console.error(`[Extractor] 🎥 Video found: ${url.substring(0, 80)}`);
721
721
  extractedData.videos.push({
722
722
  url,
723
723
  contentType,
@@ -3,7 +3,6 @@
3
3
  // @ts-nocheck
4
4
  import { withErrorHandling } from '../system-utils.js';
5
5
  import { parsePhoneNumber } from 'libphonenumber-js';
6
- import * as chrono from 'chrono-node';
7
6
  import Ajv from 'ajv/dist/2020.js';
8
7
  /**
9
8
  * Extra whitespace और special characters remove करता है
@@ -85,107 +84,6 @@ export async function handleHTMLToText(args) {
85
84
  };
86
85
  }, 'Failed to convert HTML to text');
87
86
  }
88
- /**
89
- * Currency symbols और formatting से actual numbers निकालता है
90
- */
91
- export async function handlePriceParser(args) {
92
- return await withErrorHandling(async () => {
93
- const text = args.text;
94
- const currency = args.currency;
95
- // Regular expressions for price patterns
96
- const pricePatterns = [
97
- /\$\s?(\d{1,3}(?:,\d{3})*(?:\.\d{2})?)/g, // $1,234.56
98
- /(\d{1,3}(?:,\d{3})*(?:\.\d{2})?)\s?USD/gi, // 1234.56 USD
99
- /€\s?(\d{1,3}(?:,\d{3})*(?:\.\d{2})?)/g, // €1,234.56
100
- /£\s?(\d{1,3}(?:,\d{3})*(?:\.\d{2})?)/g, // £1,234.56
101
- /₹\s?(\d{1,3}(?:,\d{3})*(?:\.\d{2})?)/g, // ₹1,234.56
102
- /(\d{1,3}(?:,\d{3})*(?:\.\d{2})?)/g, // 1,234.56
103
- ];
104
- const prices = [];
105
- pricePatterns.forEach((pattern) => {
106
- let match;
107
- while ((match = pattern.exec(text)) !== null) {
108
- const priceStr = match[1] || match[0];
109
- const numericValue = parseFloat(priceStr.replace(/,/g, ''));
110
- if (!isNaN(numericValue)) {
111
- // Detect currency symbol
112
- let detectedCurrency = currency || 'Unknown';
113
- if (match[0].includes('$'))
114
- detectedCurrency = 'USD';
115
- else if (match[0].includes('€'))
116
- detectedCurrency = 'EUR';
117
- else if (match[0].includes('£'))
118
- detectedCurrency = 'GBP';
119
- else if (match[0].includes('₹'))
120
- detectedCurrency = 'INR';
121
- prices.push({
122
- original: match[0],
123
- value: numericValue,
124
- currency: detectedCurrency,
125
- formatted: `${detectedCurrency} ${numericValue.toFixed(2)}`,
126
- });
127
- }
128
- }
129
- });
130
- // Remove duplicates
131
- const uniquePrices = prices.filter((price, index, self) => index === self.findIndex((p) => p.value === price.value && p.currency === price.currency));
132
- return {
133
- content: [
134
- {
135
- type: 'text',
136
- text: `✅ Parsed ${uniquePrices.length} price(s)\n\n${JSON.stringify(uniquePrices, null, 2)}`,
137
- },
138
- ],
139
- };
140
- }, 'Failed to parse prices');
141
- }
142
- /**
143
- * Different date formats को standard format में convert करता है
144
- */
145
- export async function handleDateNormalizer(args) {
146
- return await withErrorHandling(async () => {
147
- const text = args.text;
148
- const outputFormat = args.outputFormat || 'iso';
149
- // Parse dates using chrono-node
150
- const parsedDates = chrono.parse(text);
151
- const dates = [];
152
- parsedDates.forEach((parsed) => {
153
- const date = parsed.start.date();
154
- let formatted;
155
- if (outputFormat === 'iso') {
156
- formatted = date.toISOString();
157
- }
158
- else if (outputFormat === 'locale') {
159
- formatted = date.toLocaleString();
160
- }
161
- else if (outputFormat === 'unix') {
162
- formatted = Math.floor(date.getTime() / 1000);
163
- }
164
- else {
165
- formatted = date.toISOString();
166
- }
167
- dates.push({
168
- original: parsed.text,
169
- parsed: formatted,
170
- components: {
171
- year: date.getFullYear(),
172
- month: date.getMonth() + 1,
173
- day: date.getDate(),
174
- hour: date.getHours(),
175
- minute: date.getMinutes(),
176
- },
177
- });
178
- });
179
- return {
180
- content: [
181
- {
182
- type: 'text',
183
- text: `✅ Normalized ${dates.length} date(s)\n\n${JSON.stringify(dates, null, 2)}`,
184
- },
185
- ],
186
- };
187
- }, 'Failed to normalize dates');
188
- }
189
87
  /**
190
88
  * Contact information automatically detect करता है
191
89
  */
@@ -110,91 +110,9 @@ export async function handleProgressTracker(args) {
110
110
  throw new Error(`Unknown action: ${action}`);
111
111
  }, 'Failed progress tracker');
112
112
  }
113
- /**
114
- * Error Logger - Log and track errors
115
- */
116
- export async function handleErrorLogger(args) {
117
- return await withErrorHandling(async () => {
118
- const action = args.action || 'log'; // log, get, clear
119
- if (action === 'log') {
120
- const error = {
121
- id: `err_${Date.now()}`,
122
- message: args.message || 'Unknown error',
123
- type: args.type || 'error',
124
- timestamp: new Date().toISOString(),
125
- context: args.context || {},
126
- stackTrace: args.stackTrace || null,
127
- };
128
- monitoringState.errors.push(error);
129
- return {
130
- content: [{
131
- type: 'text',
132
- text: `✅ Error logged: ${error.message}\n\n${JSON.stringify(error, null, 2)}`,
133
- }],
134
- };
135
- }
136
- if (action === 'get') {
137
- const limit = args.limit || 10;
138
- const errorType = args.type;
139
- let filteredErrors = monitoringState.errors;
140
- if (errorType) {
141
- filteredErrors = filteredErrors.filter((err) => err.type === errorType);
142
- }
143
- const recentErrors = filteredErrors.slice(-limit);
144
- return {
145
- content: [{
146
- type: 'text',
147
- text: `✅ Retrieved ${recentErrors.length} error(s)\n\nTotal Errors: ${monitoringState.errors.length}\n\n${JSON.stringify(recentErrors, null, 2)}`,
148
- }],
149
- };
150
- }
151
- if (action === 'clear') {
152
- const count = monitoringState.errors.length;
153
- monitoringState.errors = [];
154
- return {
155
- content: [{
156
- type: 'text',
157
- text: `✅ Cleared ${count} error(s)`,
158
- }],
159
- };
160
- }
161
- throw new Error(`Unknown action: ${action}`);
162
- }, 'Failed error logger');
163
- }
164
113
  /**
165
114
  * Success Rate Reporter - Report success metrics
166
115
  */
167
- export async function handleSuccessRateReporter(args) {
168
- return await withErrorHandling(async () => {
169
- const timeRange = args.timeRange || 'all'; // all, last_hour, last_day
170
- let operations = monitoringState.operations;
171
- if (timeRange === 'last_hour') {
172
- const hourAgo = Date.now() - (60 * 60 * 1000);
173
- operations = operations.filter((op) => op.startTime >= hourAgo);
174
- }
175
- else if (timeRange === 'last_day') {
176
- const dayAgo = Date.now() - (24 * 60 * 60 * 1000);
177
- operations = operations.filter((op) => op.startTime >= dayAgo);
178
- }
179
- const total = operations.length;
180
- const completed = operations.filter((op) => op.status === 'completed').length;
181
- const failed = operations.filter((op) => op.status === 'failed').length;
182
- const inProgress = operations.filter((op) => op.status === 'in_progress').length;
183
- const successRate = total > 0 ? ((completed / total) * 100).toFixed(2) : 0;
184
- const failureRate = total > 0 ? ((failed / total) * 100).toFixed(2) : 0;
185
- // Calculate average duration
186
- const completedOps = operations.filter((op) => op.duration !== undefined);
187
- const avgDuration = completedOps.length > 0
188
- ? (completedOps.reduce((sum, op) => sum + op.duration, 0) / completedOps.length).toFixed(2)
189
- : 0;
190
- return {
191
- content: [{
192
- type: 'text',
193
- text: `✅ Success Rate Report (${timeRange})\n\nTotal Operations: ${total}\nCompleted: ${completed}\nFailed: ${failed}\nIn Progress: ${inProgress}\n\nSuccess Rate: ${successRate}%\nFailure Rate: ${failureRate}%\nAverage Duration: ${avgDuration}ms\n\nUptime: ${((Date.now() - monitoringState.startTime) / 1000 / 60).toFixed(2)} minutes`,
194
- }],
195
- };
196
- }, 'Failed success rate reporter');
197
- }
198
116
  /**
199
117
  * Data Quality Metrics - Report data quality metrics
200
118
  */
@@ -282,94 +200,6 @@ export async function handleDataQualityMetrics(args) {
282
200
  /**
283
201
  * Performance Monitor - Monitor browser and page performance
284
202
  */
285
- export async function handlePerformanceMonitor(args) {
286
- return await withErrorHandling(async () => {
287
- validateWorkflow('performance_monitor', {
288
- requireBrowser: true,
289
- requirePage: true,
290
- });
291
- const page = getCurrentPage();
292
- const performanceData = await page.evaluate(() => {
293
- const perfData = {
294
- navigation: {},
295
- resources: [],
296
- memory: {},
297
- timing: {},
298
- };
299
- // Navigation timing
300
- if (performance.timing) {
301
- const timing = performance.timing;
302
- perfData.navigation = {
303
- domContentLoaded: timing.domContentLoadedEventEnd - timing.navigationStart,
304
- loadComplete: timing.loadEventEnd - timing.navigationStart,
305
- domInteractive: timing.domInteractive - timing.navigationStart,
306
- firstPaint: timing.responseEnd - timing.requestStart,
307
- };
308
- }
309
- // Resource timing
310
- if (performance.getEntriesByType) {
311
- const resources = performance.getEntriesByType('resource');
312
- perfData.resources = resources.slice(0, 20).map((resource) => ({
313
- name: resource.name.substring(0, 100),
314
- type: resource.initiatorType,
315
- duration: Math.round(resource.duration),
316
- size: resource.transferSize || 0,
317
- }));
318
- }
319
- // Memory (if available)
320
- if (performance.memory) {
321
- const memory = performance.memory;
322
- perfData.memory = {
323
- usedJSHeapSize: Math.round(memory.usedJSHeapSize / 1024 / 1024) + ' MB',
324
- totalJSHeapSize: Math.round(memory.totalJSHeapSize / 1024 / 1024) + ' MB',
325
- jsHeapSizeLimit: Math.round(memory.jsHeapSizeLimit / 1024 / 1024) + ' MB',
326
- };
327
- }
328
- // Performance marks and measures
329
- if (performance.getEntriesByType) {
330
- const marks = performance.getEntriesByType('mark');
331
- const measures = performance.getEntriesByType('measure');
332
- perfData.timing.marks = marks.length;
333
- perfData.timing.measures = measures.length;
334
- }
335
- return perfData;
336
- });
337
- // Calculate summary
338
- const resourceCount = performanceData.resources.length;
339
- const totalResourceDuration = performanceData.resources.reduce((sum, r) => sum + r.duration, 0);
340
- const avgResourceDuration = resourceCount > 0 ? (totalResourceDuration / resourceCount).toFixed(2) : 0;
341
- return {
342
- content: [{
343
- type: 'text',
344
- text: `✅ Performance Monitor\n\nPage Load Metrics:\n${JSON.stringify(performanceData.navigation, null, 2)}\n\nResources (showing ${resourceCount}):\nAverage Load Time: ${avgResourceDuration}ms\n\nMemory Usage:\n${JSON.stringify(performanceData.memory, null, 2)}\n\nTop Resources:\n${JSON.stringify(performanceData.resources.slice(0, 10), null, 2)}`,
345
- }],
346
- };
347
- }, 'Failed performance monitor');
348
- }
349
203
  /**
350
204
  * Get Monitoring Summary - Get overall monitoring summary
351
205
  */
352
- export async function handleGetMonitoringSummary(args) {
353
- return await withErrorHandling(async () => {
354
- const summary = {
355
- uptime: ((Date.now() - monitoringState.startTime) / 1000 / 60).toFixed(2) + ' minutes',
356
- operations: {
357
- total: monitoringState.operations.length,
358
- completed: monitoringState.operations.filter((op) => op.status === 'completed').length,
359
- failed: monitoringState.operations.filter((op) => op.status === 'failed').length,
360
- inProgress: monitoringState.operations.filter((op) => op.status === 'in_progress').length,
361
- },
362
- errors: {
363
- total: monitoringState.errors.length,
364
- recent: monitoringState.errors.slice(-5),
365
- },
366
- metrics: monitoringState.metrics,
367
- };
368
- return {
369
- content: [{
370
- type: 'text',
371
- text: `✅ Monitoring Summary\n\n${JSON.stringify(summary, null, 2)}`,
372
- }],
373
- };
374
- }, 'Failed to get monitoring summary');
375
- }
@@ -441,92 +441,3 @@ export async function handleMediaExtractor(args) {
441
441
  };
442
442
  }, 'Failed to extract media');
443
443
  }
444
- /**
445
- * Downloadable files (PDF, DOC, etc.) detect करता है
446
- */
447
- export async function handlePDFLinkFinder(args) {
448
- return await withErrorHandling(async () => {
449
- validateWorkflow('pdf_link_finder', {
450
- requireBrowser: true,
451
- requirePage: true,
452
- });
453
- const page = getCurrentPage();
454
- const selector = args.selector || 'a[href]';
455
- const includeOtherFiles = args.includeOtherFiles !== false;
456
- const fileData = await page.evaluate(({ selector, includeOtherFiles }) => {
457
- const links = document.querySelectorAll(selector);
458
- const results = {
459
- pdfs: [],
460
- documents: [],
461
- archives: [],
462
- others: [],
463
- };
464
- const fileExtensions = {
465
- pdf: ['pdf'],
466
- documents: ['doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'odt', 'ods', 'odp'],
467
- archives: ['zip', 'rar', '7z', 'tar', 'gz', 'bz2'],
468
- others: ['txt', 'csv', 'json', 'xml'],
469
- };
470
- links.forEach((link, index) => {
471
- const href = link.href;
472
- const text = link.textContent?.trim() || '';
473
- // Check file extension
474
- const url = href.toLowerCase();
475
- let fileType = '';
476
- let category = '';
477
- for (const [cat, exts] of Object.entries(fileExtensions)) {
478
- for (const ext of exts) {
479
- if (url.endsWith(`.${ext}`) || url.includes(`.${ext}?`) || url.includes(`.${ext}#`)) {
480
- fileType = ext;
481
- category = cat;
482
- break;
483
- }
484
- }
485
- if (fileType)
486
- break;
487
- }
488
- if (!fileType && !includeOtherFiles) {
489
- return;
490
- }
491
- const fileInfo = {
492
- index,
493
- href,
494
- text,
495
- fileType,
496
- fileName: href.split('/').pop()?.split('?')[0] || '',
497
- };
498
- // Get file size if available
499
- const sizeAttr = link.getAttribute('data-size') || link.getAttribute('title');
500
- if (sizeAttr) {
501
- fileInfo.size = sizeAttr;
502
- }
503
- // Categorize
504
- if (category === 'pdf') {
505
- results.pdfs.push(fileInfo);
506
- }
507
- else if (category === 'documents') {
508
- results.documents.push(fileInfo);
509
- }
510
- else if (category === 'archives') {
511
- results.archives.push(fileInfo);
512
- }
513
- else if (includeOtherFiles) {
514
- results.others.push(fileInfo);
515
- }
516
- });
517
- return results;
518
- }, { selector, includeOtherFiles });
519
- const totalFiles = fileData.pdfs.length +
520
- fileData.documents.length +
521
- fileData.archives.length +
522
- fileData.others.length;
523
- return {
524
- content: [
525
- {
526
- type: 'text',
527
- text: `✅ Found ${totalFiles} downloadable files\n\n${JSON.stringify(fileData, null, 2)}`,
528
- },
529
- ],
530
- };
531
- }, 'Failed to find PDF links');
532
- }
@@ -150,62 +150,6 @@ export async function handleElementScreenshot(args) {
150
150
  };
151
151
  }
152
152
  }
153
- /**
154
- * PDF Generation - Convert page to PDF
155
- */
156
- export async function handlePDFGeneration(args) {
157
- const { url, outputPath, format = 'A4', landscape = false, printBackground = true, margin } = args;
158
- try {
159
- const page = getPageInstance();
160
- if (!page) {
161
- throw new Error('Browser not initialized. Call browser_init first.');
162
- }
163
- if (url && page.url() !== url) {
164
- await page.goto(url, { waitUntil: 'networkidle2', timeout: 30000 });
165
- }
166
- // Ensure output directory exists
167
- if (outputPath) {
168
- const dir = path.dirname(outputPath);
169
- await fs.mkdir(dir, { recursive: true });
170
- }
171
- const pdfOptions = {
172
- path: outputPath,
173
- format,
174
- landscape,
175
- printBackground
176
- };
177
- if (margin) {
178
- pdfOptions.margin = margin;
179
- }
180
- await page.pdf(pdfOptions);
181
- // Get file stats
182
- let fileSize = 0;
183
- if (outputPath) {
184
- const stats = await fs.stat(outputPath);
185
- fileSize = stats.size;
186
- }
187
- const resultText = `✅ PDF generated successfully\n\nPath: ${outputPath}\nFormat: ${format}\nLandscape: ${landscape}\nFile Size: ${(fileSize / 1024).toFixed(2)} KB (${(fileSize / (1024 * 1024)).toFixed(2)} MB)\nTimestamp: ${new Date().toISOString()}`;
188
- return {
189
- content: [
190
- {
191
- type: 'text',
192
- text: resultText,
193
- },
194
- ],
195
- };
196
- }
197
- catch (error) {
198
- return {
199
- content: [
200
- {
201
- type: 'text',
202
- text: `❌ PDF generation failed: ${error.message}`,
203
- },
204
- ],
205
- isError: true,
206
- };
207
- }
208
- }
209
153
  /**
210
154
  * Video Recording - Record browser session (basic implementation)
211
155
  */
package/dist/index.js CHANGED
@@ -27,11 +27,11 @@ import { handleSaveContentAsMarkdown } from "./handlers/file-handlers.js";
27
27
  // Import new data extraction handlers
28
28
  import { handleScrapeTable, handleExtractList, handleExtractJSON, handleScrapeMetaTags, handleExtractSchema, } from "./handlers/data-extraction-handlers.js";
29
29
  // Import multi-element handlers
30
- import { handleBatchElementScraper, handleNestedDataExtraction, handleAttributeHarvester, handleImageScraper, handleLinkHarvester, handleMediaExtractor, handlePDFLinkFinder, } from "./handlers/multi-element-handlers.js";
30
+ import { handleBatchElementScraper, handleNestedDataExtraction, handleAttributeHarvester, handleImageScraper, handleLinkHarvester, handleMediaExtractor, } from "./handlers/multi-element-handlers.js";
31
31
  // Import pagination handlers
32
32
  import { handleAutoPagination, handleInfiniteScroll, handleMultiPageScraper, handleSitemapParser, handleBreadcrumbNavigator, } from "./handlers/pagination-handlers.js";
33
33
  // Import data processing handlers
34
- import { handleSmartTextCleaner, handleHTMLToText, handlePriceParser, handleDateNormalizer, handleContactExtractor, handleSchemaValidator, handleRequiredFieldsChecker, handleDuplicateRemover, } from "./handlers/data-processing-handlers.js";
34
+ import { handleSmartTextCleaner, handleHTMLToText, handleContactExtractor, handleSchemaValidator, handleRequiredFieldsChecker, handleDuplicateRemover, } from "./handlers/data-processing-handlers.js";
35
35
  // Import AI-powered handlers
36
36
  import { handleSmartSelectorGenerator, handleContentClassification, handleSentimentAnalysis, handleSummaryGenerator, handleTranslationSupport, } from "./handlers/ai-powered-handlers.js";
37
37
  // Import search & filter handlers
@@ -41,13 +41,13 @@ import { handleDataDeduplication, handleMissingDataHandler, handleDataTypeValida
41
41
  // Import captcha handlers
42
42
  import { handleOCREngine, handleAudioCaptchaSolver, handlePuzzleCaptchaHandler, } from "./handlers/captcha-handlers.js";
43
43
  // Import visual tools handlers
44
- import { handleFullPageScreenshot, handleElementScreenshot, handlePDFGeneration, handleVideoRecording, handleVisualComparison, } from "./handlers/visual-tools-handlers.js";
44
+ import { handleFullPageScreenshot, handleElementScreenshot, handleVideoRecording, handleVisualComparison, } from "./handlers/visual-tools-handlers.js";
45
45
  // Import smart data extractors
46
46
  import { handleHtmlElementsExtractor, handleTagsFinder, handleLinksFinder, handleXpathLinks, handleAjaxExtractor, handleFetchXHR, handleNetworkRecorder, handleRegexPatternFinder, handleIframeExtractor, handleEmbedPageExtractor, handleImageExtractorAdvanced, handleVideoSourceExtractor, handleVideoPlayerExtractor, handleVideoPlayerHosterFinder, handleOriginalVideoHosterFinder, handleUrlRedirectTracer, handleUserAgentExtractor, } from "./handlers/smart-data-extractors.js";
47
47
  // Import dynamic session handlers
48
48
  import { handleShadowDOMExtractor, handleCookieManager, handleSessionPersistence, handleFormAutoFill, handleAjaxContentWaiter, handleModalPopupHandler, handleLoginSessionManager, } from "./handlers/dynamic-session-handlers.js";
49
49
  // Import monitoring & reporting handlers
50
- import { handleProgressTracker, handleErrorLogger, handleSuccessRateReporter, handleDataQualityMetrics, handlePerformanceMonitor, handleGetMonitoringSummary, } from "./handlers/monitoring-reporting-handlers.js";
50
+ import { handleProgressTracker, handleDataQualityMetrics, } from "./handlers/monitoring-reporting-handlers.js";
51
51
  // Import advanced video & media handlers
52
52
  import { handleVideoLinkFinder, handleVideoDownloadPage, handleVideoDownloadButton, handleVideoPlayPushSource, handleVideoPlayButtonClick, handleUrlRedirectTraceEndpoints, handleNetworkRecordingFinder, handleNetworkRecordingExtractors, handleVideoLinksFinders, handleVideosSelectors, handleLinkProcessExtracts, handleVideoLinkFindersExtracts, handleVideoDownloadButtonFinders, } from "./handlers/advanced-video-media-handlers.js";
53
53
  // Import advanced extraction handlers (Ad-bypass & Obfuscation)
@@ -173,9 +173,6 @@ export async function executeToolByName(name, args) {
173
173
  case TOOL_NAMES.MEDIA_EXTRACTOR:
174
174
  result = await handleMediaExtractor(args || {});
175
175
  break;
176
- case TOOL_NAMES.PDF_LINK_FINDER:
177
- result = await handlePDFLinkFinder(args || {});
178
- break;
179
176
  // Pagination Tools
180
177
  case TOOL_NAMES.AUTO_PAGINATION:
181
178
  result = await handleAutoPagination(args || {});
@@ -199,12 +196,6 @@ export async function executeToolByName(name, args) {
199
196
  case TOOL_NAMES.HTML_TO_TEXT:
200
197
  result = await handleHTMLToText(args);
201
198
  break;
202
- case TOOL_NAMES.PRICE_PARSER:
203
- result = await handlePriceParser(args);
204
- break;
205
- case TOOL_NAMES.DATE_NORMALIZER:
206
- result = await handleDateNormalizer(args);
207
- break;
208
199
  case TOOL_NAMES.CONTACT_EXTRACTOR:
209
200
  result = await handleContactExtractor(args);
210
201
  break;
@@ -283,9 +274,6 @@ export async function executeToolByName(name, args) {
283
274
  case TOOL_NAMES.ELEMENT_SCREENSHOT:
284
275
  result = await handleElementScreenshot(args);
285
276
  break;
286
- case TOOL_NAMES.PDF_GENERATION:
287
- result = await handlePDFGeneration(args);
288
- break;
289
277
  case TOOL_NAMES.VIDEO_RECORDING:
290
278
  result = await handleVideoRecording(args);
291
279
  break;
@@ -370,21 +358,9 @@ export async function executeToolByName(name, args) {
370
358
  case "progress_tracker":
371
359
  result = await handleProgressTracker(args || {});
372
360
  break;
373
- case "error_logger":
374
- result = await handleErrorLogger(args || {});
375
- break;
376
- case "success_rate_reporter":
377
- result = await handleSuccessRateReporter(args || {});
378
- break;
379
361
  case "data_quality_metrics":
380
362
  result = await handleDataQualityMetrics(args || {});
381
363
  break;
382
- case "performance_monitor":
383
- result = await handlePerformanceMonitor(args || {});
384
- break;
385
- case "monitoring_summary":
386
- result = await handleGetMonitoringSummary(args || {});
387
- break;
388
364
  // Advanced Video & Media Download Tools
389
365
  case "video_link_finder":
390
366
  result = await handleVideoLinkFinder(args || {});
@@ -9,7 +9,7 @@ import { handleClick, handleType, handlePressKey, handleSolveCaptcha, handleRand
9
9
  import { handleGetContent, handleFindSelector } from './handlers/content-handlers.js';
10
10
  import { handleSaveContentAsMarkdown } from './handlers/file-handlers.js';
11
11
  import { handleScrapeTable, handleExtractList, handleExtractJSON, handleScrapeMetaTags, handleExtractSchema } from './handlers/data-extraction-handlers.js';
12
- import { handleBatchElementScraper, handleNestedDataExtraction, handleAttributeHarvester, handleImageScraper, handleLinkHarvester, handleMediaExtractor, handlePDFLinkFinder } from './handlers/multi-element-handlers.js';
12
+ import { handleBatchElementScraper, handleNestedDataExtraction, handleAttributeHarvester, handleImageScraper, handleLinkHarvester, handleMediaExtractor, } from './handlers/multi-element-handlers.js';
13
13
  export async function createMcpServer() {
14
14
  const server = new Server(SERVER_INFO, { capabilities: CAPABILITIES });
15
15
  // Register initialize handler
@@ -111,9 +111,6 @@ export async function createMcpServer() {
111
111
  case TOOL_NAMES.MEDIA_EXTRACTOR:
112
112
  result = await handleMediaExtractor(args || {});
113
113
  break;
114
- case TOOL_NAMES.PDF_LINK_FINDER:
115
- result = await handlePDFLinkFinder(args || {});
116
- break;
117
114
  default:
118
115
  throw new Error(`Unknown tool: ${name}`);
119
116
  }
@@ -207,7 +207,7 @@ export async function executeToolWithOptimizations(toolName, toolFn, options = {
207
207
  if (cacheKey && shouldCache) {
208
208
  const cached = globalCache.get(cacheKey);
209
209
  if (cached) {
210
- console.log(`[${toolName}] Cache hit for key: ${cacheKey}`);
210
+ console.error(`[${toolName}] Cache hit for key: ${cacheKey}`);
211
211
  return cached;
212
212
  }
213
213
  }
@@ -226,7 +226,7 @@ export async function executeToolWithOptimizations(toolName, toolFn, options = {
226
226
  catch (error) {
227
227
  // Retry on failure for network tools
228
228
  if (retryAttempts > 0) {
229
- console.log(`[${toolName}] Retrying after error: ${error instanceof Error ? error.message : String(error)}`);
229
+ console.error(`[${toolName}] Retrying after error: ${error instanceof Error ? error.message : String(error)}`);
230
230
  return retryWithBackoff(toolFn, retryAttempts, retryDelay);
231
231
  }
232
232
  throw error;
@@ -253,7 +253,7 @@ export async function cleanupToolResources(page, context) {
253
253
  // Clear cache periodically
254
254
  const cacheStats = globalCache.getStats();
255
255
  if (cacheStats.size > 100) {
256
- console.log('[Cleanup] Clearing cache - size exceeded 100 items');
256
+ console.error('[Cleanup] Clearing cache - size exceeded 100 items');
257
257
  globalCache.clear();
258
258
  }
259
259
  }
@@ -468,17 +468,6 @@ export const TOOLS = [
468
468
  },
469
469
  },
470
470
  },
471
- {
472
- name: 'pdf_link_finder',
473
- description: 'Downloadable files (PDF, DOC, etc.) detect करता है',
474
- inputSchema: {
475
- type: 'object',
476
- properties: {
477
- selector: { type: 'string', default: 'a[href]' },
478
- includeOtherFiles: { type: 'boolean', default: true },
479
- },
480
- },
481
- },
482
471
  // Pagination Tools
483
472
  {
484
473
  name: 'auto_pagination',
@@ -570,31 +559,6 @@ export const TOOLS = [
570
559
  required: ['html'],
571
560
  },
572
561
  },
573
- {
574
- name: 'price_parser',
575
- description: 'Currency symbols से actual numbers extract करता है',
576
- inputSchema: {
577
- type: 'object',
578
- properties: {
579
- text: { type: 'string' },
580
- currency: { type: 'string' },
581
- },
582
- required: ['text'],
583
- },
584
- },
585
- {
586
- name: 'date_normalizer',
587
- description: 'Different date formats को standard format में convert करता है',
588
- inputSchema: {
589
- type: 'object',
590
- properties: {
591
- text: { type: 'string' },
592
- outputFormat: { type: 'string', enum: ['iso', 'locale', 'unix'], default: 'iso' },
593
- timezone: { type: 'string' },
594
- },
595
- required: ['text'],
596
- },
597
- },
598
562
  {
599
563
  name: 'contact_extractor',
600
564
  description: 'Phone numbers और email addresses automatically detect करता है',
@@ -917,22 +881,6 @@ export const TOOLS = [
917
881
  required: ['selector', 'outputPath'],
918
882
  },
919
883
  },
920
- {
921
- name: 'pdf_generation',
922
- description: 'Convert page to PDF',
923
- inputSchema: {
924
- type: 'object',
925
- properties: {
926
- url: { type: 'string' },
927
- outputPath: { type: 'string' },
928
- format: { type: 'string', default: 'A4' },
929
- landscape: { type: 'boolean', default: false },
930
- printBackground: { type: 'boolean', default: true },
931
- margin: { type: 'object' },
932
- },
933
- required: ['outputPath'],
934
- },
935
- },
936
884
  {
937
885
  name: 'video_recording',
938
886
  description: 'Record browser session',
@@ -1235,31 +1183,6 @@ export const TOOLS = [
1235
1183
  },
1236
1184
  },
1237
1185
  },
1238
- {
1239
- name: 'error_logger',
1240
- description: 'Log and track errors',
1241
- inputSchema: {
1242
- type: 'object',
1243
- properties: {
1244
- action: { type: 'string', enum: ['log', 'get', 'clear'], default: 'log' },
1245
- message: { type: 'string' },
1246
- type: { type: 'string' },
1247
- context: { type: 'object' },
1248
- stackTrace: { type: 'string' },
1249
- limit: { type: 'number', default: 10 },
1250
- },
1251
- },
1252
- },
1253
- {
1254
- name: 'success_rate_reporter',
1255
- description: 'Report success metrics',
1256
- inputSchema: {
1257
- type: 'object',
1258
- properties: {
1259
- timeRange: { type: 'string', enum: ['all', 'last_hour', 'last_day'], default: 'all' },
1260
- },
1261
- },
1262
- },
1263
1186
  {
1264
1187
  name: 'data_quality_metrics',
1265
1188
  description: 'Report data quality metrics',
@@ -1270,22 +1193,6 @@ export const TOOLS = [
1270
1193
  },
1271
1194
  },
1272
1195
  },
1273
- {
1274
- name: 'performance_monitor',
1275
- description: 'Monitor browser and page performance',
1276
- inputSchema: {
1277
- type: 'object',
1278
- properties: {},
1279
- },
1280
- },
1281
- {
1282
- name: 'monitoring_summary',
1283
- description: 'Get overall monitoring summary',
1284
- inputSchema: {
1285
- type: 'object',
1286
- properties: {},
1287
- },
1288
- },
1289
1196
  // Advanced Video & Media Download Tools
1290
1197
  {
1291
1198
  name: 'video_link_finder',
@@ -1487,7 +1394,6 @@ export const TOOL_NAMES = {
1487
1394
  IMAGE_SCRAPER: 'image_scraper',
1488
1395
  LINK_HARVESTER: 'link_harvester',
1489
1396
  MEDIA_EXTRACTOR: 'media_extractor',
1490
- PDF_LINK_FINDER: 'pdf_link_finder',
1491
1397
  // Pagination Tools
1492
1398
  AUTO_PAGINATION: 'auto_pagination',
1493
1399
  INFINITE_SCROLL: 'infinite_scroll',
@@ -1497,8 +1403,6 @@ export const TOOL_NAMES = {
1497
1403
  // Data Processing
1498
1404
  SMART_TEXT_CLEANER: 'smart_text_cleaner',
1499
1405
  HTML_TO_TEXT: 'html_to_text',
1500
- PRICE_PARSER: 'price_parser',
1501
- DATE_NORMALIZER: 'date_normalizer',
1502
1406
  CONTACT_EXTRACTOR: 'contact_extractor',
1503
1407
  // Data Validation
1504
1408
  SCHEMA_VALIDATOR: 'schema_validator',
@@ -1529,7 +1433,6 @@ export const TOOL_NAMES = {
1529
1433
  // Screenshot & Visual Tools
1530
1434
  FULL_PAGE_SCREENSHOT: 'full_page_screenshot',
1531
1435
  ELEMENT_SCREENSHOT: 'element_screenshot',
1532
- PDF_GENERATION: 'pdf_generation',
1533
1436
  VIDEO_RECORDING: 'video_recording',
1534
1437
  VISUAL_COMPARISON: 'visual_comparison',
1535
1438
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "brave-real-browser-mcp-server",
3
- "version": "2.14.6",
3
+ "version": "2.14.8",
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",
@@ -39,7 +39,7 @@
39
39
  "ajv": "^8.12.0",
40
40
  "axios": "^1.6.5",
41
41
  "brave-real-browser": "^1.5.105",
42
- "brave-real-launcher": "^1.2.28",
42
+ "brave-real-launcher": "^1.2.29",
43
43
  "brave-real-puppeteer-core": "^24.33.0-patch.1",
44
44
  "cheerio": "^1.0.0-rc.12",
45
45
  "chrono-node": "^2.7.0",