brave-real-browser-mcp-server 2.15.6 → 2.15.7
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/brave-installer.js +182 -0
- package/dist/browser-manager.js +22 -1
- package/dist/handlers/data-extraction-handlers.js +33 -3
- package/dist/handlers/multi-element-handlers.js +5 -0
- package/dist/handlers/smart-data-extractors.js +21 -1
- package/dist/index.js +15 -45
- package/dist/tool-definitions.js +5 -160
- package/package.json +1 -1
- package/scripts/check-tool-registration.ts +66 -0
- package/scripts/verify-brave-installer.cjs +13 -0
- package/scripts/verify-fixes-custom.ts +108 -0
- package/scripts/verify-fixes-standalone.js +244 -0
- package/scripts/verify-fixes-standalone.ts +248 -0
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import * as os from 'os';
|
|
4
|
+
import { exec, spawn } from 'child_process';
|
|
5
|
+
import axios from 'axios';
|
|
6
|
+
import { promisify } from 'util';
|
|
7
|
+
const execAsync = promisify(exec);
|
|
8
|
+
export class BraveInstaller {
|
|
9
|
+
static WINDOWS_INSTALLER_URL = 'https://laptop-updates.brave.com/latest/winx64';
|
|
10
|
+
static MAC_INSTALLER_URL = 'https://laptop-updates.brave.com/latest/osx';
|
|
11
|
+
/**
|
|
12
|
+
* Install Brave Browser based on the current platform with Silent/Auto options
|
|
13
|
+
*/
|
|
14
|
+
static async install() {
|
|
15
|
+
const platform = process.platform;
|
|
16
|
+
console.error(`⬇️ Attempting to install Brave Browser for ${platform} (Silent Mode)...`);
|
|
17
|
+
try {
|
|
18
|
+
if (platform === 'win32') {
|
|
19
|
+
return await this.installOnWindows();
|
|
20
|
+
}
|
|
21
|
+
else if (platform === 'darwin') {
|
|
22
|
+
return await this.installOnMac();
|
|
23
|
+
}
|
|
24
|
+
else if (platform === 'linux') {
|
|
25
|
+
return await this.installOnLinux();
|
|
26
|
+
}
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
console.error(`❌ Failed to install Brave: ${error.message}`);
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Install Brave on Windows (Silent Install)
|
|
36
|
+
*/
|
|
37
|
+
static async installOnWindows() {
|
|
38
|
+
const tempDir = os.tmpdir();
|
|
39
|
+
const installerPath = path.join(tempDir, 'BraveBrowserSetup.exe');
|
|
40
|
+
console.error('1️⃣ Downloading Brave Installer...');
|
|
41
|
+
try {
|
|
42
|
+
await this.downloadFile(this.WINDOWS_INSTALLER_URL, installerPath);
|
|
43
|
+
}
|
|
44
|
+
catch (e) {
|
|
45
|
+
console.error(` Download failed: ${e.message}`);
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
console.error('2️⃣ Running Installer (Silent Mode)...');
|
|
49
|
+
try {
|
|
50
|
+
// /silent and /install are standard for Brave/Chrome
|
|
51
|
+
// Triggers UAC prompt if not already elevated, but handles the UI silently
|
|
52
|
+
const installCmd = `"${installerPath}" --silent --install`;
|
|
53
|
+
await execAsync(installCmd);
|
|
54
|
+
console.error('⏳ Waiting for installation to complete...');
|
|
55
|
+
// Wait multiple intervals to ensure filesystem sync
|
|
56
|
+
await new Promise(resolve => setTimeout(resolve, 30000));
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
console.error(' Silent install failed, attempting interactive fallback...');
|
|
61
|
+
try {
|
|
62
|
+
// Fallback: Launch normally so user can interact
|
|
63
|
+
const child = spawn(installerPath, { detached: true, stdio: 'ignore' });
|
|
64
|
+
child.unref();
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
catch (e) {
|
|
68
|
+
console.error(` Failed to launch installer: ${error.message}`);
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Install Brave on Mac (Silent/Automated Install via DMG)
|
|
75
|
+
*/
|
|
76
|
+
static async installOnMac() {
|
|
77
|
+
const tempDir = os.tmpdir();
|
|
78
|
+
const dmgPath = path.join(tempDir, 'Brave-Browser.dmg');
|
|
79
|
+
console.error('1️⃣ Downloading Brave DMG...');
|
|
80
|
+
try {
|
|
81
|
+
await this.downloadFile(this.MAC_INSTALLER_URL, dmgPath);
|
|
82
|
+
}
|
|
83
|
+
catch (e) {
|
|
84
|
+
console.error(` Download failed: ${e.message}`);
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
console.error('2️⃣ Mounting DMG...');
|
|
88
|
+
try {
|
|
89
|
+
// Attach huge image quietly
|
|
90
|
+
await execAsync(`hdiutil attach "${dmgPath}" -nobrowse -quiet`);
|
|
91
|
+
console.error('3️⃣ Copying to Applications...');
|
|
92
|
+
// Copy the app bundle
|
|
93
|
+
try {
|
|
94
|
+
await execAsync(`cp -R "/Volumes/Brave Browser/Brave Browser.app" /Applications/`);
|
|
95
|
+
// Cleanup: Detach
|
|
96
|
+
try {
|
|
97
|
+
await execAsync(`hdiutil detach "/Volumes/Brave Browser" -quiet`);
|
|
98
|
+
}
|
|
99
|
+
catch (e) { }
|
|
100
|
+
// Force attribute update to remove quarantine (avoids 'downloaded from internet' popup)
|
|
101
|
+
try {
|
|
102
|
+
await execAsync(`xattr -r -d com.apple.quarantine "/Applications/Brave Browser.app"`);
|
|
103
|
+
}
|
|
104
|
+
catch (e) { }
|
|
105
|
+
return true;
|
|
106
|
+
}
|
|
107
|
+
catch (e) {
|
|
108
|
+
console.error(' Copy failed (Permission denied?). Opening DMG for user manually...');
|
|
109
|
+
await execAsync(`open "${dmgPath}"`);
|
|
110
|
+
return true;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
catch (error) {
|
|
114
|
+
console.error(` Install failed: ${error.message}`);
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Install Brave on Linux (Debian/Ubuntu/Fedora support)
|
|
120
|
+
*/
|
|
121
|
+
static async installOnLinux() {
|
|
122
|
+
console.error('1️⃣ Detecting Linux distribution...');
|
|
123
|
+
try {
|
|
124
|
+
let dist = 'unknown';
|
|
125
|
+
if (fs.existsSync('/etc/debian_version'))
|
|
126
|
+
dist = 'debian';
|
|
127
|
+
else if (fs.existsSync('/etc/fedora-release'))
|
|
128
|
+
dist = 'fedora';
|
|
129
|
+
// Can extend for Arch/openSUSE if needed
|
|
130
|
+
console.error(` Detected family: ${dist}`);
|
|
131
|
+
if (dist === 'debian') {
|
|
132
|
+
console.error('2️⃣ Installing for Debian/Ubuntu (Attempting sudo)...');
|
|
133
|
+
// Basic check if we are root or can sudo
|
|
134
|
+
const cmd = `
|
|
135
|
+
sudo apt install -y curl &&
|
|
136
|
+
sudo curl -fsSLo /usr/share/keyrings/brave-browser-archive-keyring.gpg https://brave-browser-apt-release.s3.brave.com/brave-browser-archive-keyring.gpg &&
|
|
137
|
+
echo "deb [signed-by=/usr/share/keyrings/brave-browser-archive-keyring.gpg] https://brave-browser-apt-release.s3.brave.com/ stable main" | sudo tee /etc/apt/sources.list.d/brave-browser-release.list &&
|
|
138
|
+
sudo apt update &&
|
|
139
|
+
sudo apt install -y brave-browser
|
|
140
|
+
`;
|
|
141
|
+
await execAsync(cmd);
|
|
142
|
+
return true;
|
|
143
|
+
}
|
|
144
|
+
else if (dist === 'fedora') {
|
|
145
|
+
console.error('2️⃣ Installing for Fedora/CentOS (Attempting sudo)...');
|
|
146
|
+
const cmd = `
|
|
147
|
+
sudo dnf install -y dnf-plugins-core &&
|
|
148
|
+
sudo dnf config-manager --add-repo https://brave-browser-rpm-release.s3.brave.com/brave-browser.repo &&
|
|
149
|
+
sudo rpm --import https://brave-browser-rpm-release.s3.brave.com/brave-core.asc &&
|
|
150
|
+
sudo dnf install -y brave-browser
|
|
151
|
+
`;
|
|
152
|
+
await execAsync(cmd);
|
|
153
|
+
return true;
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
console.error(' Unsupported Linux distribution for auto-install.');
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
catch (error) {
|
|
161
|
+
console.error(` Linux install failed: ${error.message}`);
|
|
162
|
+
console.error(' Note: This requires sudo/root access without password or interactive terminal.');
|
|
163
|
+
return false;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Download a file from URL to destination
|
|
168
|
+
*/
|
|
169
|
+
static async downloadFile(url, dest) {
|
|
170
|
+
const writer = fs.createWriteStream(dest);
|
|
171
|
+
const response = await axios({
|
|
172
|
+
url,
|
|
173
|
+
method: 'GET',
|
|
174
|
+
responseType: 'stream'
|
|
175
|
+
});
|
|
176
|
+
response.data.pipe(writer);
|
|
177
|
+
return new Promise((resolve, reject) => {
|
|
178
|
+
writer.on('finish', resolve);
|
|
179
|
+
writer.on('error', reject);
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
}
|
package/dist/browser-manager.js
CHANGED
|
@@ -4,6 +4,7 @@ import * as path from 'path';
|
|
|
4
4
|
import * as net from 'net';
|
|
5
5
|
import { execSync, spawn } from 'child_process';
|
|
6
6
|
import { config as dotenvConfig } from 'dotenv';
|
|
7
|
+
import { BraveInstaller } from './brave-installer.js';
|
|
7
8
|
// Load environment variables from .env file
|
|
8
9
|
// Silence dotenv output
|
|
9
10
|
const originalWrite = process.stdout.write;
|
|
@@ -25,6 +26,12 @@ export var BrowserErrorType;
|
|
|
25
26
|
// Store browser instance
|
|
26
27
|
let browserInstance = null;
|
|
27
28
|
let pageInstance = null;
|
|
29
|
+
export function setBrowser(browser) {
|
|
30
|
+
browserInstance = browser;
|
|
31
|
+
}
|
|
32
|
+
export function setPage(page) {
|
|
33
|
+
pageInstance = page;
|
|
34
|
+
}
|
|
28
35
|
// Check environment variable for testing override
|
|
29
36
|
const disableContentPriority = process.env.DISABLE_CONTENT_PRIORITY === 'true' || process.env.NODE_ENV === 'test';
|
|
30
37
|
let contentPriorityConfig = {
|
|
@@ -431,7 +438,21 @@ export async function initializeBrowser(options) {
|
|
|
431
438
|
await closeBrowser();
|
|
432
439
|
}
|
|
433
440
|
}
|
|
434
|
-
|
|
441
|
+
let detectedBravePath = detectBravePath();
|
|
442
|
+
const autoInstall = options?.autoInstall ?? true;
|
|
443
|
+
if (!detectedBravePath && autoInstall) {
|
|
444
|
+
console.error('⚠️ Brave Browser not found. autoInstall is enabled.');
|
|
445
|
+
const installed = await BraveInstaller.install();
|
|
446
|
+
if (installed) {
|
|
447
|
+
console.error('✅ Installation triggered. Retrying detection...');
|
|
448
|
+
// Wait a bit to ensure it's registered
|
|
449
|
+
await new Promise(r => setTimeout(r, 2000));
|
|
450
|
+
detectedBravePath = detectBravePath();
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
if (!detectedBravePath && !options?.customConfig?.chromePath) {
|
|
454
|
+
throw new Error('Brave Browser not found and auto-install failed or disabled. Please install Brave Browser manually: https://brave.com/download/');
|
|
455
|
+
}
|
|
435
456
|
const customConfig = options?.customConfig ?? {};
|
|
436
457
|
const platform = process.platform;
|
|
437
458
|
const getOptimalBraveFlags = (isWindows, isRetry = false) => {
|
|
@@ -25,11 +25,11 @@ export async function handleExtractJSON(args) {
|
|
|
25
25
|
const defaultSelector = selector || 'script[type="application/json"], script[type="application/ld+json"], script';
|
|
26
26
|
const scripts = document.querySelectorAll(defaultSelector);
|
|
27
27
|
scripts.forEach((script, index) => {
|
|
28
|
+
const content = script.textContent || '';
|
|
28
29
|
try {
|
|
29
|
-
|
|
30
|
+
// 1. Try direct parsing first
|
|
30
31
|
const data = JSON.parse(content);
|
|
31
32
|
if (filter) {
|
|
32
|
-
// Simple filter check
|
|
33
33
|
const filterLower = filter.toLowerCase();
|
|
34
34
|
const dataStr = JSON.stringify(data).toLowerCase();
|
|
35
35
|
if (!dataStr.includes(filterLower))
|
|
@@ -42,7 +42,37 @@ export async function handleExtractJSON(args) {
|
|
|
42
42
|
});
|
|
43
43
|
}
|
|
44
44
|
catch (e) {
|
|
45
|
-
//
|
|
45
|
+
// 2. Fallback: Try to find JSON objects using regex
|
|
46
|
+
// Matches { "key": ... } or [ ... ] structures
|
|
47
|
+
const jsonRegex = /({[\s\S]*?}|\[[\s\S]*?\])/g;
|
|
48
|
+
let match;
|
|
49
|
+
while ((match = jsonRegex.exec(content)) !== null) {
|
|
50
|
+
const potentialJson = match[0];
|
|
51
|
+
// Basic heuristic to avoid trying to parse tiny fragments
|
|
52
|
+
if (potentialJson.length < 20)
|
|
53
|
+
continue;
|
|
54
|
+
try {
|
|
55
|
+
const data = JSON.parse(potentialJson);
|
|
56
|
+
// Check filter
|
|
57
|
+
if (filter) {
|
|
58
|
+
const filterLower = filter.toLowerCase();
|
|
59
|
+
const dataStr = JSON.stringify(data).toLowerCase();
|
|
60
|
+
if (!dataStr.includes(filterLower))
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
// Basic check to ensure it's a nontrivial object/array
|
|
64
|
+
if ((Array.isArray(data) && data.length > 0) || (typeof data === 'object' && data !== null && Object.keys(data).length > 0)) {
|
|
65
|
+
results.push({
|
|
66
|
+
data,
|
|
67
|
+
source: 'script',
|
|
68
|
+
path: `script[${index}]_regex_match`,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
catch (e2) {
|
|
73
|
+
// Not valid JSON
|
|
74
|
+
}
|
|
75
|
+
}
|
|
46
76
|
}
|
|
47
77
|
});
|
|
48
78
|
}
|
|
@@ -146,6 +146,10 @@ export async function handleLinkHarvester(args) {
|
|
|
146
146
|
const results = [];
|
|
147
147
|
links.forEach((link, index) => {
|
|
148
148
|
const href = link.href;
|
|
149
|
+
// Skip if no href (e.g. button without href)
|
|
150
|
+
if (!href) {
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
149
153
|
// Skip anchors if not included
|
|
150
154
|
if (!includeAnchors && href.startsWith('#')) {
|
|
151
155
|
return;
|
|
@@ -177,6 +181,7 @@ export async function handleLinkHarvester(args) {
|
|
|
177
181
|
}
|
|
178
182
|
catch (e) {
|
|
179
183
|
linkInfo.type = 'invalid';
|
|
184
|
+
linkInfo.domain = 'unknown'; // Ensure domain exists even if invalid
|
|
180
185
|
}
|
|
181
186
|
}
|
|
182
187
|
// Additional attributes
|
|
@@ -307,7 +307,18 @@ export async function handleFetchXHR(args) {
|
|
|
307
307
|
});
|
|
308
308
|
const page = getCurrentPage();
|
|
309
309
|
const duration = args.duration || 15000;
|
|
310
|
+
const forceReload = args.forceReload !== false; // Default true to capture initial requests
|
|
310
311
|
const xhrData = [];
|
|
312
|
+
// Capture requests too for completeness
|
|
313
|
+
const requestHandler = (request) => {
|
|
314
|
+
try {
|
|
315
|
+
const resourceType = request.resourceType();
|
|
316
|
+
if (resourceType === 'xhr' || resourceType === 'fetch') {
|
|
317
|
+
// Optional: Log request if needed, but for now we focus on responses with bodies
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
catch (e) { }
|
|
321
|
+
};
|
|
311
322
|
const responseHandler = async (response) => {
|
|
312
323
|
const request = response.request();
|
|
313
324
|
const resourceType = request.resourceType();
|
|
@@ -320,7 +331,8 @@ export async function handleFetchXHR(args) {
|
|
|
320
331
|
statusText: response.statusText(),
|
|
321
332
|
headers: response.headers(),
|
|
322
333
|
method: request.method(),
|
|
323
|
-
|
|
334
|
+
postData: request.postData(),
|
|
335
|
+
body: body.substring(0, 5000), // Increased limit
|
|
324
336
|
timestamp: new Date().toISOString(),
|
|
325
337
|
});
|
|
326
338
|
}
|
|
@@ -330,6 +342,14 @@ export async function handleFetchXHR(args) {
|
|
|
330
342
|
}
|
|
331
343
|
};
|
|
332
344
|
page.on('response', responseHandler);
|
|
345
|
+
if (forceReload) {
|
|
346
|
+
try {
|
|
347
|
+
await page.reload({ waitUntil: 'networkidle2', timeout: 30000 });
|
|
348
|
+
}
|
|
349
|
+
catch (e) {
|
|
350
|
+
// Continue even if reload times out
|
|
351
|
+
}
|
|
352
|
+
}
|
|
333
353
|
await sleep(duration);
|
|
334
354
|
page.off('response', responseHandler);
|
|
335
355
|
return {
|
package/dist/index.js
CHANGED
|
@@ -22,7 +22,7 @@ import { setupProcessCleanup, } from "./core-infrastructure.js";
|
|
|
22
22
|
console.error("🔍 [DEBUG] Loading handlers...");
|
|
23
23
|
import { handleBrowserInit, handleBrowserClose, } from "./handlers/browser-handlers.js";
|
|
24
24
|
import { handleNavigate, handleWait } from "./handlers/navigation-handlers.js";
|
|
25
|
-
import { handleClick, handleType, handleSolveCaptcha, handleRandomScroll, } from "./handlers/interaction-handlers.js";
|
|
25
|
+
import { handleClick, handleType, handleSolveCaptcha, handleRandomScroll, handlePressKey, } from "./handlers/interaction-handlers.js";
|
|
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
|
|
@@ -42,13 +42,13 @@ import { handleOCREngine, handleAudioCaptchaSolver, handlePuzzleCaptchaHandler,
|
|
|
42
42
|
// Import visual tools handlers
|
|
43
43
|
import { handleElementScreenshot, handleVideoRecording, } from "./handlers/visual-tools-handlers.js";
|
|
44
44
|
// Import smart data extractors
|
|
45
|
-
import {
|
|
45
|
+
import { handleFetchXHR, handleNetworkRecorder, handleImageExtractorAdvanced, handleVideoSourceExtractor, handleUrlRedirectTracer, handleApiFinder, } from "./handlers/smart-data-extractors.js";
|
|
46
46
|
// Import dynamic session handlers
|
|
47
|
-
import {
|
|
47
|
+
import { handleAjaxContentWaiter, } from "./handlers/dynamic-session-handlers.js";
|
|
48
48
|
// Import monitoring & reporting handlers
|
|
49
49
|
import { handleProgressTracker, } from "./handlers/monitoring-reporting-handlers.js";
|
|
50
50
|
// Import advanced video & media handlers
|
|
51
|
-
import {
|
|
51
|
+
import { handleVideoPlayerFinder, handleStreamDetector, handleVideoDownloadLinkFinder, } from "./handlers/advanced-video-media-handlers.js";
|
|
52
52
|
// Import advanced extraction handlers (Ad-bypass & Obfuscation)
|
|
53
53
|
import { handleAdvancedVideoExtraction, handleDeobfuscateJS, handleMultiLayerRedirectTrace, handleAdProtectionDetector, } from "./handlers/advanced-extraction-handlers.js";
|
|
54
54
|
console.error("🔍 [DEBUG] All modules loaded successfully");
|
|
@@ -130,6 +130,9 @@ export async function executeToolByName(name, args) {
|
|
|
130
130
|
case TOOL_NAMES.RANDOM_SCROLL:
|
|
131
131
|
result = await handleRandomScroll();
|
|
132
132
|
break;
|
|
133
|
+
case TOOL_NAMES.PRESS_KEY:
|
|
134
|
+
result = await handlePressKey(args);
|
|
135
|
+
break;
|
|
133
136
|
case TOOL_NAMES.FIND_SELECTOR:
|
|
134
137
|
result = await handleFindSelector(args);
|
|
135
138
|
break;
|
|
@@ -210,35 +213,14 @@ export async function executeToolByName(name, args) {
|
|
|
210
213
|
result = await handleVideoRecording(args);
|
|
211
214
|
break;
|
|
212
215
|
// Smart Data Extractors (Advanced)
|
|
213
|
-
case "html_elements_extractor":
|
|
214
|
-
result = await handleHtmlElementsExtractor(args || {});
|
|
215
|
-
break;
|
|
216
|
-
case "tags_finder":
|
|
217
|
-
result = await handleTagsFinder(args || {});
|
|
218
|
-
break;
|
|
219
|
-
case "links_finder":
|
|
220
|
-
result = await handleLinksFinder(args || {});
|
|
221
|
-
break;
|
|
222
|
-
case "xpath_links":
|
|
223
|
-
result = await handleXpathLinks(args || {});
|
|
224
|
-
break;
|
|
225
|
-
case "ajax_extractor":
|
|
226
|
-
result = await handleAjaxExtractor(args || {});
|
|
227
|
-
break;
|
|
228
216
|
case "fetch_xhr":
|
|
229
217
|
result = await handleFetchXHR(args || {});
|
|
230
218
|
break;
|
|
231
219
|
case "network_recorder":
|
|
232
220
|
result = await handleNetworkRecorder(args || {});
|
|
233
221
|
break;
|
|
234
|
-
case "
|
|
235
|
-
result = await
|
|
236
|
-
break;
|
|
237
|
-
case "iframe_extractor":
|
|
238
|
-
result = await handleIframeExtractor(args || {});
|
|
239
|
-
break;
|
|
240
|
-
case "embed_page_extractor":
|
|
241
|
-
result = await handleEmbedPageExtractor(args || {});
|
|
222
|
+
case "api_finder":
|
|
223
|
+
result = await handleApiFinder(args || {});
|
|
242
224
|
break;
|
|
243
225
|
case "image_extractor_advanced":
|
|
244
226
|
result = await handleImageExtractorAdvanced(args || {});
|
|
@@ -249,16 +231,7 @@ export async function executeToolByName(name, args) {
|
|
|
249
231
|
case "url_redirect_tracer":
|
|
250
232
|
result = await handleUrlRedirectTracer(args);
|
|
251
233
|
break;
|
|
252
|
-
case "user_agent_extractor":
|
|
253
|
-
result = await handleUserAgentExtractor(args || {});
|
|
254
|
-
break;
|
|
255
234
|
// Dynamic Content & Session Handling
|
|
256
|
-
case "shadow_dom_extractor":
|
|
257
|
-
result = await handleShadowDOMExtractor(args || {});
|
|
258
|
-
break;
|
|
259
|
-
case "form_auto_fill":
|
|
260
|
-
result = await handleFormAutoFill(args);
|
|
261
|
-
break;
|
|
262
235
|
case "ajax_content_waiter":
|
|
263
236
|
result = await handleAjaxContentWaiter(args);
|
|
264
237
|
break;
|
|
@@ -267,17 +240,14 @@ export async function executeToolByName(name, args) {
|
|
|
267
240
|
result = await handleProgressTracker(args || {});
|
|
268
241
|
break;
|
|
269
242
|
// Advanced Video & Media Download Tools
|
|
270
|
-
case "
|
|
271
|
-
result = await
|
|
272
|
-
break;
|
|
273
|
-
case "video_download_button":
|
|
274
|
-
result = await handleVideoDownloadButton(args);
|
|
243
|
+
case "video_player_finder":
|
|
244
|
+
result = await handleVideoPlayerFinder(args || {});
|
|
275
245
|
break;
|
|
276
|
-
case "
|
|
277
|
-
result = await
|
|
246
|
+
case "stream_detector":
|
|
247
|
+
result = await handleStreamDetector(args || {});
|
|
278
248
|
break;
|
|
279
|
-
case "
|
|
280
|
-
result = await
|
|
249
|
+
case "video_download_link_finder":
|
|
250
|
+
result = await handleVideoDownloadLinkFinder(args || {});
|
|
281
251
|
break;
|
|
282
252
|
// Advanced Extraction Tools (Ad-Bypass & Obfuscation)
|
|
283
253
|
case "advanced_video_extraction":
|
package/dist/tool-definitions.js
CHANGED
|
@@ -32,7 +32,11 @@ export const TOOLS = [
|
|
|
32
32
|
headless: {
|
|
33
33
|
type: 'boolean',
|
|
34
34
|
description: 'Run browser in headless mode',
|
|
35
|
-
|
|
35
|
+
},
|
|
36
|
+
autoInstall: {
|
|
37
|
+
type: 'boolean',
|
|
38
|
+
description: 'Automatically install Brave Browser if not found (Default: true)',
|
|
39
|
+
default: true,
|
|
36
40
|
},
|
|
37
41
|
disableXvfb: {
|
|
38
42
|
type: 'boolean',
|
|
@@ -599,60 +603,6 @@ export const TOOLS = [
|
|
|
599
603
|
},
|
|
600
604
|
},
|
|
601
605
|
// Smart Data Extractors (Advanced)
|
|
602
|
-
{
|
|
603
|
-
name: 'html_elements_extractor',
|
|
604
|
-
description: 'Extract all HTML elements with complete details',
|
|
605
|
-
inputSchema: {
|
|
606
|
-
type: 'object',
|
|
607
|
-
properties: {
|
|
608
|
-
selector: { type: 'string', default: '*' },
|
|
609
|
-
maxElements: { type: 'number', default: 100 },
|
|
610
|
-
includeStyles: { type: 'boolean', default: false },
|
|
611
|
-
},
|
|
612
|
-
},
|
|
613
|
-
},
|
|
614
|
-
{
|
|
615
|
-
name: 'tags_finder',
|
|
616
|
-
description: 'Find specific HTML tags',
|
|
617
|
-
inputSchema: {
|
|
618
|
-
type: 'object',
|
|
619
|
-
properties: {
|
|
620
|
-
tags: { type: 'array', items: { type: 'string' }, default: ['div', 'span', 'p', 'a', 'img'] },
|
|
621
|
-
},
|
|
622
|
-
},
|
|
623
|
-
},
|
|
624
|
-
{
|
|
625
|
-
name: 'links_finder',
|
|
626
|
-
description: 'Extract all links from page',
|
|
627
|
-
inputSchema: {
|
|
628
|
-
type: 'object',
|
|
629
|
-
properties: {
|
|
630
|
-
includeExternal: { type: 'boolean', default: true },
|
|
631
|
-
maxLinks: { type: 'number', default: 200 },
|
|
632
|
-
},
|
|
633
|
-
},
|
|
634
|
-
},
|
|
635
|
-
{
|
|
636
|
-
name: 'xpath_links',
|
|
637
|
-
description: 'Use XPath to find links',
|
|
638
|
-
inputSchema: {
|
|
639
|
-
type: 'object',
|
|
640
|
-
properties: {
|
|
641
|
-
xpath: { type: 'string', default: '//a[@href]' },
|
|
642
|
-
},
|
|
643
|
-
},
|
|
644
|
-
},
|
|
645
|
-
{
|
|
646
|
-
name: 'ajax_extractor',
|
|
647
|
-
description: 'Extract AJAX/XHR request data',
|
|
648
|
-
inputSchema: {
|
|
649
|
-
type: 'object',
|
|
650
|
-
properties: {
|
|
651
|
-
duration: { type: 'number', default: 15000 },
|
|
652
|
-
url: { type: 'string' },
|
|
653
|
-
},
|
|
654
|
-
},
|
|
655
|
-
},
|
|
656
606
|
{
|
|
657
607
|
name: 'fetch_xhr',
|
|
658
608
|
description: 'Capture fetch and XHR requests with responses',
|
|
@@ -684,34 +634,6 @@ export const TOOLS = [
|
|
|
684
634
|
},
|
|
685
635
|
},
|
|
686
636
|
},
|
|
687
|
-
{
|
|
688
|
-
name: 'regex_pattern_finder',
|
|
689
|
-
description: 'Find patterns using regex',
|
|
690
|
-
inputSchema: {
|
|
691
|
-
type: 'object',
|
|
692
|
-
properties: {
|
|
693
|
-
pattern: { type: 'string' },
|
|
694
|
-
flags: { type: 'string', default: 'gi' },
|
|
695
|
-
},
|
|
696
|
-
required: ['pattern'],
|
|
697
|
-
},
|
|
698
|
-
},
|
|
699
|
-
{
|
|
700
|
-
name: 'iframe_extractor',
|
|
701
|
-
description: 'Extract all iframes and their content',
|
|
702
|
-
inputSchema: {
|
|
703
|
-
type: 'object',
|
|
704
|
-
properties: {},
|
|
705
|
-
},
|
|
706
|
-
},
|
|
707
|
-
{
|
|
708
|
-
name: 'embed_page_extractor',
|
|
709
|
-
description: 'Extract embedded content (iframes, objects, embeds)',
|
|
710
|
-
inputSchema: {
|
|
711
|
-
type: 'object',
|
|
712
|
-
properties: {},
|
|
713
|
-
},
|
|
714
|
-
},
|
|
715
637
|
{
|
|
716
638
|
name: 'image_extractor_advanced',
|
|
717
639
|
description: 'Advanced image extraction with metadata',
|
|
@@ -733,37 +655,7 @@ export const TOOLS = [
|
|
|
733
655
|
required: ['url'],
|
|
734
656
|
},
|
|
735
657
|
},
|
|
736
|
-
{
|
|
737
|
-
name: 'user_agent_extractor',
|
|
738
|
-
description: 'Extract user agent information',
|
|
739
|
-
inputSchema: {
|
|
740
|
-
type: 'object',
|
|
741
|
-
properties: {},
|
|
742
|
-
},
|
|
743
|
-
},
|
|
744
658
|
// Dynamic Content & Session Handling
|
|
745
|
-
{
|
|
746
|
-
name: 'shadow_dom_extractor',
|
|
747
|
-
description: 'Extract content from Shadow DOM',
|
|
748
|
-
inputSchema: {
|
|
749
|
-
type: 'object',
|
|
750
|
-
properties: {
|
|
751
|
-
selector: { type: 'string', default: '*' },
|
|
752
|
-
},
|
|
753
|
-
},
|
|
754
|
-
},
|
|
755
|
-
{
|
|
756
|
-
name: 'form_auto_fill',
|
|
757
|
-
description: 'Automatically fill form fields',
|
|
758
|
-
inputSchema: {
|
|
759
|
-
type: 'object',
|
|
760
|
-
properties: {
|
|
761
|
-
formData: { type: 'object' },
|
|
762
|
-
submitAfterFill: { type: 'boolean', default: false },
|
|
763
|
-
submitButtonSelector: { type: 'string' },
|
|
764
|
-
},
|
|
765
|
-
},
|
|
766
|
-
},
|
|
767
659
|
{
|
|
768
660
|
name: 'ajax_content_waiter',
|
|
769
661
|
description: 'Wait for dynamic content to load',
|
|
@@ -793,45 +685,6 @@ export const TOOLS = [
|
|
|
793
685
|
},
|
|
794
686
|
},
|
|
795
687
|
// Advanced Video & Media Download Tools
|
|
796
|
-
{
|
|
797
|
-
name: 'video_link_finder',
|
|
798
|
-
description: 'Find all video links on page',
|
|
799
|
-
inputSchema: {
|
|
800
|
-
type: 'object',
|
|
801
|
-
properties: {
|
|
802
|
-
includeEmbedded: { type: 'boolean', default: true },
|
|
803
|
-
},
|
|
804
|
-
},
|
|
805
|
-
},
|
|
806
|
-
{
|
|
807
|
-
name: 'video_download_button',
|
|
808
|
-
description: 'Find and interact with video download buttons',
|
|
809
|
-
inputSchema: {
|
|
810
|
-
type: 'object',
|
|
811
|
-
properties: {
|
|
812
|
-
action: { type: 'string', enum: ['find', 'click'], default: 'find' },
|
|
813
|
-
selector: { type: 'string' },
|
|
814
|
-
},
|
|
815
|
-
},
|
|
816
|
-
},
|
|
817
|
-
{
|
|
818
|
-
name: 'video_play_push_source',
|
|
819
|
-
description: 'Capture video sources when play button is clicked',
|
|
820
|
-
inputSchema: {
|
|
821
|
-
type: 'object',
|
|
822
|
-
properties: {},
|
|
823
|
-
},
|
|
824
|
-
},
|
|
825
|
-
{
|
|
826
|
-
name: 'video_play_button_click',
|
|
827
|
-
description: 'Click video play button',
|
|
828
|
-
inputSchema: {
|
|
829
|
-
type: 'object',
|
|
830
|
-
properties: {
|
|
831
|
-
selector: { type: 'string' },
|
|
832
|
-
},
|
|
833
|
-
},
|
|
834
|
-
},
|
|
835
688
|
// Advanced Extraction Tools (Ad-Bypass & Obfuscation)
|
|
836
689
|
{
|
|
837
690
|
name: 'advanced_video_extraction',
|
|
@@ -953,15 +806,7 @@ export const TOOL_NAMES = {
|
|
|
953
806
|
LINK_HARVESTER: 'link_harvester',
|
|
954
807
|
MEDIA_EXTRACTOR: 'media_extractor',
|
|
955
808
|
// DOM & HTML Extraction (Phase 1)
|
|
956
|
-
HTML_ELEMENTS_EXTRACTOR: 'html_elements_extractor',
|
|
957
|
-
TAGS_FINDER: 'tags_finder',
|
|
958
|
-
LINKS_FINDER: 'links_finder',
|
|
959
|
-
XPATH_LINKS: 'xpath_links',
|
|
960
|
-
SHADOW_DOM_EXTRACTOR: 'shadow_dom_extractor',
|
|
961
|
-
IFRAME_EXTRACTOR: 'iframe_extractor',
|
|
962
|
-
EMBED_PAGE_EXTRACTOR: 'embed_page_extractor',
|
|
963
809
|
// Network Tools (Phase 1)
|
|
964
|
-
AJAX_EXTRACTOR: 'ajax_extractor',
|
|
965
810
|
FETCH_XHR: 'fetch_xhr',
|
|
966
811
|
NETWORK_RECORDER: 'network_recorder',
|
|
967
812
|
API_FINDER: 'api_finder',
|
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.7",
|
|
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",
|