brave-real-browser-mcp-server 2.15.3 → 2.15.5
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 +21 -40
- package/dist/handlers/ai-powered-handlers.js +0 -107
- package/dist/handlers/data-extraction-handlers.js +0 -76
- package/dist/handlers/data-processing-handlers.js +1 -43
- package/dist/handlers/data-quality-handlers.js +0 -249
- package/dist/handlers/dynamic-session-handlers.js +0 -75
- package/dist/handlers/monitoring-reporting-handlers.js +0 -83
- package/dist/handlers/visual-tools-handlers.js +0 -114
- package/dist/index.js +6 -30
- package/dist/tool-definitions.js +0 -162
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,15 +4,15 @@
|
|
|
4
4
|
|
|
5
5
|
<div align="center">
|
|
6
6
|
|
|
7
|
-

|
|
8
8
|

|
|
9
|
-

|
|
10
10
|

|
|
11
11
|

|
|
12
12
|
|
|
13
|
-
**सभी AI IDEs के लिए Universal MCP Server |
|
|
13
|
+
**सभी AI IDEs के लिए Universal MCP Server | 66+ Tools | Browser Automation | Web Scraping | CAPTCHA Solving**
|
|
14
14
|
|
|
15
|
-
[Installation](#-installation) | [Quick Start](#-quick-start) | [Qoder AI Setup](#-qoder-ai---complete-integration-guide) | [Tools](#-available-tools-
|
|
15
|
+
[Installation](#-installation) | [Quick Start](#-quick-start) | [Qoder AI Setup](#-qoder-ai---complete-integration-guide) | [Tools](#-available-tools-66) | [IDE Configurations](#-ide-configurations)
|
|
16
16
|
|
|
17
17
|
</div>
|
|
18
18
|
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
**Brave Real Browser MCP Server** एक powerful automation tool है जो:
|
|
24
24
|
|
|
25
25
|
- ✅ **20+ AI IDEs में काम करता है** (Antigravity, Warp AI, Zed, Cursor, Claude, Windsurf, Cline, Qoder AI, etc.)
|
|
26
|
-
- ✅ **
|
|
26
|
+
- ✅ **66+ Automation Tools** - Browser control, scraping, CAPTCHA solving, video extraction
|
|
27
27
|
- ✅ **MCP Protocol (STDIO)** - Fast and secure local communication
|
|
28
28
|
- ✅ **Auto-Detection** - Automatically detects your IDE
|
|
29
29
|
- ✅ **Real Brave Browser** - Anti-detection features, bypass Cloudflare
|
|
@@ -146,10 +146,11 @@ npm install -g brave-real-browser-mcp-server@latest
|
|
|
146
146
|
|
|
147
147
|
```json
|
|
148
148
|
{
|
|
149
|
-
"
|
|
149
|
+
"context_servers": {
|
|
150
150
|
"brave-real-browser": {
|
|
151
|
-
"command": "npx",
|
|
152
|
-
"args": ["-y", "brave-real-browser-mcp-server@latest"]
|
|
151
|
+
"command": "npx.cmd",
|
|
152
|
+
"args": ["-y", "brave-real-browser-mcp-server@latest"],
|
|
153
|
+
"env": {}
|
|
153
154
|
}
|
|
154
155
|
}
|
|
155
156
|
}
|
|
@@ -189,7 +190,7 @@ npm install -g brave-real-browser-mcp-server@latest
|
|
|
189
190
|
|
|
190
191
|
---
|
|
191
192
|
|
|
192
|
-
## 🛠️ Available Tools (
|
|
193
|
+
## 🛠️ Available Tools (66)
|
|
193
194
|
|
|
194
195
|
### 🌐 Browser Management (2 tools)
|
|
195
196
|
|
|
@@ -214,14 +215,13 @@ npm install -g brave-real-browser-mcp-server@latest
|
|
|
214
215
|
| `random_scroll` | Human-like scrolling |
|
|
215
216
|
| `solve_captcha` | Solve CAPTCHA (reCAPTCHA, hCaptcha, Turnstile, etc.) |
|
|
216
217
|
|
|
217
|
-
### 📄 Content Extraction (
|
|
218
|
+
### 📄 Content Extraction (9 tools)
|
|
218
219
|
|
|
219
220
|
| Tool | Description |
|
|
220
221
|
| -------------------------- | ----------------------------------------- |
|
|
221
222
|
| `get_content` | Extract page content (HTML/Text/Markdown) |
|
|
222
223
|
| `find_selector` | Find CSS selectors for elements |
|
|
223
224
|
| `scrape_table` | Extract table data with headers |
|
|
224
|
-
| `extract_list` | Extract list items |
|
|
225
225
|
| `extract_json` | Extract JSON data from page |
|
|
226
226
|
| `scrape_meta_tags` | Extract meta tags and SEO info |
|
|
227
227
|
| `extract_schema` | Extract schema.org structured data |
|
|
@@ -284,7 +284,7 @@ npm install -g brave-real-browser-mcp-server@latest
|
|
|
284
284
|
| `audio_captcha_solver` | Solve audio CAPTCHAs |
|
|
285
285
|
| `puzzle_captcha_handler` | Handle puzzle CAPTCHAs |
|
|
286
286
|
|
|
287
|
-
### 🔧 Data Processing (
|
|
287
|
+
### 🔧 Data Processing (5 tools)
|
|
288
288
|
|
|
289
289
|
| Tool | Description |
|
|
290
290
|
| ------------------------- | ---------------------------------- |
|
|
@@ -293,28 +293,17 @@ npm install -g brave-real-browser-mcp-server@latest
|
|
|
293
293
|
| `contact_extractor` | Extract contact information |
|
|
294
294
|
| `schema_validator` | Validate data against schema |
|
|
295
295
|
| `required_fields_checker` | Check for required fields |
|
|
296
|
-
| `duplicate_remover` | Remove duplicate entries |
|
|
297
|
-
| `data_deduplication` | Advanced deduplication |
|
|
298
|
-
| `missing_data_handler` | Handle missing data |
|
|
299
|
-
| `data_type_validator` | Validate data types |
|
|
300
296
|
|
|
301
|
-
### 📊 Data Quality (
|
|
297
|
+
### 📊 Data Quality (0 tools)
|
|
302
298
|
|
|
303
|
-
|
|
304
|
-
| ---------------------- | ------------------------ |
|
|
305
|
-
| `outlier_detection` | Detect data outliers |
|
|
306
|
-
| `consistency_checker` | Check data consistency |
|
|
307
|
-
| `data_quality_metrics` | Generate quality metrics |
|
|
299
|
+
*Advanced data quality tools removed for optimization.*
|
|
308
300
|
|
|
309
|
-
### 🤖 AI-Powered Tools (
|
|
301
|
+
### 🤖 AI-Powered Tools (2 tools)
|
|
310
302
|
|
|
311
303
|
| Tool | Description |
|
|
312
304
|
| -------------------------- | --------------------------- |
|
|
313
305
|
| `smart_selector_generator` | Auto-generate CSS selectors |
|
|
314
306
|
| `content_classification` | Classify content type |
|
|
315
|
-
| `sentiment_analysis` | Analyze text sentiment |
|
|
316
|
-
| `summary_generator` | Generate content summaries |
|
|
317
|
-
| `translation_support` | Translate content |
|
|
318
307
|
|
|
319
308
|
### 🔎 Search & Filter (5 tools)
|
|
320
309
|
|
|
@@ -336,11 +325,10 @@ npm install -g brave-real-browser-mcp-server@latest
|
|
|
336
325
|
| `sitemap_parser` | Parse and navigate sitemaps |
|
|
337
326
|
| `breadcrumb_navigator` | Navigate using breadcrumbs |
|
|
338
327
|
|
|
339
|
-
### 🔒 Session Management (
|
|
328
|
+
### 🔒 Session Management (6 tools)
|
|
340
329
|
|
|
341
330
|
| Tool | Description |
|
|
342
331
|
| ----------------------- | -------------------------- |
|
|
343
|
-
| `cookie_manager` | Manage cookies |
|
|
344
332
|
| `session_persistence` | Persist sessions |
|
|
345
333
|
| `form_auto_fill` | Auto-fill forms |
|
|
346
334
|
| `ajax_content_waiter` | Wait for AJAX content |
|
|
@@ -348,25 +336,21 @@ npm install -g brave-real-browser-mcp-server@latest
|
|
|
348
336
|
| `login_session_manager` | Manage login sessions |
|
|
349
337
|
| `shadow_dom_extractor` | Extract Shadow DOM content |
|
|
350
338
|
|
|
351
|
-
### 📸 Visual Tools (
|
|
339
|
+
### 📸 Visual Tools (4 tools)
|
|
352
340
|
|
|
353
341
|
| Tool | Description |
|
|
354
342
|
| ---------------------- | --------------------------- |
|
|
355
|
-
| `full_page_screenshot` | Full page screenshot |
|
|
356
343
|
| `element_screenshot` | Screenshot specific element |
|
|
357
344
|
| `pdf_generation` | Generate PDF from page |
|
|
358
345
|
| `video_recording` | Record page as video |
|
|
359
|
-
| `visual_comparison` | Compare screenshots |
|
|
360
346
|
|
|
361
|
-
### 📈 Monitoring & Reporting (
|
|
347
|
+
### 📈 Monitoring & Reporting (3 tools)
|
|
362
348
|
|
|
363
349
|
| Tool | Description |
|
|
364
350
|
| ----------------------- | ------------------------- |
|
|
365
351
|
| `progress_tracker` | Track automation progress |
|
|
366
352
|
| `success_rate_reporter` | Report success rates |
|
|
367
|
-
| `data_quality_metrics` | Data quality metrics |
|
|
368
353
|
| `performance_monitor` | Monitor performance |
|
|
369
|
-
| `monitoring_summary` | Get monitoring summary |
|
|
370
354
|
|
|
371
355
|
### 🛡️ Advanced Extraction & Obfuscation (4 tools)
|
|
372
356
|
|
|
@@ -376,11 +360,8 @@ npm install -g brave-real-browser-mcp-server@latest
|
|
|
376
360
|
| `multi_layer_redirect_trace` | Trace multi-layer redirects |
|
|
377
361
|
| `ad_protection_detector` | Detect ad protection |
|
|
378
362
|
|
|
379
|
-
|
|
380
363
|
## 🔧 Environment Variables
|
|
381
364
|
|
|
382
|
-
|
|
383
|
-
|
|
384
365
|
You can configure the server using the local `.env` file directly.
|
|
385
366
|
|
|
386
367
|
Edit `.env` to set your preferences:
|
|
@@ -401,9 +382,9 @@ PROXY_URL=http://localhost:8080
|
|
|
401
382
|
|
|
402
383
|
## 📊 Supported Protocols
|
|
403
384
|
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
385
|
+
| Protocol | Used By | Auto-Config | Status |
|
|
386
|
+
| --------------- | --------------------------------------------- | ----------- | ---------- |
|
|
387
|
+
| **MCP (STDIO)** | Claude Desktop, Cursor, Windsurf, Cline, Warp | ✅ | 🟢 Working |
|
|
407
388
|
|
|
408
389
|
## 📄 License
|
|
409
390
|
|
|
@@ -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
|
-
}
|
|
@@ -5,82 +5,6 @@
|
|
|
5
5
|
import { getCurrentPage } from '../browser-manager.js';
|
|
6
6
|
import { validateWorkflow } from '../workflow-validation.js';
|
|
7
7
|
import { withErrorHandling } from '../system-utils.js';
|
|
8
|
-
/**
|
|
9
|
-
* Bullet lists और numbered lists से data extract करता है
|
|
10
|
-
*/
|
|
11
|
-
export async function handleExtractList(args) {
|
|
12
|
-
return await withErrorHandling(async () => {
|
|
13
|
-
validateWorkflow('extract_list', {
|
|
14
|
-
requireBrowser: true,
|
|
15
|
-
requirePage: true,
|
|
16
|
-
});
|
|
17
|
-
const page = getCurrentPage();
|
|
18
|
-
const selector = args.selector || 'ul, ol';
|
|
19
|
-
const includeNested = args.includeNested !== false;
|
|
20
|
-
const maxItems = args.maxItems || 500;
|
|
21
|
-
const listData = await page.evaluate(({ selector, includeNested, maxItems }) => {
|
|
22
|
-
const lists = document.querySelectorAll(selector);
|
|
23
|
-
const results = [];
|
|
24
|
-
lists.forEach((list) => {
|
|
25
|
-
const items = [];
|
|
26
|
-
const listType = list.tagName.toLowerCase();
|
|
27
|
-
let hasNested = false;
|
|
28
|
-
const extractItems = (element, depth = 0) => {
|
|
29
|
-
if (items.length >= maxItems)
|
|
30
|
-
return;
|
|
31
|
-
const children = Array.from(element.children);
|
|
32
|
-
children.forEach((child) => {
|
|
33
|
-
if (child.tagName.toLowerCase() === 'li') {
|
|
34
|
-
const text = Array.from(child.childNodes)
|
|
35
|
-
.filter((node) => node.nodeType === Node.TEXT_NODE)
|
|
36
|
-
.map((node) => node.textContent?.trim())
|
|
37
|
-
.filter((text) => text)
|
|
38
|
-
.join(' ');
|
|
39
|
-
if (text) {
|
|
40
|
-
const indent = ' '.repeat(depth);
|
|
41
|
-
items.push(`${indent}${text}`);
|
|
42
|
-
}
|
|
43
|
-
// Check for nested lists
|
|
44
|
-
const nestedList = child.querySelector('ul, ol');
|
|
45
|
-
if (nestedList && includeNested) {
|
|
46
|
-
hasNested = true;
|
|
47
|
-
extractItems(nestedList, depth + 1);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
});
|
|
51
|
-
};
|
|
52
|
-
extractItems(list);
|
|
53
|
-
if (items.length > 0) {
|
|
54
|
-
results.push({
|
|
55
|
-
items,
|
|
56
|
-
type: listType,
|
|
57
|
-
nested: hasNested,
|
|
58
|
-
count: items.length,
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
});
|
|
62
|
-
return results;
|
|
63
|
-
}, { selector, includeNested, maxItems });
|
|
64
|
-
if (listData.length === 0) {
|
|
65
|
-
return {
|
|
66
|
-
content: [
|
|
67
|
-
{
|
|
68
|
-
type: 'text',
|
|
69
|
-
text: `❌ No lists found with selector "${selector}"`,
|
|
70
|
-
},
|
|
71
|
-
],
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
|
-
return {
|
|
75
|
-
content: [
|
|
76
|
-
{
|
|
77
|
-
type: 'text',
|
|
78
|
-
text: `✅ Extracted ${listData.length} list(s)\n\n${JSON.stringify(listData, null, 2)}`,
|
|
79
|
-
},
|
|
80
|
-
],
|
|
81
|
-
};
|
|
82
|
-
}, 'Failed to extract list');
|
|
83
|
-
}
|
|
84
8
|
/**
|
|
85
9
|
* Page में embedded JSON/API data खोजता और extract करता है
|
|
86
10
|
*/
|
|
@@ -46,46 +46,4 @@ export async function handleHTMLToText(args) {
|
|
|
46
46
|
};
|
|
47
47
|
}, 'Failed to convert HTML to text');
|
|
48
48
|
}
|
|
49
|
-
|
|
50
|
-
* Repeated data filter करता है
|
|
51
|
-
*/
|
|
52
|
-
export async function handleDuplicateRemover(args) {
|
|
53
|
-
return await withErrorHandling(async () => {
|
|
54
|
-
const data = args.data;
|
|
55
|
-
const uniqueKey = args.uniqueKey;
|
|
56
|
-
let unique;
|
|
57
|
-
if (uniqueKey) {
|
|
58
|
-
// Remove duplicates based on specific key
|
|
59
|
-
const seen = new Set();
|
|
60
|
-
unique = data.filter((item) => {
|
|
61
|
-
const value = item[uniqueKey];
|
|
62
|
-
if (seen.has(value)) {
|
|
63
|
-
return false;
|
|
64
|
-
}
|
|
65
|
-
seen.add(value);
|
|
66
|
-
return true;
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
else {
|
|
70
|
-
// Remove duplicates based on entire object
|
|
71
|
-
const seen = new Set();
|
|
72
|
-
unique = data.filter((item) => {
|
|
73
|
-
const serialized = JSON.stringify(item);
|
|
74
|
-
if (seen.has(serialized)) {
|
|
75
|
-
return false;
|
|
76
|
-
}
|
|
77
|
-
seen.add(serialized);
|
|
78
|
-
return true;
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
const removed = data.length - unique.length;
|
|
82
|
-
return {
|
|
83
|
-
content: [
|
|
84
|
-
{
|
|
85
|
-
type: 'text',
|
|
86
|
-
text: `✅ Duplicates removed\n\nOriginal: ${data.length} items\nUnique: ${unique.length} items\nRemoved: ${removed} duplicates\n\n${JSON.stringify(unique, null, 2)}`,
|
|
87
|
-
},
|
|
88
|
-
],
|
|
89
|
-
};
|
|
90
|
-
}, 'Failed to remove duplicates');
|
|
91
|
-
}
|
|
49
|
+
// Duplicate Remover Arguments
|
|
@@ -1,76 +1,9 @@
|
|
|
1
1
|
// @ts-nocheck
|
|
2
2
|
import Ajv from 'ajv/dist/2020.js';
|
|
3
|
-
import * as crypto from 'crypto';
|
|
4
3
|
const ajv = new Ajv();
|
|
5
4
|
/**
|
|
6
5
|
* Data Deduplication - Remove duplicate entries from scraped data
|
|
7
6
|
*/
|
|
8
|
-
export async function handleDataDeduplication(args) {
|
|
9
|
-
const { data, uniqueKeys, fuzzyMatch = false, threshold = 0.9 } = args;
|
|
10
|
-
try {
|
|
11
|
-
if (!Array.isArray(data)) {
|
|
12
|
-
throw new Error('Data must be an array');
|
|
13
|
-
}
|
|
14
|
-
const unique = [];
|
|
15
|
-
const duplicates = [];
|
|
16
|
-
const seen = new Set();
|
|
17
|
-
data.forEach((item, index) => {
|
|
18
|
-
let key;
|
|
19
|
-
if (uniqueKeys && Array.isArray(uniqueKeys)) {
|
|
20
|
-
// Create composite key from specified fields
|
|
21
|
-
const keyParts = uniqueKeys.map(k => {
|
|
22
|
-
const value = typeof item === 'object' ? item[k] : item;
|
|
23
|
-
return String(value || '');
|
|
24
|
-
});
|
|
25
|
-
key = keyParts.join('|');
|
|
26
|
-
}
|
|
27
|
-
else {
|
|
28
|
-
// Use entire object as key
|
|
29
|
-
key = JSON.stringify(item);
|
|
30
|
-
}
|
|
31
|
-
if (fuzzyMatch) {
|
|
32
|
-
// Normalize key for fuzzy matching
|
|
33
|
-
key = key.toLowerCase().replace(/\s+/g, ' ').trim();
|
|
34
|
-
}
|
|
35
|
-
const hash = crypto.createHash('md5').update(key).digest('hex');
|
|
36
|
-
if (seen.has(hash)) {
|
|
37
|
-
duplicates.push({ item, index, hash });
|
|
38
|
-
}
|
|
39
|
-
else {
|
|
40
|
-
seen.add(hash);
|
|
41
|
-
unique.push(item);
|
|
42
|
-
}
|
|
43
|
-
});
|
|
44
|
-
const dedupRate = ((duplicates.length / data.length) * 100).toFixed(2);
|
|
45
|
-
let summary = `Data Deduplication Results:\n\nStatistics:\n- Original Items: ${data.length}\n- Unique Items: ${unique.length}\n- Duplicates Found: ${duplicates.length}\n- Deduplication Rate: ${dedupRate}%`;
|
|
46
|
-
if (uniqueKeys) {
|
|
47
|
-
summary += `\n- Unique Keys Used: ${uniqueKeys.join(', ')}`;
|
|
48
|
-
}
|
|
49
|
-
summary += `\n- Fuzzy Matching: ${fuzzyMatch ? 'Enabled' : 'Disabled'}`;
|
|
50
|
-
if (duplicates.length > 0) {
|
|
51
|
-
summary += `\n\nSample Duplicates (Top 5):\n${duplicates.slice(0, 5).map((d, i) => `${i + 1}. Index ${d.index}: ${JSON.stringify(d.item).substring(0, 100)}...`).join('\n')}`;
|
|
52
|
-
}
|
|
53
|
-
return {
|
|
54
|
-
content: [
|
|
55
|
-
{
|
|
56
|
-
type: "text",
|
|
57
|
-
text: summary
|
|
58
|
-
}
|
|
59
|
-
]
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
catch (error) {
|
|
63
|
-
return {
|
|
64
|
-
content: [
|
|
65
|
-
{
|
|
66
|
-
type: "text",
|
|
67
|
-
text: `Data Deduplication Error: ${error.message}`
|
|
68
|
-
}
|
|
69
|
-
],
|
|
70
|
-
isError: true
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
7
|
/**
|
|
75
8
|
* Missing Data Handler - Detect and handle missing data
|
|
76
9
|
*/
|
|
@@ -144,188 +77,6 @@ export async function handleDataTypeValidator(args) {
|
|
|
144
77
|
};
|
|
145
78
|
}
|
|
146
79
|
}
|
|
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
80
|
/**
|
|
256
81
|
* Consistency Checker - Check data consistency across fields
|
|
257
82
|
*/
|
|
258
|
-
export async function handleConsistencyChecker(args) {
|
|
259
|
-
const { data, rules } = args;
|
|
260
|
-
try {
|
|
261
|
-
if (!Array.isArray(data)) {
|
|
262
|
-
throw new Error('Data must be an array');
|
|
263
|
-
}
|
|
264
|
-
if (!rules || !Array.isArray(rules)) {
|
|
265
|
-
if (!rules)
|
|
266
|
-
return { content: [{ type: "text", text: "No rules provided. Pass." }] };
|
|
267
|
-
throw new Error('Rules must be an array');
|
|
268
|
-
}
|
|
269
|
-
const report = {
|
|
270
|
-
totalItems: data.length,
|
|
271
|
-
passedItems: 0,
|
|
272
|
-
failedItems: 0,
|
|
273
|
-
failures: []
|
|
274
|
-
};
|
|
275
|
-
data.forEach((item, index) => {
|
|
276
|
-
let itemPassed = true;
|
|
277
|
-
const itemFailures = [];
|
|
278
|
-
rules.forEach((rule) => {
|
|
279
|
-
try {
|
|
280
|
-
if (rule.type === 'dependency') {
|
|
281
|
-
if (item[rule.field] && !item[rule.dependentField]) {
|
|
282
|
-
itemPassed = false;
|
|
283
|
-
itemFailures.push(`Field '${rule.field}' requires '${rule.dependentField}'`);
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
else if (rule.type === 'value_match') {
|
|
287
|
-
if (item[rule.field] === rule.value && item[rule.targetField] !== rule.targetValue) {
|
|
288
|
-
itemPassed = false;
|
|
289
|
-
itemFailures.push(`When '${rule.field}' is '${rule.value}', '${rule.targetField}' must be '${rule.targetValue}'`);
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
catch (e) {
|
|
294
|
-
itemPassed = false;
|
|
295
|
-
// @ts-ignore
|
|
296
|
-
itemFailures.push(`Rule execution error: ${e.message}`);
|
|
297
|
-
}
|
|
298
|
-
});
|
|
299
|
-
if (itemPassed) {
|
|
300
|
-
report.passedItems++;
|
|
301
|
-
}
|
|
302
|
-
else {
|
|
303
|
-
report.failedItems++;
|
|
304
|
-
report.failures.push({
|
|
305
|
-
index,
|
|
306
|
-
item,
|
|
307
|
-
errors: itemFailures
|
|
308
|
-
});
|
|
309
|
-
}
|
|
310
|
-
});
|
|
311
|
-
return {
|
|
312
|
-
content: [
|
|
313
|
-
{
|
|
314
|
-
type: "text",
|
|
315
|
-
text: `Consistency Check Results:\nTotal: ${report.totalItems}\nPassed: ${report.passedItems}\nFailed: ${report.failedItems}\n\nFailures:\n${JSON.stringify(report.failures, null, 2)}`
|
|
316
|
-
}
|
|
317
|
-
]
|
|
318
|
-
};
|
|
319
|
-
}
|
|
320
|
-
catch (error) {
|
|
321
|
-
return {
|
|
322
|
-
content: [
|
|
323
|
-
{
|
|
324
|
-
type: "text",
|
|
325
|
-
text: `Consistency Checker Error: ${error.message}`
|
|
326
|
-
}
|
|
327
|
-
],
|
|
328
|
-
isError: true
|
|
329
|
-
};
|
|
330
|
-
}
|
|
331
|
-
}
|
|
@@ -49,81 +49,6 @@ export async function handleShadowDOMExtractor(args) {
|
|
|
49
49
|
/**
|
|
50
50
|
* Cookie Manager - Manage cookies
|
|
51
51
|
*/
|
|
52
|
-
export async function handleCookieManager(args) {
|
|
53
|
-
return await withErrorHandling(async () => {
|
|
54
|
-
validateWorkflow('cookie_manager', {
|
|
55
|
-
requireBrowser: true,
|
|
56
|
-
requirePage: true,
|
|
57
|
-
});
|
|
58
|
-
const page = getCurrentPage();
|
|
59
|
-
const action = args.action || 'get'; // get, set, delete, clear
|
|
60
|
-
if (action === 'get') {
|
|
61
|
-
const cookies = await page.cookies();
|
|
62
|
-
return {
|
|
63
|
-
content: [{
|
|
64
|
-
type: 'text',
|
|
65
|
-
text: `✅ Retrieved ${cookies.length} cookies\n\n${JSON.stringify(cookies, null, 2)}`,
|
|
66
|
-
}],
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
if (action === 'set') {
|
|
70
|
-
const cookie = args.cookie;
|
|
71
|
-
if (!cookie || !cookie.name || !cookie.value) {
|
|
72
|
-
throw new Error('Cookie name and value are required');
|
|
73
|
-
}
|
|
74
|
-
await page.setCookie({
|
|
75
|
-
name: cookie.name,
|
|
76
|
-
value: cookie.value,
|
|
77
|
-
domain: cookie.domain || new URL(page.url()).hostname,
|
|
78
|
-
path: cookie.path || '/',
|
|
79
|
-
expires: cookie.expires,
|
|
80
|
-
httpOnly: cookie.httpOnly || false,
|
|
81
|
-
secure: cookie.secure || false,
|
|
82
|
-
sameSite: cookie.sameSite || 'Lax',
|
|
83
|
-
});
|
|
84
|
-
return {
|
|
85
|
-
content: [{
|
|
86
|
-
type: 'text',
|
|
87
|
-
text: `✅ Cookie set: ${cookie.name} = ${cookie.value}`,
|
|
88
|
-
}],
|
|
89
|
-
};
|
|
90
|
-
}
|
|
91
|
-
if (action === 'delete') {
|
|
92
|
-
const cookieName = args.cookieName;
|
|
93
|
-
if (!cookieName) {
|
|
94
|
-
throw new Error('Cookie name is required');
|
|
95
|
-
}
|
|
96
|
-
const cookies = await page.cookies();
|
|
97
|
-
const cookieToDelete = cookies.find(c => c.name === cookieName);
|
|
98
|
-
if (cookieToDelete) {
|
|
99
|
-
await page.deleteCookie(cookieToDelete);
|
|
100
|
-
return {
|
|
101
|
-
content: [{
|
|
102
|
-
type: 'text',
|
|
103
|
-
text: `✅ Cookie deleted: ${cookieName}`,
|
|
104
|
-
}],
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
|
-
return {
|
|
108
|
-
content: [{
|
|
109
|
-
type: 'text',
|
|
110
|
-
text: `⚠️ Cookie not found: ${cookieName}`,
|
|
111
|
-
}],
|
|
112
|
-
};
|
|
113
|
-
}
|
|
114
|
-
if (action === 'clear') {
|
|
115
|
-
const cookies = await page.cookies();
|
|
116
|
-
await Promise.all(cookies.map(cookie => page.deleteCookie(cookie)));
|
|
117
|
-
return {
|
|
118
|
-
content: [{
|
|
119
|
-
type: 'text',
|
|
120
|
-
text: `✅ Cleared all ${cookies.length} cookies`,
|
|
121
|
-
}],
|
|
122
|
-
};
|
|
123
|
-
}
|
|
124
|
-
throw new Error(`Unknown action: ${action}`);
|
|
125
|
-
}, 'Failed to manage cookies');
|
|
126
|
-
}
|
|
127
52
|
/**
|
|
128
53
|
* Session Persistence - Save and restore browser session
|
|
129
54
|
*/
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
// Monitoring & Reporting Module
|
|
2
2
|
// Progress tracking, error logging, success rate reporting, metrics
|
|
3
3
|
// @ts-nocheck
|
|
4
|
-
import { getCurrentPage } from '../browser-manager.js';
|
|
5
|
-
import { validateWorkflow } from '../workflow-validation.js';
|
|
6
4
|
import { withErrorHandling } from '../system-utils.js';
|
|
7
5
|
// Global monitoring state
|
|
8
6
|
const monitoringState = {
|
|
@@ -116,87 +114,6 @@ export async function handleProgressTracker(args) {
|
|
|
116
114
|
/**
|
|
117
115
|
* Data Quality Metrics - Report data quality metrics
|
|
118
116
|
*/
|
|
119
|
-
export async function handleDataQualityMetrics(args) {
|
|
120
|
-
return await withErrorHandling(async () => {
|
|
121
|
-
validateWorkflow('data_quality_metrics', {
|
|
122
|
-
requireBrowser: true,
|
|
123
|
-
requirePage: true,
|
|
124
|
-
});
|
|
125
|
-
const page = getCurrentPage();
|
|
126
|
-
const data = args.data || [];
|
|
127
|
-
// Calculate metrics
|
|
128
|
-
const metrics = {
|
|
129
|
-
totalRecords: data.length,
|
|
130
|
-
completeRecords: 0,
|
|
131
|
-
incompleteRecords: 0,
|
|
132
|
-
emptyFields: 0,
|
|
133
|
-
duplicates: 0,
|
|
134
|
-
dataTypes: {},
|
|
135
|
-
fieldCompleteness: {},
|
|
136
|
-
};
|
|
137
|
-
if (data.length === 0) {
|
|
138
|
-
return {
|
|
139
|
-
content: [{
|
|
140
|
-
type: 'text',
|
|
141
|
-
text: `ℹ️ No data provided for quality metrics`,
|
|
142
|
-
}],
|
|
143
|
-
};
|
|
144
|
-
}
|
|
145
|
-
// Analyze data quality
|
|
146
|
-
const seenRecords = new Set();
|
|
147
|
-
const allFields = new Set();
|
|
148
|
-
data.forEach((record) => {
|
|
149
|
-
const recordStr = JSON.stringify(record);
|
|
150
|
-
// Check for duplicates
|
|
151
|
-
if (seenRecords.has(recordStr)) {
|
|
152
|
-
metrics.duplicates++;
|
|
153
|
-
}
|
|
154
|
-
else {
|
|
155
|
-
seenRecords.add(recordStr);
|
|
156
|
-
}
|
|
157
|
-
// Collect all fields
|
|
158
|
-
Object.keys(record).forEach(key => allFields.add(key));
|
|
159
|
-
// Check completeness
|
|
160
|
-
let hasAllFields = true;
|
|
161
|
-
Object.values(record).forEach(value => {
|
|
162
|
-
if (value === null || value === undefined || value === '') {
|
|
163
|
-
metrics.emptyFields++;
|
|
164
|
-
hasAllFields = false;
|
|
165
|
-
}
|
|
166
|
-
});
|
|
167
|
-
if (hasAllFields) {
|
|
168
|
-
metrics.completeRecords++;
|
|
169
|
-
}
|
|
170
|
-
else {
|
|
171
|
-
metrics.incompleteRecords++;
|
|
172
|
-
}
|
|
173
|
-
});
|
|
174
|
-
// Field completeness
|
|
175
|
-
allFields.forEach(field => {
|
|
176
|
-
const nonEmptyCount = data.filter((record) => {
|
|
177
|
-
const value = record[field];
|
|
178
|
-
return value !== null && value !== undefined && value !== '';
|
|
179
|
-
}).length;
|
|
180
|
-
metrics.fieldCompleteness[field] = ((nonEmptyCount / data.length) * 100).toFixed(2) + '%';
|
|
181
|
-
});
|
|
182
|
-
// Data type analysis
|
|
183
|
-
allFields.forEach(field => {
|
|
184
|
-
const types = new Set();
|
|
185
|
-
data.forEach((record) => {
|
|
186
|
-
const value = record[field];
|
|
187
|
-
types.add(typeof value);
|
|
188
|
-
});
|
|
189
|
-
metrics.dataTypes[field] = Array.from(types).join(', ');
|
|
190
|
-
});
|
|
191
|
-
const qualityScore = ((metrics.completeRecords / metrics.totalRecords) * 100).toFixed(2);
|
|
192
|
-
return {
|
|
193
|
-
content: [{
|
|
194
|
-
type: 'text',
|
|
195
|
-
text: `✅ Data Quality Metrics\n\nTotal Records: ${metrics.totalRecords}\nComplete Records: ${metrics.completeRecords}\nIncomplete Records: ${metrics.incompleteRecords}\nDuplicates: ${metrics.duplicates}\nEmpty Fields: ${metrics.emptyFields}\n\nQuality Score: ${qualityScore}%\n\nField Completeness:\n${JSON.stringify(metrics.fieldCompleteness, null, 2)}\n\nData Types:\n${JSON.stringify(metrics.dataTypes, null, 2)}`,
|
|
196
|
-
}],
|
|
197
|
-
};
|
|
198
|
-
}, 'Failed data quality metrics');
|
|
199
|
-
}
|
|
200
117
|
/**
|
|
201
118
|
* Performance Monitor - Monitor browser and page performance
|
|
202
119
|
*/
|
|
@@ -2,64 +2,10 @@
|
|
|
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
|
|
10
8
|
*/
|
|
11
|
-
export async function handleFullPageScreenshot(args) {
|
|
12
|
-
const { url, outputPath, format = 'png', quality = 90, fullPage = true } = args;
|
|
13
|
-
try {
|
|
14
|
-
const page = getPageInstance();
|
|
15
|
-
if (!page) {
|
|
16
|
-
throw new Error('Browser not initialized. Call browser_init first.');
|
|
17
|
-
}
|
|
18
|
-
if (url && page.url() !== url) {
|
|
19
|
-
await page.goto(url, { waitUntil: 'networkidle2', timeout: 30000 });
|
|
20
|
-
}
|
|
21
|
-
// Ensure output directory exists
|
|
22
|
-
if (outputPath) {
|
|
23
|
-
const dir = path.dirname(outputPath);
|
|
24
|
-
await fs.mkdir(dir, { recursive: true });
|
|
25
|
-
}
|
|
26
|
-
const screenshotOptions = {
|
|
27
|
-
path: outputPath,
|
|
28
|
-
type: format,
|
|
29
|
-
fullPage
|
|
30
|
-
};
|
|
31
|
-
if (format === 'jpeg') {
|
|
32
|
-
screenshotOptions.quality = quality;
|
|
33
|
-
}
|
|
34
|
-
await page.screenshot(screenshotOptions);
|
|
35
|
-
// Get file stats if saved
|
|
36
|
-
let fileSize = 0;
|
|
37
|
-
if (outputPath) {
|
|
38
|
-
const stats = await fs.stat(outputPath);
|
|
39
|
-
fileSize = stats.size;
|
|
40
|
-
}
|
|
41
|
-
const resultText = `✅ Screenshot captured successfully\n\nPath: ${outputPath}\nFormat: ${format}\nFull Page: ${fullPage}\nFile Size: ${(fileSize / 1024).toFixed(2)} KB\nTimestamp: ${new Date().toISOString()}`;
|
|
42
|
-
return {
|
|
43
|
-
content: [
|
|
44
|
-
{
|
|
45
|
-
type: 'text',
|
|
46
|
-
text: resultText,
|
|
47
|
-
},
|
|
48
|
-
],
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
catch (error) {
|
|
52
|
-
return {
|
|
53
|
-
content: [
|
|
54
|
-
{
|
|
55
|
-
type: 'text',
|
|
56
|
-
text: `❌ Screenshot failed: ${error.message}`,
|
|
57
|
-
},
|
|
58
|
-
],
|
|
59
|
-
isError: true,
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
9
|
/**
|
|
64
10
|
* Element Screenshot - Capture specific element
|
|
65
11
|
*/
|
|
@@ -205,63 +151,3 @@ export async function handleVideoRecording(args) {
|
|
|
205
151
|
};
|
|
206
152
|
}
|
|
207
153
|
}
|
|
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
|
@@ -26,29 +26,29 @@ import { handleClick, handleType, handleSolveCaptcha, handleRandomScroll, } from
|
|
|
26
26
|
import { handleGetContent, handleFindSelector, } from "./handlers/content-handlers.js";
|
|
27
27
|
import { handleSaveContentAsMarkdown } from "./handlers/file-handlers.js";
|
|
28
28
|
// Import new data extraction handlers
|
|
29
|
-
import {
|
|
29
|
+
import { handleExtractJSON, handleScrapeMetaTags, handleExtractSchema, } from "./handlers/data-extraction-handlers.js";
|
|
30
30
|
// Import multi-element handlers
|
|
31
31
|
import { handleBatchElementScraper, handleNestedDataExtraction, handleAttributeHarvester, handleLinkHarvester, handleMediaExtractor, } from "./handlers/multi-element-handlers.js";
|
|
32
32
|
// Import pagination handlers
|
|
33
33
|
import { handleMultiPageScraper, handleBreadcrumbNavigator, } from "./handlers/pagination-handlers.js";
|
|
34
34
|
// Import data processing handlers
|
|
35
|
-
import { handleHTMLToText,
|
|
35
|
+
import { handleHTMLToText, } from "./handlers/data-processing-handlers.js";
|
|
36
36
|
// Import AI-powered handlers
|
|
37
37
|
import { handleSmartSelectorGenerator, handleContentClassification, } from "./handlers/ai-powered-handlers.js";
|
|
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 {
|
|
41
|
+
import { 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 {
|
|
45
|
+
import { handleElementScreenshot, handleVideoRecording, } from "./handlers/visual-tools-handlers.js";
|
|
46
46
|
// Import smart data extractors
|
|
47
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
|
-
import { handleShadowDOMExtractor,
|
|
49
|
+
import { handleShadowDOMExtractor, handleFormAutoFill, handleAjaxContentWaiter, } from "./handlers/dynamic-session-handlers.js";
|
|
50
50
|
// Import monitoring & reporting handlers
|
|
51
|
-
import { handleProgressTracker,
|
|
51
|
+
import { handleProgressTracker, } from "./handlers/monitoring-reporting-handlers.js";
|
|
52
52
|
// Import advanced video & media handlers
|
|
53
53
|
import { handleVideoLinkFinder, handleVideoDownloadButton, handleVideoPlayPushSource, handleVideoPlayButtonClick, } from "./handlers/advanced-video-media-handlers.js";
|
|
54
54
|
// Import advanced extraction handlers (Ad-bypass & Obfuscation)
|
|
@@ -139,9 +139,6 @@ export async function executeToolByName(name, args) {
|
|
|
139
139
|
result = await handleSaveContentAsMarkdown(args);
|
|
140
140
|
break;
|
|
141
141
|
// Smart Data Extractors
|
|
142
|
-
case TOOL_NAMES.EXTRACT_LIST:
|
|
143
|
-
result = await handleExtractList(args || {});
|
|
144
|
-
break;
|
|
145
142
|
case TOOL_NAMES.EXTRACT_JSON:
|
|
146
143
|
result = await handleExtractJSON(args || {});
|
|
147
144
|
break;
|
|
@@ -180,9 +177,6 @@ export async function executeToolByName(name, args) {
|
|
|
180
177
|
case TOOL_NAMES.HTML_TO_TEXT:
|
|
181
178
|
result = await handleHTMLToText(args);
|
|
182
179
|
break;
|
|
183
|
-
case TOOL_NAMES.DUPLICATE_REMOVER:
|
|
184
|
-
result = await handleDuplicateRemover(args);
|
|
185
|
-
break;
|
|
186
180
|
// AI-Powered Features
|
|
187
181
|
case TOOL_NAMES.SMART_SELECTOR_GENERATOR:
|
|
188
182
|
result = await handleSmartSelectorGenerator(args);
|
|
@@ -207,15 +201,9 @@ export async function executeToolByName(name, args) {
|
|
|
207
201
|
result = await handleVisualElementFinder(args);
|
|
208
202
|
break;
|
|
209
203
|
// Data Quality & Validation
|
|
210
|
-
case TOOL_NAMES.DATA_DEDUPLICATION:
|
|
211
|
-
result = await handleDataDeduplication(args);
|
|
212
|
-
break;
|
|
213
204
|
case TOOL_NAMES.DATA_TYPE_VALIDATOR:
|
|
214
205
|
result = await handleDataTypeValidator(args);
|
|
215
206
|
break;
|
|
216
|
-
case TOOL_NAMES.OUTLIER_DETECTION:
|
|
217
|
-
result = await handleOutlierDetection(args);
|
|
218
|
-
break;
|
|
219
207
|
// Advanced Captcha Handling
|
|
220
208
|
case TOOL_NAMES.OCR_ENGINE:
|
|
221
209
|
result = await handleOCREngine(args);
|
|
@@ -227,18 +215,12 @@ export async function executeToolByName(name, args) {
|
|
|
227
215
|
result = await handlePuzzleCaptchaHandler(args);
|
|
228
216
|
break;
|
|
229
217
|
// Screenshot & Visual Tools
|
|
230
|
-
case TOOL_NAMES.FULL_PAGE_SCREENSHOT:
|
|
231
|
-
result = await handleFullPageScreenshot(args);
|
|
232
|
-
break;
|
|
233
218
|
case TOOL_NAMES.ELEMENT_SCREENSHOT:
|
|
234
219
|
result = await handleElementScreenshot(args);
|
|
235
220
|
break;
|
|
236
221
|
case TOOL_NAMES.VIDEO_RECORDING:
|
|
237
222
|
result = await handleVideoRecording(args);
|
|
238
223
|
break;
|
|
239
|
-
case TOOL_NAMES.VISUAL_COMPARISON:
|
|
240
|
-
result = await handleVisualComparison(args);
|
|
241
|
-
break;
|
|
242
224
|
// Smart Data Extractors (Advanced)
|
|
243
225
|
case "html_elements_extractor":
|
|
244
226
|
result = await handleHtmlElementsExtractor(args || {});
|
|
@@ -286,9 +268,6 @@ export async function executeToolByName(name, args) {
|
|
|
286
268
|
case "shadow_dom_extractor":
|
|
287
269
|
result = await handleShadowDOMExtractor(args || {});
|
|
288
270
|
break;
|
|
289
|
-
case "cookie_manager":
|
|
290
|
-
result = await handleCookieManager(args);
|
|
291
|
-
break;
|
|
292
271
|
case "form_auto_fill":
|
|
293
272
|
result = await handleFormAutoFill(args);
|
|
294
273
|
break;
|
|
@@ -299,9 +278,6 @@ export async function executeToolByName(name, args) {
|
|
|
299
278
|
case "progress_tracker":
|
|
300
279
|
result = await handleProgressTracker(args || {});
|
|
301
280
|
break;
|
|
302
|
-
case "data_quality_metrics":
|
|
303
|
-
result = await handleDataQualityMetrics(args || {});
|
|
304
|
-
break;
|
|
305
281
|
// Advanced Video & Media Download Tools
|
|
306
282
|
case "video_link_finder":
|
|
307
283
|
result = await handleVideoLinkFinder(args || {});
|
package/dist/tool-definitions.js
CHANGED
|
@@ -331,18 +331,6 @@ export const TOOLS = [
|
|
|
331
331
|
},
|
|
332
332
|
},
|
|
333
333
|
// Smart Data Extractors
|
|
334
|
-
{
|
|
335
|
-
name: 'extract_list',
|
|
336
|
-
description: 'Extract data from bullet lists and numbered lists',
|
|
337
|
-
inputSchema: {
|
|
338
|
-
type: 'object',
|
|
339
|
-
properties: {
|
|
340
|
-
selector: { type: 'string', default: 'ul, ol' },
|
|
341
|
-
includeNested: { type: 'boolean', default: true },
|
|
342
|
-
maxItems: { type: 'number', default: 500 },
|
|
343
|
-
},
|
|
344
|
-
},
|
|
345
|
-
},
|
|
346
334
|
{
|
|
347
335
|
name: 'extract_json',
|
|
348
336
|
description: 'Extract embedded JSON/API data from the page',
|
|
@@ -483,18 +471,6 @@ export const TOOLS = [
|
|
|
483
471
|
},
|
|
484
472
|
},
|
|
485
473
|
// Data Validation Tools
|
|
486
|
-
{
|
|
487
|
-
name: 'duplicate_remover',
|
|
488
|
-
description: 'Remove duplicate items from an array',
|
|
489
|
-
inputSchema: {
|
|
490
|
-
type: 'object',
|
|
491
|
-
properties: {
|
|
492
|
-
data: { type: 'array' },
|
|
493
|
-
uniqueKey: { type: 'string' },
|
|
494
|
-
},
|
|
495
|
-
required: ['data'],
|
|
496
|
-
},
|
|
497
|
-
},
|
|
498
474
|
// AI-Powered Features (5 tools)
|
|
499
475
|
{
|
|
500
476
|
name: 'smart_selector_generator',
|
|
@@ -593,20 +569,6 @@ export const TOOLS = [
|
|
|
593
569
|
},
|
|
594
570
|
},
|
|
595
571
|
// Data Quality & Validation (5 tools)
|
|
596
|
-
{
|
|
597
|
-
name: 'data_deduplication',
|
|
598
|
-
description: 'Remove duplicate entries from scraped data',
|
|
599
|
-
inputSchema: {
|
|
600
|
-
type: 'object',
|
|
601
|
-
properties: {
|
|
602
|
-
data: { type: 'array' },
|
|
603
|
-
uniqueKeys: { type: 'array', items: { type: 'string' } },
|
|
604
|
-
fuzzyMatch: { type: 'boolean', default: false },
|
|
605
|
-
threshold: { type: 'number', default: 0.9 },
|
|
606
|
-
},
|
|
607
|
-
required: ['data'],
|
|
608
|
-
},
|
|
609
|
-
},
|
|
610
572
|
{
|
|
611
573
|
name: 'data_type_validator',
|
|
612
574
|
description: 'Validate data types against JSON schema',
|
|
@@ -619,32 +581,6 @@ export const TOOLS = [
|
|
|
619
581
|
required: ['data', 'schema'],
|
|
620
582
|
},
|
|
621
583
|
},
|
|
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
|
-
{
|
|
637
|
-
name: 'consistency_checker',
|
|
638
|
-
description: 'Check data consistency across fields',
|
|
639
|
-
inputSchema: {
|
|
640
|
-
type: 'object',
|
|
641
|
-
properties: {
|
|
642
|
-
data: { type: 'array' },
|
|
643
|
-
rules: { type: 'array', description: 'Validation rules' },
|
|
644
|
-
},
|
|
645
|
-
required: ['data', 'rules'],
|
|
646
|
-
},
|
|
647
|
-
},
|
|
648
584
|
// Advanced Captcha Handling (3 tools)
|
|
649
585
|
{
|
|
650
586
|
name: 'ocr_engine',
|
|
@@ -687,21 +623,6 @@ export const TOOLS = [
|
|
|
687
623
|
},
|
|
688
624
|
},
|
|
689
625
|
// Screenshot & Visual Tools (5 tools)
|
|
690
|
-
{
|
|
691
|
-
name: 'full_page_screenshot',
|
|
692
|
-
description: 'Capture entire page screenshot',
|
|
693
|
-
inputSchema: {
|
|
694
|
-
type: 'object',
|
|
695
|
-
properties: {
|
|
696
|
-
url: { type: 'string' },
|
|
697
|
-
outputPath: { type: 'string' },
|
|
698
|
-
format: { type: 'string', enum: ['png', 'jpeg'], default: 'png' },
|
|
699
|
-
quality: { type: 'number', default: 90 },
|
|
700
|
-
fullPage: { type: 'boolean', default: true },
|
|
701
|
-
},
|
|
702
|
-
required: ['outputPath'],
|
|
703
|
-
},
|
|
704
|
-
},
|
|
705
626
|
{
|
|
706
627
|
name: 'element_screenshot',
|
|
707
628
|
description: 'Capture screenshot of specific element',
|
|
@@ -730,20 +651,6 @@ export const TOOLS = [
|
|
|
730
651
|
required: ['outputPath'],
|
|
731
652
|
},
|
|
732
653
|
},
|
|
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
654
|
// Smart Data Extractors (Advanced)
|
|
748
655
|
{
|
|
749
656
|
name: 'html_elements_extractor',
|
|
@@ -898,18 +805,6 @@ export const TOOLS = [
|
|
|
898
805
|
},
|
|
899
806
|
},
|
|
900
807
|
},
|
|
901
|
-
{
|
|
902
|
-
name: 'cookie_manager',
|
|
903
|
-
description: 'Manage cookies (get, set, delete, clear)',
|
|
904
|
-
inputSchema: {
|
|
905
|
-
type: 'object',
|
|
906
|
-
properties: {
|
|
907
|
-
action: { type: 'string', enum: ['get', 'set', 'delete', 'clear'], default: 'get' },
|
|
908
|
-
cookie: { type: 'object' },
|
|
909
|
-
cookieName: { type: 'string' },
|
|
910
|
-
},
|
|
911
|
-
},
|
|
912
|
-
},
|
|
913
808
|
{
|
|
914
809
|
name: 'form_auto_fill',
|
|
915
810
|
description: 'Automatically fill form fields',
|
|
@@ -950,16 +845,6 @@ export const TOOLS = [
|
|
|
950
845
|
},
|
|
951
846
|
},
|
|
952
847
|
},
|
|
953
|
-
{
|
|
954
|
-
name: 'data_quality_metrics',
|
|
955
|
-
description: 'Report data quality metrics',
|
|
956
|
-
inputSchema: {
|
|
957
|
-
type: 'object',
|
|
958
|
-
properties: {
|
|
959
|
-
data: { type: 'array' },
|
|
960
|
-
},
|
|
961
|
-
},
|
|
962
|
-
},
|
|
963
848
|
// Advanced Video & Media Download Tools
|
|
964
849
|
{
|
|
965
850
|
name: 'video_link_finder',
|
|
@@ -1055,43 +940,6 @@ export const TOOLS = [
|
|
|
1055
940
|
},
|
|
1056
941
|
},
|
|
1057
942
|
},
|
|
1058
|
-
{
|
|
1059
|
-
name: 'sentiment_analysis',
|
|
1060
|
-
description: 'Analyze the sentiment of text or page content',
|
|
1061
|
-
inputSchema: {
|
|
1062
|
-
type: 'object',
|
|
1063
|
-
properties: {
|
|
1064
|
-
text: { type: 'string', description: 'Text to analyze' },
|
|
1065
|
-
url: { type: 'string', description: 'URL to analyze' },
|
|
1066
|
-
selector: { type: 'string', description: 'Selector to extract text from' }
|
|
1067
|
-
}
|
|
1068
|
-
}
|
|
1069
|
-
},
|
|
1070
|
-
{
|
|
1071
|
-
name: 'summary_generator',
|
|
1072
|
-
description: 'Generate a summary of text or page content',
|
|
1073
|
-
inputSchema: {
|
|
1074
|
-
type: 'object',
|
|
1075
|
-
properties: {
|
|
1076
|
-
text: { type: 'string', description: 'Text to summarize' },
|
|
1077
|
-
url: { type: 'string', description: 'URL to summarize' },
|
|
1078
|
-
selector: { type: 'string', description: 'Selector to extract text from' },
|
|
1079
|
-
maxLength: { type: 'number', description: 'Maximum length of summary' }
|
|
1080
|
-
}
|
|
1081
|
-
}
|
|
1082
|
-
},
|
|
1083
|
-
{
|
|
1084
|
-
name: 'translation_support',
|
|
1085
|
-
description: 'Detect language and translate text',
|
|
1086
|
-
inputSchema: {
|
|
1087
|
-
type: 'object',
|
|
1088
|
-
properties: {
|
|
1089
|
-
text: { type: 'string', description: 'Text to translate' },
|
|
1090
|
-
url: { type: 'string', description: 'URL to translate content from' },
|
|
1091
|
-
targetLanguage: { type: 'string', description: 'Target language code (e.g. "es", "fr")' }
|
|
1092
|
-
}
|
|
1093
|
-
}
|
|
1094
|
-
},
|
|
1095
943
|
// Phase 3: Media & Video Tools
|
|
1096
944
|
{
|
|
1097
945
|
name: 'video_source_extractor',
|
|
@@ -1148,8 +996,6 @@ export const TOOL_NAMES = {
|
|
|
1148
996
|
RANDOM_SCROLL: 'random_scroll',
|
|
1149
997
|
FIND_SELECTOR: 'find_selector',
|
|
1150
998
|
SAVE_CONTENT_AS_MARKDOWN: 'save_content_as_markdown',
|
|
1151
|
-
// Smart Data Extractors
|
|
1152
|
-
EXTRACT_LIST: 'extract_list',
|
|
1153
999
|
EXTRACT_JSON: 'extract_json',
|
|
1154
1000
|
SCRAPE_META_TAGS: 'scrape_meta_tags',
|
|
1155
1001
|
EXTRACT_SCHEMA: 'extract_schema',
|
|
@@ -1178,13 +1024,9 @@ export const TOOL_NAMES = {
|
|
|
1178
1024
|
BREADCRUMB_NAVIGATOR: 'breadcrumb_navigator',
|
|
1179
1025
|
// Data Processing
|
|
1180
1026
|
HTML_TO_TEXT: 'html_to_text',
|
|
1181
|
-
DUPLICATE_REMOVER: 'duplicate_remover',
|
|
1182
1027
|
// AI-Powered Features
|
|
1183
1028
|
SMART_SELECTOR_GENERATOR: 'smart_selector_generator',
|
|
1184
1029
|
CONTENT_CLASSIFICATION: 'content_classification',
|
|
1185
|
-
SENTIMENT_ANALYSIS: 'sentiment_analysis',
|
|
1186
|
-
SUMMARY_GENERATOR: 'summary_generator',
|
|
1187
|
-
TRANSLATION_SUPPORT: 'translation_support',
|
|
1188
1030
|
// Phase 3: Media & Video
|
|
1189
1031
|
VIDEO_SOURCE_EXTRACTOR: 'video_source_extractor',
|
|
1190
1032
|
VIDEO_PLAYER_FINDER: 'video_player_finder',
|
|
@@ -1196,18 +1038,14 @@ export const TOOL_NAMES = {
|
|
|
1196
1038
|
ADVANCED_CSS_SELECTORS: 'advanced_css_selectors',
|
|
1197
1039
|
VISUAL_ELEMENT_FINDER: 'visual_element_finder',
|
|
1198
1040
|
// Data Quality & Validation
|
|
1199
|
-
DATA_DEDUPLICATION: 'data_deduplication',
|
|
1200
1041
|
DATA_TYPE_VALIDATOR: 'data_type_validator',
|
|
1201
|
-
OUTLIER_DETECTION: 'outlier_detection',
|
|
1202
1042
|
// Advanced Captcha Handling
|
|
1203
1043
|
OCR_ENGINE: 'ocr_engine',
|
|
1204
1044
|
AUDIO_CAPTCHA_SOLVER: 'audio_captcha_solver',
|
|
1205
1045
|
PUZZLE_CAPTCHA_HANDLER: 'puzzle_captcha_handler',
|
|
1206
1046
|
// Screenshot & Visual Tools
|
|
1207
|
-
FULL_PAGE_SCREENSHOT: 'full_page_screenshot',
|
|
1208
1047
|
ELEMENT_SCREENSHOT: 'element_screenshot',
|
|
1209
1048
|
VIDEO_RECORDING: 'video_recording',
|
|
1210
|
-
VISUAL_COMPARISON: 'visual_comparison',
|
|
1211
1049
|
};
|
|
1212
1050
|
// Tool categories for organization
|
|
1213
1051
|
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.5",
|
|
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",
|