brave-real-browser-mcp-server 2.17.11 → 2.17.13

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.
@@ -1,264 +0,0 @@
1
- import { getPageInstance } from '../browser-manager.js';
2
- /**
3
- * Keyword Search - Advanced keyword search in page content
4
- */
5
- export async function handleKeywordSearch(args) {
6
- const { url, keywords, caseSensitive = false, wholeWord = false, context = 50 } = args;
7
- try {
8
- const page = getPageInstance();
9
- if (!page) {
10
- throw new Error('Browser not initialized. Call browser_init first.');
11
- }
12
- if (url && page.url() !== url) {
13
- await page.goto(url, { waitUntil: 'networkidle2', timeout: 30000 });
14
- }
15
- const results = await page.evaluate((kws, caseSens, whole, ctx) => {
16
- const allMatches = [];
17
- const keywordList = Array.isArray(kws) ? kws : [kws];
18
- keywordList.forEach(keyword => {
19
- const flags = caseSens ? 'g' : 'gi';
20
- const pattern = whole ? `\\b${keyword}\\b` : keyword;
21
- //const regex = new RegExp(pattern, flags);
22
- const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT, null);
23
- let node;
24
- while (node = walker.nextNode()) {
25
- const text = node.textContent || '';
26
- let match;
27
- const nodeRegex = new RegExp(pattern, flags);
28
- while ((match = nodeRegex.exec(text)) !== null) {
29
- const start = Math.max(0, match.index - ctx);
30
- const end = Math.min(text.length, match.index + match[0].length + ctx);
31
- const contextText = text.substring(start, end);
32
- // Get element info
33
- const element = node.parentElement;
34
- const tagName = element?.tagName.toLowerCase() || 'text';
35
- const className = element?.className || '';
36
- const id = element?.id || '';
37
- allMatches.push({
38
- keyword,
39
- match: match[0],
40
- position: match.index,
41
- context: contextText,
42
- element: {
43
- tag: tagName,
44
- class: className,
45
- id: id
46
- }
47
- });
48
- }
49
- }
50
- });
51
- // Group by keyword
52
- const grouped = {};
53
- allMatches.forEach(m => {
54
- if (!grouped[m.keyword])
55
- grouped[m.keyword] = [];
56
- grouped[m.keyword].push(m);
57
- });
58
- return {
59
- totalMatches: allMatches.length,
60
- matchesByKeyword: grouped,
61
- allMatches: allMatches.slice(0, 100) // Limit to first 100
62
- };
63
- }, Array.isArray(keywords) ? keywords : [keywords], caseSensitive, wholeWord, context);
64
- const resultText = `✅ Keyword Search Results\n\nTotal Matches: ${results.totalMatches}\n\nKeywords searched: ${Array.isArray(keywords) ? keywords.join(', ') : keywords}\n\nMatches by keyword:\n${JSON.stringify(results.matchesByKeyword, null, 2)}\n\nFirst 100 matches:\n${JSON.stringify(results.allMatches, null, 2)}`;
65
- return {
66
- content: [
67
- {
68
- type: 'text',
69
- text: resultText,
70
- },
71
- ],
72
- };
73
- }
74
- catch (error) {
75
- return {
76
- content: [{ type: 'text', text: `❌ Keyword search failed: ${error.message}` }],
77
- isError: true,
78
- };
79
- }
80
- }
81
- /**
82
- * Regex Pattern Matcher - Search using regular expressions
83
- */
84
- export async function handleRegexPatternMatcher(args) {
85
- const { url, pattern, flags = 'g', selector } = args;
86
- try {
87
- const page = getPageInstance();
88
- if (!page) {
89
- throw new Error('Browser not initialized. Call browser_init first.');
90
- }
91
- if (url && page.url() !== url) {
92
- await page.goto(url, { waitUntil: 'networkidle2', timeout: 30000 });
93
- }
94
- const results = await page.evaluate((pat, flgs, sel) => {
95
- let content;
96
- if (sel) {
97
- const element = document.querySelector(sel);
98
- content = element ? element.textContent || '' : '';
99
- }
100
- else {
101
- content = document.body.innerText;
102
- }
103
- const regex = new RegExp(pat, flgs);
104
- const matches = [];
105
- let match;
106
- // Safety check for infinite loop
107
- let count = 0;
108
- while ((match = regex.exec(content)) !== null && count < 1000) {
109
- count++;
110
- matches.push({
111
- match: match[0],
112
- index: match.index,
113
- groups: match.slice(1),
114
- context: content.substring(Math.max(0, match.index - 50), Math.min(content.length, match.index + match[0].length + 50))
115
- });
116
- if (match.index === regex.lastIndex) {
117
- regex.lastIndex++;
118
- }
119
- }
120
- return {
121
- totalMatches: matches.length,
122
- matches: matches.slice(0, 100),
123
- pattern: pat,
124
- flags: flgs
125
- };
126
- }, pattern, flags, selector || '');
127
- const resultText = `✅ Regex Pattern Matcher Results\n\nPattern: ${results.pattern}\nFlags: ${results.flags}\nTotal Matches: ${results.totalMatches}\n\nMatches (first 100):\n${JSON.stringify(results.matches, null, 2)}`;
128
- return {
129
- content: [{ type: 'text', text: resultText }],
130
- };
131
- }
132
- catch (error) {
133
- return { content: [{ type: 'text', text: `❌ Regex pattern matcher failed: ${error.message}` }], isError: true };
134
- }
135
- }
136
- /**
137
- * XPath Support - Query elements using XPath
138
- */
139
- export async function handleXPathSupport(args) {
140
- const { url, xpath, returnType = 'elements' } = args;
141
- try {
142
- const page = getPageInstance();
143
- if (!page) {
144
- throw new Error('Browser not initialized. Call browser_init first.');
145
- }
146
- if (url && page.url() !== url) {
147
- await page.goto(url, { waitUntil: 'networkidle2', timeout: 30000 });
148
- }
149
- const results = await page.evaluate((xp, type) => {
150
- const xpathResult = document.evaluate(xp, document, null, XPathResult.ANY_TYPE, null);
151
- const elements = [];
152
- let node = xpathResult.iterateNext();
153
- while (node) {
154
- if (node.nodeType === Node.ELEMENT_NODE) {
155
- const element = node;
156
- elements.push({
157
- tagName: element.tagName.toLowerCase(),
158
- id: element.id,
159
- className: element.className,
160
- text: element.textContent?.substring(0, 200),
161
- attributes: Array.from(element.attributes).reduce((acc, attr) => {
162
- acc[attr.name] = attr.value;
163
- return acc;
164
- }, {}),
165
- innerHTML: type === 'html' ? element.innerHTML.substring(0, 500) : undefined
166
- });
167
- }
168
- else if (node.nodeType === Node.TEXT_NODE) {
169
- elements.push({
170
- type: 'text',
171
- content: node.textContent?.trim()
172
- });
173
- }
174
- else if (node.nodeType === Node.ATTRIBUTE_NODE) {
175
- const attr = node;
176
- elements.push({
177
- type: 'attribute',
178
- name: attr.name,
179
- value: attr.value
180
- });
181
- }
182
- node = xpathResult.iterateNext();
183
- }
184
- return {
185
- count: elements.length,
186
- elements
187
- };
188
- }, xpath, returnType);
189
- const resultText = `✅ XPath Query Results\n\nXPath: ${xpath}\nElements Found: ${results.count}\n\nElements:\n${JSON.stringify(results.elements, null, 2)}`;
190
- return {
191
- content: [{ type: 'text', text: resultText }],
192
- };
193
- }
194
- catch (error) {
195
- return { content: [{ type: 'text', text: `❌ XPath query failed: ${error.message}` }], isError: true };
196
- }
197
- }
198
- /**
199
- * Advanced CSS Selectors - Support for complex CSS selectors
200
- */
201
- export async function handleAdvancedCSSSelectors(args) {
202
- const { url, selector, operation = 'query', returnType = 'elements' } = args;
203
- try {
204
- const page = getPageInstance();
205
- if (!page) {
206
- throw new Error('Browser not initialized. Call browser_init first.');
207
- }
208
- if (url && page.url() !== url) {
209
- await page.goto(url, { waitUntil: 'networkidle2', timeout: 30000 });
210
- }
211
- const results = await page.evaluate((sel, op, type) => {
212
- let elements;
213
- switch (op) {
214
- case 'query':
215
- elements = Array.from(document.querySelectorAll(sel));
216
- break;
217
- case 'closest':
218
- const firstEl = document.querySelector(sel);
219
- elements = firstEl ? [firstEl.closest(sel)].filter(Boolean) : [];
220
- break;
221
- case 'matches':
222
- elements = Array.from(document.querySelectorAll('*')).filter(el => el.matches(sel));
223
- break;
224
- default:
225
- elements = Array.from(document.querySelectorAll(sel));
226
- }
227
- const results = elements.map(element => {
228
- const computed = window.getComputedStyle(element);
229
- return {
230
- tagName: element.tagName.toLowerCase(),
231
- id: element.id,
232
- className: element.className,
233
- text: element.textContent?.substring(0, 200),
234
- attributes: Array.from(element.attributes).reduce((acc, attr) => {
235
- acc[attr.name] = attr.value;
236
- return acc;
237
- }, {}),
238
- computedStyles: type === 'styles' ? {
239
- display: computed.display,
240
- visibility: computed.visibility,
241
- position: computed.position,
242
- width: computed.width,
243
- height: computed.height,
244
- color: computed.color,
245
- backgroundColor: computed.backgroundColor
246
- } : undefined,
247
- innerHTML: type === 'html' ? element.innerHTML.substring(0, 500) : undefined,
248
- boundingRect: element.getBoundingClientRect()
249
- };
250
- });
251
- return {
252
- count: results.length,
253
- elements: results
254
- };
255
- }, selector, operation, returnType);
256
- const resultText = `✅ Advanced CSS Selector Results\n\nSelector: ${selector}\nOperation: ${operation}\nElements Found: ${results.count}\n\nElements (first 10):\n${JSON.stringify(results.elements.slice(0, 10), null, 2)}`;
257
- return {
258
- content: [{ type: 'text', text: resultText }],
259
- };
260
- }
261
- catch (error) {
262
- return { content: [{ type: 'text', text: `❌ CSS selector query failed: ${error.message}` }], isError: true };
263
- }
264
- }