brave-real-browser-mcp-server 2.8.6 → 2.8.8

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.
@@ -88,27 +88,31 @@ export async function handleRESTAPIEndpointFinder(args) {
88
88
  });
89
89
  return apis;
90
90
  });
91
+ let summary = `REST API Discovery Results:\n\nSummary:\n- Total APIs Found: ${apiEndpoints.length + discoveredAPIs.length}\n- Network APIs: ${apiEndpoints.length}\n- Discovered in Content: ${discoveredAPIs.length}`;
92
+ if (apiEndpoints.length > 0) {
93
+ summary += `\n\nNetwork API Endpoints (Top 10):\n${apiEndpoints.slice(0, 10).map((ep, i) => `${i + 1}. ${ep.method} ${ep.url}\n Type: ${ep.resourceType}${ep.hasBody ? ' (with body)' : ''}`).join('\n')}`;
94
+ }
95
+ if (discoveredAPIs.length > 0) {
96
+ summary += `\n\nDiscovered APIs (Top 10):\n${discoveredAPIs.slice(0, 10).map((api, i) => `${i + 1}. ${api.url}\n Source: ${api.source}`).join('\n')}`;
97
+ }
91
98
  return {
92
- success: true,
93
- networkRequests: {
94
- count: apiEndpoints.length,
95
- endpoints: apiEndpoints
96
- },
97
- discoveredInContent: {
98
- count: discoveredAPIs.length,
99
- endpoints: discoveredAPIs.slice(0, 20) // Limit to 20
100
- },
101
- summary: {
102
- totalFound: apiEndpoints.length + discoveredAPIs.length,
103
- uniqueNetworkAPIs: apiEndpoints.length,
104
- discoveredAPIs: discoveredAPIs.length
105
- }
99
+ content: [
100
+ {
101
+ type: "text",
102
+ text: summary
103
+ }
104
+ ]
106
105
  };
107
106
  }
108
107
  catch (error) {
109
108
  return {
110
- success: false,
111
- error: error.message
109
+ content: [
110
+ {
111
+ type: "text",
112
+ text: `REST API Endpoint Finder Error: ${error.message}`
113
+ }
114
+ ],
115
+ isError: true
112
116
  };
113
117
  }
114
118
  }
@@ -138,48 +142,47 @@ export async function handleWebhookSupport(args) {
138
142
  timeout: 10000
139
143
  });
140
144
  return {
141
- success: true,
142
- webhookUrl,
143
- method,
144
- testMode: true,
145
- response: {
146
- status: response.status,
147
- statusText: response.statusText,
148
- headers: response.headers,
149
- data: response.data
150
- }
145
+ content: [
146
+ {
147
+ type: "text",
148
+ text: `Webhook Test Successful:\n- URL: ${webhookUrl}\n- Method: ${method}\n- Status: ${response.status} ${response.statusText}\n- Response Headers: ${JSON.stringify(response.headers, null, 2)}\n- Response Data: ${JSON.stringify(response.data, null, 2)}`
149
+ }
150
+ ]
151
151
  };
152
152
  }
153
153
  catch (webhookError) {
154
154
  return {
155
- success: false,
156
- webhookUrl,
157
- testMode: true,
158
- error: webhookError.message,
159
- details: {
160
- status: webhookError.response?.status,
161
- statusText: webhookError.response?.statusText,
162
- data: webhookError.response?.data
163
- }
155
+ content: [
156
+ {
157
+ type: "text",
158
+ text: `Webhook Test Failed:\n- URL: ${webhookUrl}\n- Error: ${webhookError.message}${webhookError.response ? `\n- Status: ${webhookError.response.status} ${webhookError.response.statusText}\n- Response: ${JSON.stringify(webhookError.response.data, null, 2)}` : ''}`
159
+ }
160
+ ],
161
+ isError: true
164
162
  };
165
163
  }
166
164
  }
167
165
  else {
168
166
  // Production mode - set up webhook listener
169
167
  return {
170
- success: true,
171
- webhookUrl,
172
- method,
173
- testMode: false,
174
- status: 'configured',
175
- note: 'Webhook configured. Send data using separate call or integrate with scraping workflow'
168
+ content: [
169
+ {
170
+ type: "text",
171
+ text: `Webhook Configured:\n- URL: ${webhookUrl}\n- Method: ${method}\n- Test Mode: No\n- Status: Configured\n\nNote: Webhook configured. Send data using separate call or integrate with scraping workflow`
172
+ }
173
+ ]
176
174
  };
177
175
  }
