brave-real-browser-mcp-server 2.23.7 ā 2.23.9
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.
|
@@ -44,15 +44,31 @@ export async function handleClick(args) {
|
|
|
44
44
|
strategyMessage = `\nš Self-healing: Used ${strategy} fallback selector: ${usedSelector}`;
|
|
45
45
|
tracker.setProgress(50, `š Using fallback selector: ${usedSelector}`);
|
|
46
46
|
}
|
|
47
|
+
// Text-based strategies have special __TEXT__: prefix or are strategy-identified
|
|
48
|
+
// These have invalid CSS selectors, so we skip waitForSelector and use element directly
|
|
49
|
+
const isTextBasedStrategy = ['text-content', 'implicit-text-match', 'text', 'text-exact', 'text-partial', 'tag-text'].includes(strategy) ||
|
|
50
|
+
usedSelector.startsWith('__TEXT__:');
|
|
51
|
+
// Clean display selector for output (remove __TEXT__: prefix)
|
|
52
|
+
const displaySelector = usedSelector.startsWith('__TEXT__:')
|
|
53
|
+
? usedSelector.replace('__TEXT__:', 'text:')
|
|
54
|
+
: usedSelector;
|
|
47
55
|
try {
|
|
48
56
|
tracker.setProgress(60, 'ā³ Waiting for element to be ready...');
|
|
49
|
-
//
|
|
50
|
-
|
|
57
|
+
// Only wait for selector if it's a valid CSS selector (not text-based)
|
|
58
|
+
if (!isTextBasedStrategy) {
|
|
59
|
+
await pageInstance.waitForSelector(usedSelector, { timeout: 5000 });
|
|
60
|
+
}
|
|
51
61
|
// Check element visibility and interaction options
|
|
52
62
|
const boundingBox = await element.boundingBox();
|
|
53
63
|
if (!boundingBox) {
|
|
54
64
|
tracker.setProgress(70, 'š§ No bounding box, using JavaScript click...');
|
|
55
|
-
|
|
65
|
+
// For text-based strategies, use element.evaluate to click
|
|
66
|
+
if (isTextBasedStrategy) {
|
|
67
|
+
await element.evaluate((el) => el.click());
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
await pageInstance.$eval(usedSelector, (el) => el.click());
|
|
71
|
+
}
|
|
56
72
|
}
|
|
57
73
|
else {
|
|
58
74
|
tracker.setProgress(70, 'š±ļø Clicking element...');
|
|
@@ -60,12 +76,13 @@ export async function handleClick(args) {
|
|
|
60
76
|
tracker.setProgress(75, 'š Clicking and waiting for navigation...');
|
|
61
77
|
await Promise.all([
|
|
62
78
|
pageInstance.waitForNavigation({ waitUntil: 'networkidle2' }),
|
|
63
|
-
|
|
79
|
+
element.click(), // Use element.click() for all strategies
|
|
64
80
|
]);
|
|
65
81
|
tracker.setProgress(90, 'ā
Navigation completed');
|
|
66
82
|
}
|
|
67
83
|
else {
|
|
68
|
-
|
|
84
|
+
// Use element.click() directly - works for all strategies
|
|
85
|
+
await element.click();
|
|
69
86
|
}
|
|
70
87
|
}
|
|
71
88
|
tracker.complete('š Click completed successfully');
|
|
@@ -82,7 +99,13 @@ export async function handleClick(args) {
|
|
|
82
99
|
tracker.setProgress(85, 'ā ļø Click failed, trying JavaScript fallback...');
|
|
83
100
|
// Final fallback: JavaScript click
|
|
84
101
|
try {
|
|
85
|
-
|
|
102
|
+
// For text-based strategies, use element.evaluate instead of $eval
|
|
103
|
+
if (isTextBasedStrategy) {
|
|
104
|
+
await element.evaluate((el) => el.click());
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
await pageInstance.$eval(usedSelector, (el) => el.click());
|
|
108
|
+
}
|
|
86
109
|
tracker.complete('š Click completed via JavaScript fallback');
|
|
87
110
|
return {
|
|
88
111
|
content: [
|
package/dist/index.js
CHANGED
|
@@ -63,7 +63,7 @@ handleM3u8Parser, handleCookieManager,
|
|
|
63
63
|
// Download tools
|
|
64
64
|
handleFileDownloader,
|
|
65
65
|
// Enhanced streaming/download tools
|
|
66
|
-
handleIframeHandler,
|
|
66
|
+
handleIframeHandler, handleStreamExtractor, } from './handlers/advanced-tools.js';
|
|
67
67
|
// State for video recording
|
|
68
68
|
const recorderState = new Map();
|
|
69
69
|
debug('All modules loaded successfully');
|
|
@@ -259,10 +259,6 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
259
259
|
if (!page)
|
|
260
260
|
throw new Error('Browser not initialized. Call browser_init first.');
|
|
261
261
|
return { content: [{ type: 'text', text: JSON.stringify(await handleIframeHandler(page, args)) }] };
|
|
262
|
-
case TOOL_NAMES.POPUP_HANDLER:
|
|
263
|
-
if (!page)
|
|
264
|
-
throw new Error('Browser not initialized. Call browser_init first.');
|
|
265
|
-
return { content: [{ type: 'text', text: JSON.stringify(await handlePopupHandler(page, args)) }] };
|
|
266
262
|
case TOOL_NAMES.STREAM_EXTRACTOR:
|
|
267
263
|
if (!page)
|
|
268
264
|
throw new Error('Browser not initialized. Call browser_init first.');
|
|
@@ -323,15 +323,6 @@ const TOOL_DEFINITIONS = {
|
|
|
323
323
|
{ name: 'selector', type: 'string', description: 'CSS selector of target iframe', required: false },
|
|
324
324
|
],
|
|
325
325
|
},
|
|
326
|
-
popup_handler: {
|
|
327
|
-
name: 'popup_handler',
|
|
328
|
-
description: 'Handle popups, new tabs, and ad overlays during navigation',
|
|
329
|
-
category: 'Advanced',
|
|
330
|
-
parameters: [
|
|
331
|
-
{ name: 'action', type: 'string', description: 'Popup handling action', required: false, enum: ['block', 'allow', 'close', 'switch', 'list', 'closeAll'] },
|
|
332
|
-
{ name: 'autoCloseAds', type: 'boolean', description: 'Automatically close detected ad popups', required: false, default: true },
|
|
333
|
-
],
|
|
334
|
-
},
|
|
335
326
|
};
|
|
336
327
|
// ============================================================
|
|
337
328
|
// LSP SERVER
|
|
@@ -145,7 +145,7 @@ export class SelfHealingLocators {
|
|
|
145
145
|
if (element) {
|
|
146
146
|
return {
|
|
147
147
|
element,
|
|
148
|
-
usedSelector:
|
|
148
|
+
usedSelector: `__TEXT__:${textSelector.tagName || '*'}:${textSelector.text}`,
|
|
149
149
|
strategy: 'text-content'
|
|
150
150
|
};
|
|
151
151
|
}
|
|
@@ -171,7 +171,7 @@ export class SelfHealingLocators {
|
|
|
171
171
|
if (textElement) {
|
|
172
172
|
return {
|
|
173
173
|
element: textElement,
|
|
174
|
-
usedSelector:
|
|
174
|
+
usedSelector: `__TEXT__:*:${primarySelector}`,
|
|
175
175
|
strategy: 'implicit-text-match'
|
|
176
176
|
};
|
|
177
177
|
}
|
package/dist/tool-definitions.js
CHANGED
|
@@ -626,21 +626,6 @@ export const TOOLS = [
|
|
|
626
626
|
},
|
|
627
627
|
},
|
|
628
628
|
},
|
|
629
|
-
{
|
|
630
|
-
name: 'popup_handler',
|
|
631
|
-
description: 'Handle popups, new tabs, and ad overlays during navigation',
|
|
632
|
-
inputSchema: {
|
|
633
|
-
type: 'object',
|
|
634
|
-
additionalProperties: false,
|
|
635
|
-
properties: {
|
|
636
|
-
action: { type: 'string', enum: ['block', 'allow', 'close', 'switch', 'list', 'closeAll'], description: 'Popup handling action' },
|
|
637
|
-
autoCloseAds: { type: 'boolean', description: 'Automatically close detected ad popups', default: true },
|
|
638
|
-
waitForTarget: { type: 'boolean', description: 'Wait for new tab/popup to open', default: false },
|
|
639
|
-
targetIndex: { type: 'number', description: 'Index of tab to switch to' },
|
|
640
|
-
timeout: { type: 'number', description: 'Timeout for waiting operations in ms', default: 10000 },
|
|
641
|
-
},
|
|
642
|
-
},
|
|
643
|
-
},
|
|
644
629
|
{
|
|
645
630
|
name: 'stream_extractor',
|
|
646
631
|
description: 'Master tool: Extract direct download/stream URLs from any page with automatic redirect following, countdown waiting, and format detection',
|
|
@@ -698,7 +683,6 @@ export const TOOL_NAMES = {
|
|
|
698
683
|
FILE_DOWNLOADER: 'file_downloader',
|
|
699
684
|
// Enhanced tools
|
|
700
685
|
IFRAME_HANDLER: 'iframe_handler',
|
|
701
|
-
POPUP_HANDLER: 'popup_handler',
|
|
702
686
|
STREAM_EXTRACTOR: 'stream_extractor',
|
|
703
687
|
};
|
|
704
688
|
// Tool categories for organization
|
package/dist/unified-server.js
CHANGED
|
@@ -536,7 +536,6 @@ async function main() {
|
|
|
536
536
|
console.error(' šŖ cookie_manager - Manage cookies');
|
|
537
537
|
console.error(' š„ file_downloader - Download files');
|
|
538
538
|
console.error(' š¼ļø iframe_handler - Handle iframes');
|
|
539
|
-
console.error(' š« popup_handler - Handle popups/ads');
|
|
540
539
|
console.error('');
|
|
541
540
|
console.error('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
|
|
542
541
|
console.error('');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "brave-real-browser-mcp-server",
|
|
3
|
-
"version": "2.23.
|
|
3
|
+
"version": "2.23.9",
|
|
4
4
|
"description": "š¦ MCP server for Brave Real Browser - NPM Workspaces Monorepo with anti-detection features, SSE streaming, and LSP compatibility",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"dependencies": {
|
|
51
51
|
"@modelcontextprotocol/sdk": "latest",
|
|
52
52
|
"@types/turndown": "latest",
|
|
53
|
-
"brave-real-browser": "^2.4.
|
|
53
|
+
"brave-real-browser": "^2.4.9",
|
|
54
54
|
"turndown": "latest",
|
|
55
55
|
"vscode-languageserver": "^9.0.1",
|
|
56
56
|
"vscode-languageserver-textdocument": "^1.0.12"
|