brave-real-browser-mcp-server 2.15.2 → 2.15.4
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/handlers/ai-powered-handlers.js +0 -107
- package/dist/handlers/data-quality-handlers.js +0 -108
- package/dist/handlers/visual-tools-handlers.js +0 -62
- package/dist/index.js +3 -18
- package/dist/tool-definitions.js +0 -113
- package/package.json +1 -1
- package/dist/handlers/APPLY_OPTIMIZATION_PATTERN.js +0 -326
- package/dist/handlers/advanced-scraping-handlers.js +0 -58
- package/dist/handlers/data-transform-handlers.js +0 -66
- package/dist/handlers/dom-handlers.js +0 -206
- package/dist/handlers/network-handlers.js +0 -111
- package/dist/mcp-server.js +0 -265
- package/dist/test-constants.js +0 -111
- package/scripts/update-to-latest.cjs +0 -130
|
@@ -126,110 +126,3 @@ export async function handleContentClassification(args) {
|
|
|
126
126
|
return { content: [{ type: 'text', text: `❌ Error: ${error.message}` }], isError: true };
|
|
127
127
|
}
|
|
128
128
|
}
|
|
129
|
-
/**
|
|
130
|
-
* Sentiment Analysis - Analyze sentiment of page content (Basic Heuristic)
|
|
131
|
-
*/
|
|
132
|
-
export async function handleSentimentAnalysis(args) {
|
|
133
|
-
try {
|
|
134
|
-
let textToAnalyze = args.text || '';
|
|
135
|
-
if (args.url || args.selector) {
|
|
136
|
-
const page = getPageInstance();
|
|
137
|
-
if (!page)
|
|
138
|
-
throw new Error('Browser not initialized');
|
|
139
|
-
if (args.url && page.url() !== args.url) {
|
|
140
|
-
await page.goto(args.url, { waitUntil: 'domcontentloaded' });
|
|
141
|
-
}
|
|
142
|
-
if (args.selector) {
|
|
143
|
-
textToAnalyze = await page.evaluate((sel) => document.querySelector(sel)?.textContent || '', args.selector);
|
|
144
|
-
}
|
|
145
|
-
else if (!textToAnalyze) {
|
|
146
|
-
textToAnalyze = await page.evaluate(() => document.body.innerText);
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
if (!textToAnalyze)
|
|
150
|
-
throw new Error('No text to analyze');
|
|
151
|
-
// Simple Bag of Words
|
|
152
|
-
const positiveWords = ['good', 'great', 'awesome', 'excellent', 'happy', 'love', 'best', 'wonderful', 'amazing'];
|
|
153
|
-
const negativeWords = ['bad', 'terrible', 'awful', 'worst', 'hate', 'sad', 'poor', 'disappointing', 'fail'];
|
|
154
|
-
const lowerText = textToAnalyze.toLowerCase();
|
|
155
|
-
let score = 0;
|
|
156
|
-
let matchCount = 0;
|
|
157
|
-
positiveWords.forEach(w => {
|
|
158
|
-
const regex = new RegExp(`\\b${w}\\b`, 'g');
|
|
159
|
-
const count = (lowerText.match(regex) || []).length;
|
|
160
|
-
score += count;
|
|
161
|
-
matchCount += count;
|
|
162
|
-
});
|
|
163
|
-
negativeWords.forEach(w => {
|
|
164
|
-
const regex = new RegExp(`\\b${w}\\b`, 'g');
|
|
165
|
-
const count = (lowerText.match(regex) || []).length;
|
|
166
|
-
score -= count;
|
|
167
|
-
matchCount += count;
|
|
168
|
-
});
|
|
169
|
-
let sentiment = 'Neutral';
|
|
170
|
-
if (score > 0)
|
|
171
|
-
sentiment = 'Positive';
|
|
172
|
-
if (score < 0)
|
|
173
|
-
sentiment = 'Negative';
|
|
174
|
-
return {
|
|
175
|
-
content: [{
|
|
176
|
-
type: 'text',
|
|
177
|
-
text: JSON.stringify({ sentiment, score, matchCount, analyzedLength: textToAnalyze.length }, null, 2)
|
|
178
|
-
}]
|
|
179
|
-
};
|
|
180
|
-
}
|
|
181
|
-
catch (error) {
|
|
182
|
-
return { content: [{ type: 'text', text: `❌ Error: ${error.message}` }], isError: true };
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
/**
|
|
186
|
-
* Summary Generator - Generate summary of page content (Basic Truncation/Extraction)
|
|
187
|
-
*/
|
|
188
|
-
export async function handleSummaryGenerator(args) {
|
|
189
|
-
try {
|
|
190
|
-
let textToSummary = args.text || '';
|
|
191
|
-
if (args.url || args.selector) {
|
|
192
|
-
const page = getPageInstance();
|
|
193
|
-
if (!page)
|
|
194
|
-
throw new Error('Browser not initialized');
|
|
195
|
-
if (args.url && page.url() !== args.url) {
|
|
196
|
-
await page.goto(args.url, { waitUntil: 'domcontentloaded' });
|
|
197
|
-
}
|
|
198
|
-
if (args.selector) {
|
|
199
|
-
textToSummary = await page.evaluate((sel) => document.querySelector(sel)?.textContent || '', args.selector);
|
|
200
|
-
}
|
|
201
|
-
else if (!textToSummary) {
|
|
202
|
-
// Heuristic: Get paragraphs
|
|
203
|
-
textToSummary = await page.evaluate(() => {
|
|
204
|
-
return Array.from(document.querySelectorAll('p')).map(p => p.textContent).join('\n\n');
|
|
205
|
-
});
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
if (!textToSummary)
|
|
209
|
-
throw new Error('No text to summarize');
|
|
210
|
-
// Basic Summary: First 5 sentences or maxLength
|
|
211
|
-
const sentences = textToSummary.split(/[.!?]+/).filter(s => s.trim().length > 20);
|
|
212
|
-
const summary = sentences.slice(0, 5).join('. ') + '.';
|
|
213
|
-
const finalSummary = args.maxLength ? summary.slice(0, args.maxLength) : summary;
|
|
214
|
-
return {
|
|
215
|
-
content: [{
|
|
216
|
-
type: 'text',
|
|
217
|
-
text: JSON.stringify({ summary: finalSummary, originalLength: textToSummary.length }, null, 2)
|
|
218
|
-
}]
|
|
219
|
-
};
|
|
220
|
-
}
|
|
221
|
-
catch (error) {
|
|
222
|
-
return { content: [{ type: 'text', text: `❌ Error: ${error.message}` }], isError: true };
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
/**
|
|
226
|
-
* Translation Support - Placeholder
|
|
227
|
-
*/
|
|
228
|
-
export async function handleTranslationSupport(args) {
|
|
229
|
-
return {
|
|
230
|
-
content: [{
|
|
231
|
-
type: 'text',
|
|
232
|
-
text: `⚠️ Translation Support requires an external API (e.g., Google Translate, DeepL). This feature is defined but currently running in 'offline' mode. To implement, valid API keys would be required.\n\nInput extracted: ${args.text ? 'Yes' : 'No'}\nTarget Language: ${args.targetLanguage}`
|
|
233
|
-
}]
|
|
234
|
-
};
|
|
235
|
-
}
|
|
@@ -144,114 +144,6 @@ export async function handleDataTypeValidator(args) {
|
|
|
144
144
|
};
|
|
145
145
|
}
|
|
146
146
|
}
|
|
147
|
-
/**
|
|
148
|
-
* Outlier Detection - Detect outliers in numerical data
|
|
149
|
-
*/
|
|
150
|
-
export async function handleOutlierDetection(args) {
|
|
151
|
-
const { data, field, method = 'iqr', threshold = 1.5 } = args;
|
|
152
|
-
try {
|
|
153
|
-
if (!Array.isArray(data)) {
|
|
154
|
-
throw new Error('Data must be an array');
|
|
155
|
-
}
|
|
156
|
-
// Extract numerical values
|
|
157
|
-
const values = data
|
|
158
|
-
.map(item => {
|
|
159
|
-
const value = field ? item[field] : item;
|
|
160
|
-
return typeof value === 'number' ? value : parseFloat(value);
|
|
161
|
-
})
|
|
162
|
-
.filter(v => !isNaN(v));
|
|
163
|
-
if (values.length === 0) {
|
|
164
|
-
throw new Error('No valid numerical values found');
|
|
165
|
-
}
|
|
166
|
-
let outliers = [];
|
|
167
|
-
let stats = {};
|
|
168
|
-
// Sort values
|
|
169
|
-
const sorted = [...values].sort((a, b) => a - b);
|
|
170
|
-
// Calculate statistics
|
|
171
|
-
const mean = values.reduce((a, b) => a + b, 0) / values.length;
|
|
172
|
-
const variance = values.reduce((a, b) => a + Math.pow(b - mean, 2), 0) / values.length;
|
|
173
|
-
const stdDev = Math.sqrt(variance);
|
|
174
|
-
const q1Index = Math.floor(sorted.length * 0.25);
|
|
175
|
-
const q3Index = Math.floor(sorted.length * 0.75);
|
|
176
|
-
const q1 = sorted[q1Index];
|
|
177
|
-
const q3 = sorted[q3Index];
|
|
178
|
-
const iqr = q3 - q1;
|
|
179
|
-
stats = {
|
|
180
|
-
count: values.length,
|
|
181
|
-
min: sorted[0],
|
|
182
|
-
max: sorted[sorted.length - 1],
|
|
183
|
-
mean: mean.toFixed(2),
|
|
184
|
-
median: sorted[Math.floor(sorted.length / 2)],
|
|
185
|
-
stdDev: stdDev.toFixed(2),
|
|
186
|
-
q1,
|
|
187
|
-
q3,
|
|
188
|
-
iqr: iqr.toFixed(2)
|
|
189
|
-
};
|
|
190
|
-
// Detect outliers based on method
|
|
191
|
-
if (method === 'iqr') {
|
|
192
|
-
const lowerBound = q1 - threshold * iqr;
|
|
193
|
-
const upperBound = q3 + threshold * iqr;
|
|
194
|
-
data.forEach((item, index) => {
|
|
195
|
-
const value = field ? item[field] : item;
|
|
196
|
-
const numValue = typeof value === 'number' ? value : parseFloat(value);
|
|
197
|
-
if (!isNaN(numValue) && (numValue < lowerBound || numValue > upperBound)) {
|
|
198
|
-
outliers.push({
|
|
199
|
-
item,
|
|
200
|
-
index,
|
|
201
|
-
value: numValue,
|
|
202
|
-
reason: numValue < lowerBound ? 'below lower bound' : 'above upper bound',
|
|
203
|
-
bounds: { lower: lowerBound.toFixed(2), upper: upperBound.toFixed(2) }
|
|
204
|
-
});
|
|
205
|
-
}
|
|
206
|
-
});
|
|
207
|
-
}
|
|
208
|
-
else if (method === 'zscore') {
|
|
209
|
-
data.forEach((item, index) => {
|
|
210
|
-
const value = field ? item[field] : item;
|
|
211
|
-
const numValue = typeof value === 'number' ? value : parseFloat(value);
|
|
212
|
-
if (!isNaN(numValue)) {
|
|
213
|
-
const zscore = (numValue - mean) / stdDev;
|
|
214
|
-
if (Math.abs(zscore) > threshold) {
|
|
215
|
-
outliers.push({
|
|
216
|
-
item,
|
|
217
|
-
index,
|
|
218
|
-
value: numValue,
|
|
219
|
-
zscore: zscore.toFixed(2),
|
|
220
|
-
reason: `zscore ${zscore > 0 ? 'above' : 'below'} threshold`
|
|
221
|
-
});
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
});
|
|
225
|
-
}
|
|
226
|
-
const outlierPercentage = ((outliers.length / data.length) * 100).toFixed(2);
|
|
227
|
-
let summary = `Outlier Detection Results:\n\nMethod: ${method}\nThreshold: ${threshold}${field ? `\nField Analyzed: ${field}` : ''}\n\nStatistics:\n- Count: ${stats.count}\n- Min: ${stats.min}\n- Max: ${stats.max}\n- Mean: ${stats.mean}\n- Median: ${stats.median}\n- Std Dev: ${stats.stdDev}\n- Q1: ${stats.q1}\n- Q3: ${stats.q3}\n- IQR: ${stats.iqr}`;
|
|
228
|
-
summary += `\n\nOutliers:\n- Count: ${outliers.length}\n- Percentage: ${outlierPercentage}%`;
|
|
229
|
-
if (outliers.length > 0) {
|
|
230
|
-
summary += `\n\nOutlier Samples (Top 10):\n${outliers.slice(0, 10).map((o, i) => {
|
|
231
|
-
return `${i + 1}. Index ${o.index}: Value=${o.value}, Reason: ${o.reason}${o.zscore ? `, Z-score=${o.zscore}` : ''}${o.bounds ? `, Bounds=[${o.bounds.lower}, ${o.bounds.upper}]` : ''}`;
|
|
232
|
-
}).join('\n')}`;
|
|
233
|
-
}
|
|
234
|
-
return {
|
|
235
|
-
content: [
|
|
236
|
-
{
|
|
237
|
-
type: "text",
|
|
238
|
-
text: summary
|
|
239
|
-
}
|
|
240
|
-
]
|
|
241
|
-
};
|
|
242
|
-
}
|
|
243
|
-
catch (error) {
|
|
244
|
-
return {
|
|
245
|
-
content: [
|
|
246
|
-
{
|
|
247
|
-
type: "text",
|
|
248
|
-
text: `Outlier Detection Error: ${error.message}`
|
|
249
|
-
}
|
|
250
|
-
],
|
|
251
|
-
isError: true
|
|
252
|
-
};
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
147
|
/**
|
|
256
148
|
* Consistency Checker - Check data consistency across fields
|
|
257
149
|
*/
|
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
import { getPageInstance } from '../browser-manager.js';
|
|
3
3
|
import * as fs from 'fs/promises';
|
|
4
4
|
import * as path from 'path';
|
|
5
|
-
import pixelmatch from 'pixelmatch';
|
|
6
|
-
import { PNG } from 'pngjs';
|
|
7
5
|
import { sleep } from '../system-utils.js';
|
|
8
6
|
/**
|
|
9
7
|
* Full Page Screenshot - Capture entire page
|
|
@@ -205,63 +203,3 @@ export async function handleVideoRecording(args) {
|
|
|
205
203
|
};
|
|
206
204
|
}
|
|
207
205
|
}
|
|
208
|
-
/**
|
|
209
|
-
* Visual Comparison - Compare two screenshots
|
|
210
|
-
*/
|
|
211
|
-
export async function handleVisualComparison(args) {
|
|
212
|
-
const { image1Path, image2Path, diffOutputPath, threshold = 0.1 } = args;
|
|
213
|
-
try {
|
|
214
|
-
if (!image1Path || !image2Path) {
|
|
215
|
-
throw new Error('Both image paths are required');
|
|
216
|
-
}
|
|
217
|
-
// Read images
|
|
218
|
-
const img1Data = await fs.readFile(image1Path);
|
|
219
|
-
const img2Data = await fs.readFile(image2Path);
|
|
220
|
-
const img1 = PNG.sync.read(img1Data);
|
|
221
|
-
const img2 = PNG.sync.read(img2Data);
|
|
222
|
-
// Check if dimensions match
|
|
223
|
-
if (img1.width !== img2.width || img1.height !== img2.height) {
|
|
224
|
-
return {
|
|
225
|
-
content: [
|
|
226
|
-
{
|
|
227
|
-
type: "text",
|
|
228
|
-
text: `Image dimensions do not match:\n- Image 1: ${img1.width}x${img1.height}\n- Image 2: ${img2.width}x${img2.height}`
|
|
229
|
-
}
|
|
230
|
-
],
|
|
231
|
-
isError: true
|
|
232
|
-
};
|
|
233
|
-
}
|
|
234
|
-
// Create diff image
|
|
235
|
-
const diff = new PNG({ width: img1.width, height: img1.height });
|
|
236
|
-
// Compare images
|
|
237
|
-
const numDiffPixels = pixelmatch(img1.data, img2.data, diff.data, img1.width, img1.height, { threshold });
|
|
238
|
-
// Save diff image if path provided
|
|
239
|
-
if (diffOutputPath) {
|
|
240
|
-
const dir = path.dirname(diffOutputPath);
|
|
241
|
-
await fs.mkdir(dir, { recursive: true });
|
|
242
|
-
await fs.writeFile(diffOutputPath, PNG.sync.write(diff));
|
|
243
|
-
}
|
|
244
|
-
const totalPixels = img1.width * img1.height;
|
|
245
|
-
const diffPercentage = (numDiffPixels / totalPixels) * 100;
|
|
246
|
-
const similarity = ((1 - (numDiffPixels / totalPixels)) * 100).toFixed(2);
|
|
247
|
-
return {
|
|
248
|
-
content: [
|
|
249
|
-
{
|
|
250
|
-
type: "text",
|
|
251
|
-
text: `Visual Comparison Results:\n- Identical: ${numDiffPixels === 0 ? 'Yes' : 'No'}\n- Similarity: ${similarity}%\n- Different Pixels: ${numDiffPixels} (${diffPercentage.toFixed(2)}%)\n- Total Pixels: ${totalPixels}\n- Image Dimensions: ${img1.width}x${img1.height}\n- Threshold: ${threshold}${diffOutputPath ? `\n- Diff Image Saved: ${diffOutputPath}` : ''}`
|
|
252
|
-
}
|
|
253
|
-
]
|
|
254
|
-
};
|
|
255
|
-
}
|
|
256
|
-
catch (error) {
|
|
257
|
-
return {
|
|
258
|
-
content: [
|
|
259
|
-
{
|
|
260
|
-
type: "text",
|
|
261
|
-
text: `Visual Comparison Error: ${error.message}`
|
|
262
|
-
}
|
|
263
|
-
],
|
|
264
|
-
isError: true
|
|
265
|
-
};
|
|
266
|
-
}
|
|
267
|
-
}
|
package/dist/index.js
CHANGED
|
@@ -38,13 +38,13 @@ import { handleSmartSelectorGenerator, handleContentClassification, } from "./ha
|
|
|
38
38
|
// Import search & filter handlers
|
|
39
39
|
import { handleKeywordSearch, handleRegexPatternMatcher, handleXPathSupport, handleAdvancedCSSSelectors, handleVisualElementFinder, } from "./handlers/search-filter-handlers.js";
|
|
40
40
|
// Import data quality handlers
|
|
41
|
-
import { handleDataDeduplication, handleDataTypeValidator,
|
|
41
|
+
import { handleDataDeduplication, handleDataTypeValidator, } from "./handlers/data-quality-handlers.js";
|
|
42
42
|
// Import captcha handlers
|
|
43
43
|
import { handleOCREngine, handleAudioCaptchaSolver, handlePuzzleCaptchaHandler, } from "./handlers/captcha-handlers.js";
|
|
44
44
|
// Import visual tools handlers
|
|
45
|
-
import { handleFullPageScreenshot, handleElementScreenshot, handleVideoRecording,
|
|
45
|
+
import { handleFullPageScreenshot, handleElementScreenshot, handleVideoRecording, } from "./handlers/visual-tools-handlers.js";
|
|
46
46
|
// Import smart data extractors
|
|
47
|
-
import { handleHtmlElementsExtractor, handleTagsFinder, handleLinksFinder, handleXpathLinks, handleAjaxExtractor, handleFetchXHR, handleNetworkRecorder, handleRegexPatternFinder, handleIframeExtractor, handleEmbedPageExtractor, handleImageExtractorAdvanced, handleVideoSourceExtractor,
|
|
47
|
+
import { handleHtmlElementsExtractor, handleTagsFinder, handleLinksFinder, handleXpathLinks, handleAjaxExtractor, handleFetchXHR, handleNetworkRecorder, handleRegexPatternFinder, handleIframeExtractor, handleEmbedPageExtractor, handleImageExtractorAdvanced, handleVideoSourceExtractor, handleUrlRedirectTracer, handleUserAgentExtractor, } from "./handlers/smart-data-extractors.js";
|
|
48
48
|
// Import dynamic session handlers
|
|
49
49
|
import { handleShadowDOMExtractor, handleCookieManager, handleFormAutoFill, handleAjaxContentWaiter, } from "./handlers/dynamic-session-handlers.js";
|
|
50
50
|
// Import monitoring & reporting handlers
|
|
@@ -213,9 +213,6 @@ export async function executeToolByName(name, args) {
|
|
|
213
213
|
case TOOL_NAMES.DATA_TYPE_VALIDATOR:
|
|
214
214
|
result = await handleDataTypeValidator(args);
|
|
215
215
|
break;
|
|
216
|
-
case TOOL_NAMES.OUTLIER_DETECTION:
|
|
217
|
-
result = await handleOutlierDetection(args);
|
|
218
|
-
break;
|
|
219
216
|
// Advanced Captcha Handling
|
|
220
217
|
case TOOL_NAMES.OCR_ENGINE:
|
|
221
218
|
result = await handleOCREngine(args);
|
|
@@ -236,9 +233,6 @@ export async function executeToolByName(name, args) {
|
|
|
236
233
|
case TOOL_NAMES.VIDEO_RECORDING:
|
|
237
234
|
result = await handleVideoRecording(args);
|
|
238
235
|
break;
|
|
239
|
-
case TOOL_NAMES.VISUAL_COMPARISON:
|
|
240
|
-
result = await handleVisualComparison(args);
|
|
241
|
-
break;
|
|
242
236
|
// Smart Data Extractors (Advanced)
|
|
243
237
|
case "html_elements_extractor":
|
|
244
238
|
result = await handleHtmlElementsExtractor(args || {});
|
|
@@ -276,15 +270,6 @@ export async function executeToolByName(name, args) {
|
|
|
276
270
|
case "video_source_extractor":
|
|
277
271
|
result = await handleVideoSourceExtractor(args || {});
|
|
278
272
|
break;
|
|
279
|
-
case "video_player_extractor":
|
|
280
|
-
result = await handleVideoPlayerExtractor(args || {});
|
|
281
|
-
break;
|
|
282
|
-
case "video_player_hoster_finder":
|
|
283
|
-
result = await handleVideoPlayerHosterFinder(args || {});
|
|
284
|
-
break;
|
|
285
|
-
case "original_video_hoster_finder":
|
|
286
|
-
result = await handleOriginalVideoHosterFinder(args || {});
|
|
287
|
-
break;
|
|
288
273
|
case "url_redirect_tracer":
|
|
289
274
|
result = await handleUrlRedirectTracer(args);
|
|
290
275
|
break;
|
package/dist/tool-definitions.js
CHANGED
|
@@ -619,20 +619,6 @@ export const TOOLS = [
|
|
|
619
619
|
required: ['data', 'schema'],
|
|
620
620
|
},
|
|
621
621
|
},
|
|
622
|
-
{
|
|
623
|
-
name: 'outlier_detection',
|
|
624
|
-
description: 'Detect outliers in numerical data',
|
|
625
|
-
inputSchema: {
|
|
626
|
-
type: 'object',
|
|
627
|
-
properties: {
|
|
628
|
-
data: { type: 'array' },
|
|
629
|
-
field: { type: 'string', description: 'Field to analyze' },
|
|
630
|
-
method: { type: 'string', enum: ['iqr', 'zscore'], default: 'iqr' },
|
|
631
|
-
threshold: { type: 'number', default: 1.5 },
|
|
632
|
-
},
|
|
633
|
-
required: ['data'],
|
|
634
|
-
},
|
|
635
|
-
},
|
|
636
622
|
{
|
|
637
623
|
name: 'consistency_checker',
|
|
638
624
|
description: 'Check data consistency across fields',
|
|
@@ -730,20 +716,6 @@ export const TOOLS = [
|
|
|
730
716
|
required: ['outputPath'],
|
|
731
717
|
},
|
|
732
718
|
},
|
|
733
|
-
{
|
|
734
|
-
name: 'visual_comparison',
|
|
735
|
-
description: 'Compare two screenshots',
|
|
736
|
-
inputSchema: {
|
|
737
|
-
type: 'object',
|
|
738
|
-
properties: {
|
|
739
|
-
image1Path: { type: 'string' },
|
|
740
|
-
image2Path: { type: 'string' },
|
|
741
|
-
diffOutputPath: { type: 'string' },
|
|
742
|
-
threshold: { type: 'number', default: 0.1 },
|
|
743
|
-
},
|
|
744
|
-
required: ['image1Path', 'image2Path'],
|
|
745
|
-
},
|
|
746
|
-
},
|
|
747
719
|
// Smart Data Extractors (Advanced)
|
|
748
720
|
{
|
|
749
721
|
name: 'html_elements_extractor',
|
|
@@ -868,38 +840,6 @@ export const TOOLS = [
|
|
|
868
840
|
},
|
|
869
841
|
},
|
|
870
842
|
},
|
|
871
|
-
{
|
|
872
|
-
name: 'video_source_extractor',
|
|
873
|
-
description: 'Extract video sources from video elements',
|
|
874
|
-
inputSchema: {
|
|
875
|
-
type: 'object',
|
|
876
|
-
properties: {},
|
|
877
|
-
},
|
|
878
|
-
},
|
|
879
|
-
{
|
|
880
|
-
name: 'video_player_extractor',
|
|
881
|
-
description: 'Extract video player information',
|
|
882
|
-
inputSchema: {
|
|
883
|
-
type: 'object',
|
|
884
|
-
properties: {},
|
|
885
|
-
},
|
|
886
|
-
},
|
|
887
|
-
{
|
|
888
|
-
name: 'video_player_hoster_finder',
|
|
889
|
-
description: 'Detect video hosting platform (YouTube, Vimeo, etc.)',
|
|
890
|
-
inputSchema: {
|
|
891
|
-
type: 'object',
|
|
892
|
-
properties: {},
|
|
893
|
-
},
|
|
894
|
-
},
|
|
895
|
-
{
|
|
896
|
-
name: 'original_video_hoster_finder',
|
|
897
|
-
description: 'Find original video source',
|
|
898
|
-
inputSchema: {
|
|
899
|
-
type: 'object',
|
|
900
|
-
properties: {},
|
|
901
|
-
},
|
|
902
|
-
},
|
|
903
843
|
{
|
|
904
844
|
name: 'url_redirect_tracer',
|
|
905
845
|
description: 'Trace URL redirects',
|
|
@@ -1087,43 +1027,6 @@ export const TOOLS = [
|
|
|
1087
1027
|
},
|
|
1088
1028
|
},
|
|
1089
1029
|
},
|
|
1090
|
-
{
|
|
1091
|
-
name: 'sentiment_analysis',
|
|
1092
|
-
description: 'Analyze the sentiment of text or page content',
|
|
1093
|
-
inputSchema: {
|
|
1094
|
-
type: 'object',
|
|
1095
|
-
properties: {
|
|
1096
|
-
text: { type: 'string', description: 'Text to analyze' },
|
|
1097
|
-
url: { type: 'string', description: 'URL to analyze' },
|
|
1098
|
-
selector: { type: 'string', description: 'Selector to extract text from' }
|
|
1099
|
-
}
|
|
1100
|
-
}
|
|
1101
|
-
},
|
|
1102
|
-
{
|
|
1103
|
-
name: 'summary_generator',
|
|
1104
|
-
description: 'Generate a summary of text or page content',
|
|
1105
|
-
inputSchema: {
|
|
1106
|
-
type: 'object',
|
|
1107
|
-
properties: {
|
|
1108
|
-
text: { type: 'string', description: 'Text to summarize' },
|
|
1109
|
-
url: { type: 'string', description: 'URL to summarize' },
|
|
1110
|
-
selector: { type: 'string', description: 'Selector to extract text from' },
|
|
1111
|
-
maxLength: { type: 'number', description: 'Maximum length of summary' }
|
|
1112
|
-
}
|
|
1113
|
-
}
|
|
1114
|
-
},
|
|
1115
|
-
{
|
|
1116
|
-
name: 'translation_support',
|
|
1117
|
-
description: 'Detect language and translate text',
|
|
1118
|
-
inputSchema: {
|
|
1119
|
-
type: 'object',
|
|
1120
|
-
properties: {
|
|
1121
|
-
text: { type: 'string', description: 'Text to translate' },
|
|
1122
|
-
url: { type: 'string', description: 'URL to translate content from' },
|
|
1123
|
-
targetLanguage: { type: 'string', description: 'Target language code (e.g. "es", "fr")' }
|
|
1124
|
-
}
|
|
1125
|
-
}
|
|
1126
|
-
},
|
|
1127
1030
|
// Phase 3: Media & Video Tools
|
|
1128
1031
|
{
|
|
1129
1032
|
name: 'video_source_extractor',
|
|
@@ -1155,16 +1058,6 @@ export const TOOLS = [
|
|
|
1155
1058
|
}
|
|
1156
1059
|
}
|
|
1157
1060
|
},
|
|
1158
|
-
{
|
|
1159
|
-
name: 'redirect_tracer',
|
|
1160
|
-
description: 'Trace URL redirects to find final destination',
|
|
1161
|
-
inputSchema: {
|
|
1162
|
-
type: 'object',
|
|
1163
|
-
properties: {
|
|
1164
|
-
url: { type: 'string' }
|
|
1165
|
-
}
|
|
1166
|
-
}
|
|
1167
|
-
},
|
|
1168
1061
|
{
|
|
1169
1062
|
name: 'video_download_link_finder',
|
|
1170
1063
|
description: 'Find direct download links for video files',
|
|
@@ -1224,14 +1117,10 @@ export const TOOL_NAMES = {
|
|
|
1224
1117
|
// AI-Powered Features
|
|
1225
1118
|
SMART_SELECTOR_GENERATOR: 'smart_selector_generator',
|
|
1226
1119
|
CONTENT_CLASSIFICATION: 'content_classification',
|
|
1227
|
-
SENTIMENT_ANALYSIS: 'sentiment_analysis',
|
|
1228
|
-
SUMMARY_GENERATOR: 'summary_generator',
|
|
1229
|
-
TRANSLATION_SUPPORT: 'translation_support',
|
|
1230
1120
|
// Phase 3: Media & Video
|
|
1231
1121
|
VIDEO_SOURCE_EXTRACTOR: 'video_source_extractor',
|
|
1232
1122
|
VIDEO_PLAYER_FINDER: 'video_player_finder',
|
|
1233
1123
|
STREAM_DETECTOR: 'stream_detector',
|
|
1234
|
-
REDIRECT_TRACER: 'redirect_tracer',
|
|
1235
1124
|
// Search & Filter Tools
|
|
1236
1125
|
KEYWORD_SEARCH: 'keyword_search',
|
|
1237
1126
|
REGEX_PATTERN_MATCHER: 'regex_pattern_matcher',
|
|
@@ -1241,7 +1130,6 @@ export const TOOL_NAMES = {
|
|
|
1241
1130
|
// Data Quality & Validation
|
|
1242
1131
|
DATA_DEDUPLICATION: 'data_deduplication',
|
|
1243
1132
|
DATA_TYPE_VALIDATOR: 'data_type_validator',
|
|
1244
|
-
OUTLIER_DETECTION: 'outlier_detection',
|
|
1245
1133
|
// Advanced Captcha Handling
|
|
1246
1134
|
OCR_ENGINE: 'ocr_engine',
|
|
1247
1135
|
AUDIO_CAPTCHA_SOLVER: 'audio_captcha_solver',
|
|
@@ -1250,7 +1138,6 @@ export const TOOL_NAMES = {
|
|
|
1250
1138
|
FULL_PAGE_SCREENSHOT: 'full_page_screenshot',
|
|
1251
1139
|
ELEMENT_SCREENSHOT: 'element_screenshot',
|
|
1252
1140
|
VIDEO_RECORDING: 'video_recording',
|
|
1253
|
-
VISUAL_COMPARISON: 'visual_comparison',
|
|
1254
1141
|
};
|
|
1255
1142
|
// Tool categories for organization
|
|
1256
1143
|
export const TOOL_CATEGORIES = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "brave-real-browser-mcp-server",
|
|
3
|
-
"version": "2.15.
|
|
3
|
+
"version": "2.15.4",
|
|
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",
|