178
176
  }
179
177
  catch (error) {
180
178
  return {
181
- success: false,
182
- error: error.message
179
+ content: [
180
+ {
181
+ type: "text",
182
+ text: `Webhook Support Error: ${error.message}`
183
+ }
184
+ ],
185
+ isError: true
183
186
  };
184
187
  }
185
188
  }
@@ -291,24 +294,41 @@ export async function handleAllWebsiteAPIFinder(args) {
291
294
  }, deepScan, includeExternal);
292
295
  // Deduplicate APIs
293
296
  const uniqueAPIs = [...new Set(apiDiscovery.apis.map((api) => api.url))];
297
+ const restFound = apiDiscovery.rest.filter((r) => r.found).length;
298
+ let summary = `Comprehensive API Discovery:\n\nSummary:\n- Total Unique APIs: ${uniqueAPIs.length}\n- GraphQL Detected: ${apiDiscovery.graphql.length > 0 ? 'Yes' : 'No'}\n- REST Endpoints: ${restFound}\n- WebSockets: ${apiDiscovery.websockets.length}\n- Documentation Links: ${apiDiscovery.documentationLinks?.length || 0}`;
299
+ if (apiDiscovery.graphql.length > 0) {
300
+ summary += `\n\nGraphQL:\n- Indicators Found: ${apiDiscovery.graphql[0].indicators}\n- Possible Endpoints: ${apiDiscovery.graphql[0].possibleEndpoints.join(', ')}`;
301
+ }
302
+ if (uniqueAPIs.length > 0) {
303
+ summary += `\n\nUnique APIs (Top 10):\n${uniqueAPIs.slice(0, 10).map((api, i) => `${i + 1}. ${api}`).join('\n')}`;
304
+ }
305
+ if (apiDiscovery.websockets.length > 0) {
306
+ summary += `\n\nWebSockets:\n${apiDiscovery.websockets.map((ws, i) => `${i + 1}. ${ws.url} (${ws.protocol})`).join('\n')}`;
307
+ }
308
+ if (apiDiscovery.documentationLinks?.length > 0) {
309
+ summary += `\n\nDocumentation Links:\n${apiDiscovery.documentationLinks.slice(0, 5).map((link, i) => `${i + 1}. ${link.text}: ${link.href}`).join('\n')}`;
310
+ }
311
+ if (apiDiscovery.swagger?.length > 0) {
312
+ summary += `\n\nSwagger/OpenAPI:\n${apiDiscovery.swagger.map((s, i) => `${i + 1}. ${s.href}`).join('\n')}`;
313
+ }
294
314
  return {
295
- success: true,
296
- summary: {
297
- totalAPIsFound: uniqueAPIs.length,
298
- graphqlDetected: apiDiscovery.graphql.length > 0,
299
- restEndpointsFound: apiDiscovery.rest.filter((r) => r.found).length,
300
- websocketsFound: apiDiscovery.websockets.length,
301
- documentationLinks: apiDiscovery.documentationLinks?.length || 0
302
- },
303
- details: apiDiscovery,
304
- uniqueAPIs: uniqueAPIs.slice(0, 20),
305
- recommendations: []
315
+ content: [
316
+ {
317
+ type: "text",
318
+ text: summary
319
+ }
320
+ ]
306
321
  };
307
322
  }
308
323
  catch (error) {
309
324
  return {
310
- success: false,
311
- error: error.message
325
+ content: [
326
+ {
327
+ type: "text",
328
+ text: `All Website API Finder Error: ${error.message}`
329
+ }
330
+ ],
331
+ isError: true
312
332
  };
313
333
  }
314
334
  }
@@ -41,22 +41,33 @@ export async function handleDataDeduplication(args) {
41
41
  unique.push(item);
42
42
  }
