brave-real-browser-mcp-server 2.27.6 → 2.27.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/handlers/interaction-handlers.js +0 -161
- package/dist/index.js +1 -3
- package/dist/tool-definitions.js +0 -46
- package/package.json +2 -2
|
@@ -126,167 +126,6 @@ export async function handleClick(args) {
|
|
|
126
126
|
}, 'Failed to click element');
|
|
127
127
|
});
|
|
128
128
|
}
|
|
129
|
-
export async function handleSelect(args) {
|
|
130
|
-
const progressNotifier = getProgressNotifier();
|
|
131
|
-
const progressToken = `select-${Date.now()}`;
|
|
132
|
-
const tracker = progressNotifier.createTracker(progressToken);
|
|
133
|
-
return await withWorkflowValidation('select', args, async () => {
|
|
134
|
-
return await withErrorHandling(async () => {
|
|
135
|
-
tracker.start(100, '📋 Starting select operation...');
|
|
136
|
-
const pageInstance = getPageInstance();
|
|
137
|
-
if (!pageInstance) {
|
|
138
|
-
tracker.fail('Browser not initialized');
|
|
139
|
-
throw new Error('Browser not initialized. Call browser_init first.');
|
|
140
|
-
}
|
|
141
|
-
const { selector, value, text, index, searchText, waitForOptions = true, clickToOpen = false, optionSelector } = args;
|
|
142
|
-
tracker.setProgress(10, `🔍 Finding select element: ${selector}`);
|
|
143
|
-
// Find the select/dropdown element
|
|
144
|
-
const elementResult = await selfHealingLocators.findElementWithFallbacks(pageInstance, selector);
|
|
145
|
-
if (!elementResult) {
|
|
146
|
-
tracker.fail('Select element not found');
|
|
147
|
-
throw new Error(`Select element not found: ${selector}`);
|
|
148
|
-
}
|
|
149
|
-
const { element, usedSelector } = elementResult;
|
|
150
|
-
tracker.setProgress(25, '✅ Select element found, detecting type...');
|
|
151
|
-
// Detect select type: native <select> or custom dropdown
|
|
152
|
-
const selectType = await pageInstance.evaluate((sel) => {
|
|
153
|
-
const el = document.querySelector(sel);
|
|
154
|
-
if (!el)
|
|
155
|
-
return 'not-found';
|
|
156
|
-
if (el.tagName.toLowerCase() === 'select')
|
|
157
|
-
return 'native';
|
|
158
|
-
if (el.getAttribute('role') === 'listbox' || el.getAttribute('role') === 'combobox')
|
|
159
|
-
return 'aria';
|
|
160
|
-
if (el.classList.toString().match(/select|dropdown|combo/i))
|
|
161
|
-
return 'custom';
|
|
162
|
-
return 'custom';
|
|
163
|
-
}, usedSelector);
|
|
164
|
-
tracker.setProgress(35, `🎯 Detected type: ${selectType}`);
|
|
165
|
-
// Handle native <select> elements
|
|
166
|
-
if (selectType === 'native') {
|
|
167
|
-
tracker.setProgress(50, '📋 Handling native <select> element...');
|
|
168
|
-
let selectResult = [];
|
|
169
|
-
if (value !== undefined) {
|
|
170
|
-
selectResult = await pageInstance.select(usedSelector, value);
|
|
171
|
-
}
|
|
172
|
-
else if (text !== undefined) {
|
|
173
|
-
// Select by visible text
|
|
174
|
-
const optionValue = await pageInstance.evaluate((sel, targetText) => {
|
|
175
|
-
const select = document.querySelector(sel);
|
|
176
|
-
if (!select)
|
|
177
|
-
return null;
|
|
178
|
-
const option = Array.from(select.options).find(o => o.text.trim() === targetText.trim() ||
|
|
179
|
-
o.text.toLowerCase().includes(targetText.toLowerCase()));
|
|
180
|
-
return option?.value || null;
|
|
181
|
-
}, usedSelector, text);
|
|
182
|
-
if (optionValue) {
|
|
183
|
-
selectResult = await pageInstance.select(usedSelector, optionValue);
|
|
184
|
-
}
|
|
185
|
-
else {
|
|
186
|
-
throw new Error(`Option with text "${text}" not found`);
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
else if (index !== undefined) {
|
|
190
|
-
// Select by index
|
|
191
|
-
const optionValue = await pageInstance.evaluate((sel, idx) => {
|
|
192
|
-
const select = document.querySelector(sel);
|
|
193
|
-
return select?.options[idx]?.value || null;
|
|
194
|
-
}, usedSelector, index);
|
|
195
|
-
if (optionValue) {
|
|
196
|
-
selectResult = await pageInstance.select(usedSelector, optionValue);
|
|
197
|
-
}
|
|
198
|
-
else {
|
|
199
|
-
throw new Error(`Option at index ${index} not found`);
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
tracker.complete('🎉 Native select completed successfully');
|
|
203
|
-
return {
|
|
204
|
-
content: [{
|
|
205
|
-
type: 'text',
|
|
206
|
-
text: `✅ Selected value in native dropdown: ${selector}\nSelected: ${selectResult.join(', ') || 'success'}`,
|
|
207
|
-
}],
|
|
208
|
-
};
|
|
209
|
-
}
|
|
210
|
-
// Handle custom dropdowns (React, Vue, etc.)
|
|
211
|
-
tracker.setProgress(50, '📋 Handling custom dropdown...');
|
|
212
|
-
// Click to open if needed
|
|
213
|
-
if (clickToOpen) {
|
|
214
|
-
tracker.setProgress(55, '🖱️ Opening dropdown...');
|
|
215
|
-
await element.click();
|
|
216
|
-
await sleep(300); // Wait for animation
|
|
217
|
-
}
|
|
218
|
-
// Wait for options to load (AJAX dropdowns)
|
|
219
|
-
if (waitForOptions) {
|
|
220
|
-
tracker.setProgress(60, '⏳ Waiting for options to load...');
|
|
221
|
-
await sleep(500);
|
|
222
|
-
}
|
|
223
|
-
// Handle searchable dropdowns
|
|
224
|
-
if (searchText) {
|
|
225
|
-
tracker.setProgress(65, `🔍 Searching: ${searchText}...`);
|
|
226
|
-
// Type search text into the input
|
|
227
|
-
await element.type(searchText, { delay: 50 });
|
|
228
|
-
await sleep(500); // Wait for search results
|
|
229
|
-
}
|
|
230
|
-
// Find and click the option
|
|
231
|
-
tracker.setProgress(75, '🎯 Selecting option...');
|
|
232
|
-
const finalOptionSelector = optionSelector ||
|
|
233
|
-
'[role="option"],' +
|
|
234
|
-
' [class*="option"]:not([class*="disabled"]),' +
|
|
235
|
-
' li[data-value],' +
|
|
236
|
-
' li:not(.disabled),' +
|
|
237
|
-
' .dropdown-item';
|
|
238
|
-
const targetValue = value || text;
|
|
239
|
-
const optionClicked = await pageInstance.evaluate((optSel, targetVal, targetIndex) => {
|
|
240
|
-
const options = Array.from(document.querySelectorAll(optSel));
|
|
241
|
-
if (targetVal !== undefined) {
|
|
242
|
-
// Find by value or text
|
|
243
|
-
const option = options.find(opt => opt.getAttribute('value') === targetVal ||
|
|
244
|
-
opt.textContent?.trim() === targetVal ||
|
|
245
|
-
opt.textContent?.toLowerCase().includes(targetVal.toLowerCase()));
|
|
246
|
-
if (option) {
|
|
247
|
-
option.click();
|
|
248
|
-
return true;
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
else if (targetIndex !== undefined && options[targetIndex]) {
|
|
252
|
-
options[targetIndex].click();
|
|
253
|
-
return true;
|
|
254
|
-
}
|
|
255
|
-
return false;
|
|
256
|
-
}, finalOptionSelector, targetValue, index);
|
|
257
|
-
if (!optionClicked) {
|
|
258
|
-
// Fallback: try clicking by text content
|
|
259
|
-
const textToFind = text || value || searchText;
|
|
260
|
-
if (textToFind) {
|
|
261
|
-
const clicked = await pageInstance.evaluate((searchText) => {
|
|
262
|
-
const allElements = Array.from(document.querySelectorAll('*'));
|
|
263
|
-
for (const el of allElements) {
|
|
264
|
-
if (el.textContent?.trim() === searchText ||
|
|
265
|
-
el.textContent?.toLowerCase().includes(searchText.toLowerCase())) {
|
|
266
|
-
const style = window.getComputedStyle(el);
|
|
267
|
-
if (style.display !== 'none' && style.visibility !== 'hidden') {
|
|
268
|
-
el.click();
|
|
269
|
-
return true;
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
return false;
|
|
274
|
-
}, textToFind);
|
|
275
|
-
if (!clicked) {
|
|
276
|
-
throw new Error(`Could not find or click option: ${textToFind}`);
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
tracker.complete('🎉 Custom dropdown selection completed');
|
|
281
|
-
return {
|
|
282
|
-
content: [{
|
|
283
|
-
type: 'text',
|
|
284
|
-
text: `✅ Selected option in custom dropdown: ${selector}\nType: ${selectType}\nTarget: ${value || text || `index:${index}`}`,
|
|
285
|
-
}],
|
|
286
|
-
};
|
|
287
|
-
}, 'Failed to select option');
|
|
288
|
-
});
|
|
289
|
-
}
|
|
290
129
|
// Type handler with real-time progress
|
|
291
130
|
export async function handleType(args) {
|
|
292
131
|
const progressNotifier = getProgressNotifier();
|
package/dist/index.js
CHANGED
|
@@ -53,7 +53,7 @@ import { setupProcessCleanup } from './core-infrastructure.js';
|
|
|
53
53
|
debug('Loading handlers...');
|
|
54
54
|
import { handleBrowserInit, handleBrowserClose } from './handlers/browser-handlers.js';
|
|
55
55
|
import { handleNavigate, handleWait } from './handlers/navigation-handlers.js';
|
|
56
|
-
import { handleClick,
|
|
56
|
+
import { handleClick, handleType, handleSolveCaptcha, handleRandomScroll } from './handlers/interaction-handlers.js';
|
|
57
57
|
import { handleGetContent, handleFindSelector } from './handlers/content-handlers.js';
|
|
58
58
|
import { handleSaveContentAsMarkdown } from './handlers/file-handlers.js';
|
|
59
59
|
// Import advanced tools handlers
|
|
@@ -159,8 +159,6 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
159
159
|
return await handleGetContent(args || {});
|
|
160
160
|
case TOOL_NAMES.CLICK:
|
|
161
161
|
return await handleClick(args);
|
|
162
|
-
case TOOL_NAMES.DROPDOWN_SELECT:
|
|
163
|
-
return await handleSelect(args);
|
|
164
162
|
case TOOL_NAMES.TYPE:
|
|
165
163
|
return await handleType(args);
|
|
166
164
|
case TOOL_NAMES.WAIT:
|
package/dist/tool-definitions.js
CHANGED
|
@@ -259,51 +259,6 @@ export const TOOLS = [
|
|
|
259
259
|
required: ['type', 'value'],
|
|
260
260
|
},
|
|
261
261
|
},
|
|
262
|
-
{
|
|
263
|
-
name: 'dropdown_select',
|
|
264
|
-
description: 'Intelligent dropdown/select element handler. Supports native HTML select, custom dropdowns, autocomplete, and searchable selects with smart fallback strategies.',
|
|
265
|
-
inputSchema: {
|
|
266
|
-
type: 'object',
|
|
267
|
-
additionalProperties: false,
|
|
268
|
-
properties: {
|
|
269
|
-
selector: {
|
|
270
|
-
type: 'string',
|
|
271
|
-
description: 'CSS selector for the select/dropdown element',
|
|
272
|
-
},
|
|
273
|
-
value: {
|
|
274
|
-
type: 'string',
|
|
275
|
-
description: 'Value to select (option value attribute)',
|
|
276
|
-
},
|
|
277
|
-
text: {
|
|
278
|
-
type: 'string',
|
|
279
|
-
description: 'Visible text of option to select (alternative to value)',
|
|
280
|
-
},
|
|
281
|
-
index: {
|
|
282
|
-
type: 'number',
|
|
283
|
-
description: 'Index of option to select (0-based, alternative to value/text)',
|
|
284
|
-
},
|
|
285
|
-
searchText: {
|
|
286
|
-
type: 'string',
|
|
287
|
-
description: 'For searchable dropdowns: text to type before selecting',
|
|
288
|
-
},
|
|
289
|
-
waitForOptions: {
|
|
290
|
-
type: 'boolean',
|
|
291
|
-
description: 'Wait for dropdown options to load (useful for AJAX dropdowns)',
|
|
292
|
-
default: true,
|
|
293
|
-
},
|
|
294
|
-
clickToOpen: {
|
|
295
|
-
type: 'boolean',
|
|
296
|
-
description: 'Click to open dropdown before selecting (for custom dropdowns)',
|
|
297
|
-
default: false,
|
|
298
|
-
},
|
|
299
|
-
optionSelector: {
|
|
300
|
-
type: 'string',
|
|
301
|
-
description: 'CSS selector for dropdown options (for custom dropdowns)',
|
|
302
|
-
},
|
|
303
|
-
},
|
|
304
|
-
required: ['selector'],
|
|
305
|
-
},
|
|
306
|
-
},
|
|
307
262
|
{
|
|
308
263
|
name: 'click',
|
|
309
264
|
description: 'Click on an element',
|
|
@@ -787,7 +742,6 @@ export const TOOL_NAMES = {
|
|
|
787
742
|
NAVIGATE: 'navigate',
|
|
788
743
|
GET_CONTENT: 'get_content',
|
|
789
744
|
CLICK: 'click',
|
|
790
|
-
DROPDOWN_SELECT: 'dropdown_select',
|
|
791
745
|
TYPE: 'type',
|
|
792
746
|
WAIT: 'wait',
|
|
793
747
|
BROWSER_CLOSE: 'browser_close',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "brave-real-browser-mcp-server",
|
|
3
|
-
"version": "2.27.
|
|
3
|
+
"version": "2.27.7",
|
|
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.8.
|
|
53
|
+
"brave-real-browser": "^2.8.7",
|
|
54
54
|
"puppeteer-core": "^24.35.0",
|
|
55
55
|
"turndown": "latest",
|
|
56
56
|
"vscode-languageserver": "^9.0.1",
|