43
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
+ }
44
53
  return {
45
- success: true,
46
- statistics: {
47
- original: data.length,
48
- unique: unique.length,
49
- duplicates: duplicates.length,
50
- deduplicationRate: ((duplicates.length / data.length) * 100).toFixed(2) + '%'
51
- },
52
- uniqueData: unique,
53
- duplicateItems: duplicates.slice(0, 10) // Show first 10 duplicates
54
+ content: [
55
+ {
56
+ type: "text",
57
+ text: summary
58
+ }
59
+ ]
54
60
  };
55
61
  }
56
62
  catch (error) {
57
63
  return {
58
- success: false,
59
- error: error.message
64
+ content: [
65
+ {
66
+ type: "text",
67
+ text: `Data Deduplication Error: ${error.message}`
68
+ }
69
+ ],
70
+ isError: true
60
71
  };
61
72
  }
62
73
  }
@@ -122,24 +133,32 @@ export async function handleMissingDataHandler(args) {
122
133
  break;
123
134
  }
124
135
  });
136
+ const itemsWithMissing = Object.values(missingReport).length > 0 ?
137
+ [...new Set(Object.values(missingReport).flatMap((r) => r.indices))].length : 0;
138
+ const missingRate = ((totalMissing / (data.length * (requiredFields?.length || 1))) * 100).toFixed(2);
139
+ let summary = `Missing Data Analysis:\n\nStatistics:\n- Total Items: ${data.length}\n- Items with Missing Data: ${itemsWithMissing}\n- Total Missing Fields: ${totalMissing}\n- Missing Rate: ${missingRate}%\n- Strategy: ${strategy}`;
140
+ if (Object.keys(missingReport).length > 0) {
141
+ summary += `\n\nMissing Fields Report:\n${Object.entries(missingReport).map(([field, info]) => `- ${field}: ${info.count} occurrences (indices: ${info.indices.slice(0, 5).join(', ')}${info.indices.length > 5 ? '...' : ''})`).join('\n')}`;
142
+ }
143
+ summary += `\n\nProcessed Items: ${results.length}`;
125
144
  return {
126
- success: true,
127
- statistics: {
128
- totalItems: data.length,
129
- itemsWithMissing: Object.values(missingReport).length > 0 ?
130
- [...new Set(Object.values(missingReport).flatMap((r) => r.indices))].length : 0,
131
- totalMissingFields: totalMissing,
132
- missingRate: ((totalMissing / (data.length * (requiredFields?.length || 1))) * 100).toFixed(2) + '%'
133
- },
134
- missingReport,
135
- processedData: results,
136
- strategy
145
+ content: [
146
+ {
147
+ type: "text",
148
+ text: summary
149
+ }
150
+ ]
137
151
  };
138
152
  }
139
153
  catch (error) {
140
154
  return {
141
- success: false,
142
- error: error.message
155
+ content: [
156
+ {
157
+ type: "text",
158
+ text: `Missing Data Handler Error: ${error.message}`
159
+ }
160
+ ],
161
+ isError: true
143
162
  };
144
163
  }
145
164
  }
@@ -182,23 +201,34 @@ export async function handleDataTypeValidator(args) {
182
201
  });
183
202
  }
184
203
  }
204
+ const total = Array.isArray(data) ? data.length : 1;
205
+ const validationRate = ((validItems.length / total) * 100).toFixed(2);
206
+ let summary = `Data Type Validation Results:\n\nStatistics:\n- Total Items: ${total}\n- Valid Items: ${validItems.length}\n- Invalid Items: ${invalidItems.length}\n- Validation Rate: ${validationRate}%`;
207
+ if (invalidItems.length > 0) {
208
+ summary += `\n\nInvalid Items (Top 5):\n${invalidItems.slice(0, 5).map((inv, i) => {
209
+ const errorMsgs = inv.errors?.map((e) => `${e.instancePath || 'root'}: ${e.message}`).join(', ') || 'Unknown error';
210
+ return `${i + 1}. Index ${inv.index || 'N/A'}:\n Errors: ${errorMsgs}`;
211
+ }).join('\n')}`;
212
+ }
213
+ summary += `\n\nSchema: ${JSON.stringify(schema, null, 2).substring(0, 200)}${JSON.stringify(schema).length > 200 ? '...' : ''}`;
185
214
  return {
186
- success: true,
187
- validation: {
188
- total: Array.isArray(data) ? data.length : 1,
189
- valid: validItems.length,
190
- invalid: invalidItems.length,
191
- validationRate: ((validItems.length / (Array.isArray(data) ? data.length : 1)) * 100).toFixed(2) + '%'
192
- },
193
- validData: validItems,
194
- invalidData: invalidItems.slice(0, 10), // Show first 10 invalid items
195
- schema
215
+ content: [
216
+ {
217
+ type: "text",
218
+ text: summary
219
+ }
220
+ ]
196
221
  };
197
222
  }
198
223
  catch (error) {
199
224
  return {
200
- success: false,
201
- error: error.message
225
+ content: [
226
+ {
227
+ type: "text",
228
+ text: `Data Type Validator Error: ${error.message}`
229
+ }
230
+ ],
231
+ isError: true
202
232
  };
203
233
  }
204
234
  }
@@ -281,22 +311,32 @@ export async function handleOutlierDetection(args) {
281
311
  }
282
312
  });
283
313
  }
314
+ const outlierPercentage = ((outliers.length / data.length) * 100).toFixed(2);
315
+ 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}`;
316
+ summary += `\n\nOutliers:\n- Count: ${outliers.length}\n- Percentage: ${outlierPercentage}%`;
317
+ if (outliers.length > 0) {
318
+ summary += `\n\nOutlier Samples (Top 10):\n${outliers.slice(0, 10).map((o, i) => {
319
+ 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}]` : ''}`;
320
+ }).join('\n')}`;
321
+ }
284
322
  return {
285
- success: true,
286
- method,
287
- threshold,
288
- statistics: stats,
289
- outliers: {
290
- count: outliers.length,
291
- percentage: ((outliers.length / data.length) * 100).toFixed(2) + '%',
292
- items: outliers.slice(0, 20) // Show first 20 outliers
293
- }
323
+ content: [
324
+ {
325
+ type: "text",
326
+ text: summary
327
+ }
328
+ ]
294
329
  };
295
330
  }
296
331
  catch (error) {
297
332
  return {
298
- success: false,
299
- error: error.message
333
+ content: [
334
+ {
335
+ type: "text",
336
+ text: `Outlier Detection Error: ${error.message}`
337
+ }
338
+ ],
339
+ isError: true
300
340
  };
301
341
  }
302
342
  }
@@ -408,22 +448,30 @@ export async function handleConsistencyChecker(args) {
408
448
  }
409
449
  });
410
450
  });
451
+ const consistencyRate = (((data.length - violations.length) / data.length) * 100).toFixed(2);
452
+ let summary = `Consistency Check Results:\n\nSummary:\n- Total Items: ${data.length}\n- Rules Checked: ${rules.length}\n- Total Violations: ${violations.length}\n- Consistency Rate: ${consistencyRate}%`;
453
+ summary += `\n\nRule Results:\n${Object.entries(ruleResults).map(([name, result]) => `- ${name}: ${result.passed} passed, ${result.failed} failed`).join('\n')}`;
454
+ if (violations.length > 0) {
455
+ summary += `\n\nViolations (Top 10):\n${violations.slice(0, 10).map((v, i) => `${i + 1}. Index ${v.index} - Rule: ${v.rule}\n Reason: ${v.reason}`).join('\n')}`;
456
+ }
411
457
  return {
412
- success: true,
413
- summary: {
414
- totalItems: data.length,
415
- totalViolations: violations.length,
416
- rulesChecked: rules.length,
417
- consistencyRate: (((data.length - violations.length) / data.length) * 100).toFixed(2) + '%'
418
- },
419
- ruleResults,
420
- violations: violations.slice(0, 20) // Show first 20 violations
458
+ content: [
459
+ {
460
+ type: "text",
461
+ text: summary
462
+ }
463
+ ]
421
464
  };
422
465
  }
423
466
  catch (error) {
424
467
  return {
425
- success: false,
426
- error: error.message
468
+ content: [
469
+ {
470
+ type: "text",
471
+ text: `Consistency Checker Error: ${error.message}`
472
+ }
473
+ ],
474
+ isError: true
427
475
  };
428
476
  }
429
477
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "brave-real-browser-mcp-server",
3
- "version": "2.8.6",
3
+ "version": "2.8.8",
4
4
  "description": "MCP server for brave-real-browser",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",