brave-real-browser-mcp-server 2.14.4 → 2.14.6
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/README.md +20 -557
- package/dist/index.js +19 -77
- package/dist/tool-definitions.js +0 -45
- package/package.json +4 -15
- package/dist/handlers/api-integration-handlers.js +0 -335
- package/dist/launcher.js +0 -266
- package/dist/transports/http-transport.js +0 -198
- package/dist/transports/lsp-transport.js +0 -165
- package/dist/transports/sse-transport.js +0 -312
- package/dist/transports/sse-transport.test.js +0 -244
- package/dist/universal-ide-adapter.js +0 -855
package/dist/index.js
CHANGED
|
@@ -3,9 +3,6 @@
|
|
|
3
3
|
console.error(`🔍 [DEBUG] Process starting - PID: ${process.pid}, Node: ${process.version}, Platform: ${process.platform}`);
|
|
4
4
|
console.error(`🔍 [DEBUG] Working directory: ${process.cwd()}`);
|
|
5
5
|
console.error(`🔍 [DEBUG] Command args: ${process.argv.join(" ")}`);
|
|
6
|
-
// Universal AI IDE Adapter - Auto-detect and support all AI IDEs
|
|
7
|
-
console.error("🔍 [DEBUG] Loading Universal IDE Adapter...");
|
|
8
|
-
import { UniversalIDEAdapter, } from "./universal-ide-adapter.js";
|
|
9
6
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
10
7
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
11
8
|
import { CallToolRequestSchema, ListToolsRequestSchema, ListResourcesRequestSchema, ListPromptsRequestSchema, InitializeRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
@@ -13,7 +10,6 @@ console.error("🔍 [DEBUG] MCP SDK imports completed successfully");
|
|
|
13
10
|
// Import extracted modules
|
|
14
11
|
console.error("🔍 [DEBUG] Loading tool definitions...");
|
|
15
12
|
import { TOOLS, SERVER_INFO, CAPABILITIES, TOOL_NAMES, } from "./tool-definitions.js";
|
|
16
|
-
console.error("🔍 [DEBUG] Universal IDE Adapter loaded successfully");
|
|
17
13
|
console.error("🔍 [DEBUG] Loading system utils...");
|
|
18
14
|
import { withErrorHandling } from "./system-utils.js";
|
|
19
15
|
import { validateMCPResponse } from "./mcp-response-validator.js";
|
|
@@ -21,12 +17,6 @@ console.error("🔍 [DEBUG] Loading browser manager...");
|
|
|
21
17
|
import { closeBrowser, forceKillAllBraveProcesses } from "./browser-manager.js";
|
|
22
18
|
console.error("🔍 [DEBUG] Loading core infrastructure...");
|
|
23
19
|
import { setupProcessCleanup, } from "./core-infrastructure.js";
|
|
24
|
-
// Initialize Universal IDE Adapter
|
|
25
|
-
const universalAdapter = new UniversalIDEAdapter({
|
|
26
|
-
enableAutoDetection: true,
|
|
27
|
-
fallbackToHttp: true,
|
|
28
|
-
logDetectionDetails: true,
|
|
29
|
-
});
|
|
30
20
|
// Import handlers
|
|
31
21
|
console.error("🔍 [DEBUG] Loading handlers...");
|
|
32
22
|
import { handleBrowserInit, handleBrowserClose, } from "./handlers/browser-handlers.js";
|
|
@@ -52,10 +42,8 @@ import { handleDataDeduplication, handleMissingDataHandler, handleDataTypeValida
|
|
|
52
42
|
import { handleOCREngine, handleAudioCaptchaSolver, handlePuzzleCaptchaHandler, } from "./handlers/captcha-handlers.js";
|
|
53
43
|
// Import visual tools handlers
|
|
54
44
|
import { handleFullPageScreenshot, handleElementScreenshot, handlePDFGeneration, handleVideoRecording, handleVisualComparison, } from "./handlers/visual-tools-handlers.js";
|
|
55
|
-
// Import API integration handlers
|
|
56
|
-
import { handleRESTAPIEndpointFinder, handleWebhookSupport, handleAllWebsiteAPIFinder, } from "./handlers/api-integration-handlers.js";
|
|
57
45
|
// Import smart data extractors
|
|
58
|
-
import { handleHtmlElementsExtractor, handleTagsFinder, handleLinksFinder, handleXpathLinks, handleAjaxExtractor, handleFetchXHR, handleNetworkRecorder,
|
|
46
|
+
import { handleHtmlElementsExtractor, handleTagsFinder, handleLinksFinder, handleXpathLinks, handleAjaxExtractor, handleFetchXHR, handleNetworkRecorder, handleRegexPatternFinder, handleIframeExtractor, handleEmbedPageExtractor, handleImageExtractorAdvanced, handleVideoSourceExtractor, handleVideoPlayerExtractor, handleVideoPlayerHosterFinder, handleOriginalVideoHosterFinder, handleUrlRedirectTracer, handleUserAgentExtractor, } from "./handlers/smart-data-extractors.js";
|
|
59
47
|
// Import dynamic session handlers
|
|
60
48
|
import { handleShadowDOMExtractor, handleCookieManager, handleSessionPersistence, handleFormAutoFill, handleAjaxContentWaiter, handleModalPopupHandler, handleLoginSessionManager, } from "./handlers/dynamic-session-handlers.js";
|
|
61
49
|
// Import monitoring & reporting handlers
|
|
@@ -304,16 +292,6 @@ export async function executeToolByName(name, args) {
|
|
|
304
292
|
case TOOL_NAMES.VISUAL_COMPARISON:
|
|
305
293
|
result = await handleVisualComparison(args);
|
|
306
294
|
break;
|
|
307
|
-
// Website API Integration
|
|
308
|
-
case TOOL_NAMES.REST_API_ENDPOINT_FINDER:
|
|
309
|
-
result = await handleRESTAPIEndpointFinder(args);
|
|
310
|
-
break;
|
|
311
|
-
case TOOL_NAMES.WEBHOOK_SUPPORT:
|
|
312
|
-
result = await handleWebhookSupport(args);
|
|
313
|
-
break;
|
|
314
|
-
case TOOL_NAMES.ALL_WEBSITE_API_FINDER:
|
|
315
|
-
result = await handleAllWebsiteAPIFinder(args);
|
|
316
|
-
break;
|
|
317
295
|
// Smart Data Extractors (Advanced)
|
|
318
296
|
case "html_elements_extractor":
|
|
319
297
|
result = await handleHtmlElementsExtractor(args || {});
|
|
@@ -336,9 +314,6 @@ export async function executeToolByName(name, args) {
|
|
|
336
314
|
case "network_recorder":
|
|
337
315
|
result = await handleNetworkRecorder(args || {});
|
|
338
316
|
break;
|
|
339
|
-
case "api_finder":
|
|
340
|
-
result = await handleApiFinder(args || {});
|
|
341
|
-
break;
|
|
342
317
|
case "regex_pattern_finder":
|
|
343
318
|
result = await handleRegexPatternFinder(args);
|
|
344
319
|
break;
|
|
@@ -498,29 +473,19 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
498
473
|
return await executeToolByName(name, args);
|
|
499
474
|
});
|
|
500
475
|
// Main function - now using multi-protocol launcher
|
|
501
|
-
|
|
476
|
+
// Main function
|
|
502
477
|
async function main() {
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
console.error("
|
|
512
|
-
console.error("
|
|
513
|
-
|
|
514
|
-
await closeBrowser();
|
|
515
|
-
await forceKillAllBraveProcesses();
|
|
516
|
-
});
|
|
517
|
-
const transport = new StdioServerTransport();
|
|
518
|
-
await withErrorHandling(async () => {
|
|
519
|
-
await server.connect(transport);
|
|
520
|
-
console.error("🚀 Brave Real Browser MCP Server started successfully");
|
|
521
|
-
console.error("📋 Available tools:", TOOLS.map((t) => t.name).join(", "));
|
|
522
|
-
}, "Failed to start MCP server");
|
|
523
|
-
}
|
|
478
|
+
console.error("🔍 [DEBUG] Starting in STDIO mode...");
|
|
479
|
+
setupProcessCleanup(async () => {
|
|
480
|
+
await closeBrowser();
|
|
481
|
+
await forceKillAllBraveProcesses();
|
|
482
|
+
});
|
|
483
|
+
const transport = new StdioServerTransport();
|
|
484
|
+
await withErrorHandling(async () => {
|
|
485
|
+
await server.connect(transport);
|
|
486
|
+
console.error("🚀 Brave Real Browser MCP Server started successfully");
|
|
487
|
+
console.error("📋 Available tools:", TOOLS.map((t) => t.name).join(", "));
|
|
488
|
+
}, "Failed to start MCP server");
|
|
524
489
|
}
|
|
525
490
|
// Enhanced error handling with debug info
|
|
526
491
|
console.error("🔍 [DEBUG] Setting up error handlers...");
|
|
@@ -551,32 +516,9 @@ process.on("SIGINT", () => {
|
|
|
551
516
|
});
|
|
552
517
|
console.error("🔍 [DEBUG] All error handlers registered");
|
|
553
518
|
// Start the server
|
|
554
|
-
|
|
555
|
-
console.error(`🔍 [DEBUG]
|
|
556
|
-
console.error(
|
|
557
|
-
console.error(`🔍 [DEBUG]
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
process.argv[1].includes("brave-real-browser-mcp-server") ||
|
|
561
|
-
process.argv[1].endsWith(".bin/brave-real-browser-mcp-server") ||
|
|
562
|
-
process.argv.some((arg) => arg.includes("brave-real-browser-mcp-server"));
|
|
563
|
-
console.error(`🔍 [DEBUG] Enhanced main detection result: ${isMain}`);
|
|
564
|
-
if (isMain) {
|
|
565
|
-
console.error("🔍 [DEBUG] Module is main - starting server...");
|
|
566
|
-
main().catch((error) => {
|
|
567
|
-
console.error(`🔍 [DEBUG] Main function failed at ${new Date().toISOString()}`);
|
|
568
|
-
console.error("❌ Failed to start server:", error);
|
|
569
|
-
console.error(`🔍 [DEBUG] Error stack:`, error.stack);
|
|
570
|
-
process.exit(1);
|
|
571
|
-
});
|
|
572
|
-
}
|
|
573
|
-
else {
|
|
574
|
-
console.error("🔍 [DEBUG] Module is not main - not starting server");
|
|
575
|
-
console.error("🔍 [DEBUG] FORCE STARTING - This is likely an npx execution");
|
|
576
|
-
main().catch((error) => {
|
|
577
|
-
console.error(`🔍 [DEBUG] Forced main function failed at ${new Date().toISOString()}`);
|
|
578
|
-
console.error("❌ Failed to start server:", error);
|
|
579
|
-
console.error(`🔍 [DEBUG] Error stack:`, error.stack);
|
|
580
|
-
process.exit(1);
|
|
581
|
-
});
|
|
582
|
-
}
|
|
519
|
+
main().catch((error) => {
|
|
520
|
+
console.error(`🔍 [DEBUG] Main function failed at ${new Date().toISOString()}`);
|
|
521
|
+
console.error("❌ Failed to start server:", error);
|
|
522
|
+
console.error(`🔍 [DEBUG] Error stack:`, error.stack);
|
|
523
|
+
process.exit(1);
|
|
524
|
+
});
|
package/dist/tool-definitions.js
CHANGED
|
@@ -960,47 +960,6 @@ export const TOOLS = [
|
|
|
960
960
|
required: ['image1Path', 'image2Path'],
|
|
961
961
|
},
|
|
962
962
|
},
|
|
963
|
-
// Website API Integration (3 tools)
|
|
964
|
-
{
|
|
965
|
-
name: 'rest_api_endpoint_finder',
|
|
966
|
-
description: 'Discover REST API endpoints',
|
|
967
|
-
inputSchema: {
|
|
968
|
-
type: 'object',
|
|
969
|
-
properties: {
|
|
970
|
-
url: { type: 'string' },
|
|
971
|
-
analyzeNetworkRequests: { type: 'boolean', default: true },
|
|
972
|
-
scanDuration: { type: 'number', default: 10000 },
|
|
973
|
-
},
|
|
974
|
-
},
|
|
975
|
-
},
|
|
976
|
-
{
|
|
977
|
-
name: 'webhook_support',
|
|
978
|
-
description: 'Set up and test webhooks',
|
|
979
|
-
inputSchema: {
|
|
980
|
-
type: 'object',
|
|
981
|
-
properties: {
|
|
982
|
-
webhookUrl: { type: 'string' },
|
|
983
|
-
method: { type: 'string', default: 'POST' },
|
|
984
|
-
payload: { type: 'object' },
|
|
985
|
-
headers: { type: 'object' },
|
|
986
|
-
testMode: { type: 'boolean', default: true },
|
|
987
|
-
},
|
|
988
|
-
required: ['webhookUrl'],
|
|
989
|
-
},
|
|
990
|
-
},
|
|
991
|
-
{
|
|
992
|
-
name: 'all_website_api_finder',
|
|
993
|
-
description: 'Comprehensive API discovery',
|
|
994
|
-
inputSchema: {
|
|
995
|
-
type: 'object',
|
|
996
|
-
properties: {
|
|
997
|
-
url: { type: 'string' },
|
|
998
|
-
deepScan: { type: 'boolean', default: true },
|
|
999
|
-
includeExternal: { type: 'boolean', default: false },
|
|
1000
|
-
},
|
|
1001
|
-
required: ['url'],
|
|
1002
|
-
},
|
|
1003
|
-
},
|
|
1004
963
|
// Smart Data Extractors (Advanced)
|
|
1005
964
|
{
|
|
1006
965
|
name: 'html_elements_extractor',
|
|
@@ -1573,10 +1532,6 @@ export const TOOL_NAMES = {
|
|
|
1573
1532
|
PDF_GENERATION: 'pdf_generation',
|
|
1574
1533
|
VIDEO_RECORDING: 'video_recording',
|
|
1575
1534
|
VISUAL_COMPARISON: 'visual_comparison',
|
|
1576
|
-
// Website API Integration
|
|
1577
|
-
REST_API_ENDPOINT_FINDER: 'rest_api_endpoint_finder',
|
|
1578
|
-
WEBHOOK_SUPPORT: 'webhook_support',
|
|
1579
|
-
ALL_WEBSITE_API_FINDER: 'all_website_api_finder',
|
|
1580
1535
|
};
|
|
1581
1536
|
// Tool categories for organization
|
|
1582
1537
|
export const TOOL_CATEGORIES = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "brave-real-browser-mcp-server",
|
|
3
|
-
"version": "2.14.
|
|
3
|
+
"version": "2.14.6",
|
|
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",
|
|
@@ -19,12 +19,7 @@
|
|
|
19
19
|
"build": "tsc",
|
|
20
20
|
"rebuild": "npm run clean && npm run build",
|
|
21
21
|
"start": "node dist/index.js",
|
|
22
|
-
"start:http": "node dist/index.js --mode http",
|
|
23
|
-
"start:lsp": "node dist/index.js --mode lsp",
|
|
24
|
-
"start:all": "node dist/index.js --mode all",
|
|
25
22
|
"dev": "tsx src/index.ts",
|
|
26
|
-
"dev:http": "tsx src/index.ts --mode http",
|
|
27
|
-
"dev:lsp": "tsx src/index.ts --mode lsp",
|
|
28
23
|
"test": "vitest",
|
|
29
24
|
"test:watch": "vitest --watch",
|
|
30
25
|
"test:ui": "vitest --ui",
|
|
@@ -44,13 +39,12 @@
|
|
|
44
39
|
"ajv": "^8.12.0",
|
|
45
40
|
"axios": "^1.6.5",
|
|
46
41
|
"brave-real-browser": "^1.5.105",
|
|
47
|
-
"brave-real-launcher": "^1.2.
|
|
48
|
-
"brave-real-puppeteer-core": "^24.
|
|
42
|
+
"brave-real-launcher": "^1.2.28",
|
|
43
|
+
"brave-real-puppeteer-core": "^24.33.0-patch.1",
|
|
49
44
|
"cheerio": "^1.0.0-rc.12",
|
|
50
45
|
"chrono-node": "^2.7.0",
|
|
51
46
|
"compromise": "^14.13.0",
|
|
52
47
|
"dotenv": "^17.2.3",
|
|
53
|
-
"express": "^4.21.2",
|
|
54
48
|
"franc": "^6.2.0",
|
|
55
49
|
"libphonenumber-js": "^1.10.51",
|
|
56
50
|
"natural": "^6.12.0",
|
|
@@ -60,20 +54,15 @@
|
|
|
60
54
|
"sentiment": "^5.0.2",
|
|
61
55
|
"tesseract.js": "^5.0.5",
|
|
62
56
|
"turndown": "^7.2.2",
|
|
63
|
-
"vscode-languageserver": "^9.0.1",
|
|
64
|
-
"vscode-languageserver-textdocument": "^1.0.12",
|
|
65
|
-
"ws": "^8.18.3",
|
|
66
57
|
"xml2js": "^0.6.2"
|
|
67
58
|
},
|
|
68
59
|
"devDependencies": {
|
|
69
60
|
"@types/cheerio": "^0.22.35",
|
|
70
|
-
"@types/express": "^4.17.23",
|
|
71
61
|
"@types/node": "latest",
|
|
72
|
-
"@types/ws": "^8.18.1",
|
|
73
62
|
"@types/xml2js": "^0.4.14",
|
|
74
63
|
"@vitest/coverage-v8": "^3.2.4",
|
|
75
64
|
"@vitest/ui": "^3.2.4",
|
|
76
|
-
"rimraf": "^6.
|
|
65
|
+
"rimraf": "^6.1.2",
|
|
77
66
|
"tsx": "latest",
|
|
78
67
|
"typescript": "^5.5.3",
|
|
79
68
|
"vitest": "^3.2.4"
|
|
@@ -1,335 +0,0 @@
|
|
|
1
|
-
// @ts-nocheck
|
|
2
|
-
import { getPageInstance } from '../browser-manager.js';
|
|
3
|
-
import axios from 'axios';
|
|
4
|
-
import { sleep } from '../system-utils.js';
|
|
5
|
-
/**
|
|
6
|
-
* REST API Endpoint Finder - Discover REST API endpoints
|
|
7
|
-
*/
|
|
8
|
-
export async function handleRESTAPIEndpointFinder(args) {
|
|
9
|
-
const { url, analyzeNetworkRequests = true, scanDuration = 10000 } = args;
|
|
10
|
-
try {
|
|
11
|
-
const page = getPageInstance();
|
|
12
|
-
if (!page) {
|
|
13
|
-
throw new Error('Browser not initialized. Call browser_init first.');
|
|
14
|
-
}
|
|
15
|
-
const apiEndpoints = [];
|
|
16
|
-
const seenUrls = new Set();
|
|
17
|
-
// Listen to network requests
|
|
18
|
-
if (analyzeNetworkRequests) {
|
|
19
|
-
const requestHandler = (request) => {
|
|
20
|
-
const requestUrl = request.url();
|
|
21
|
-
const method = request.method();
|
|
22
|
-
const resourceType = request.resourceType();
|
|
23
|
-
// Filter for API-like requests
|
|
24
|
-
if ((resourceType === 'xhr' || resourceType === 'fetch') &&
|
|
25
|
-
!seenUrls.has(requestUrl)) {
|
|
26
|
-
seenUrls.add(requestUrl);
|
|
27
|
-
const headers = request.headers();
|
|
28
|
-
const postData = request.postData();
|
|
29
|
-
apiEndpoints.push({
|
|
30
|
-
url: requestUrl,
|
|
31
|
-
method,
|
|
32
|
-
resourceType,
|
|
33
|
-
headers: Object.keys(headers).reduce((acc, key) => {
|
|
34
|
-
if (!key.toLowerCase().includes('cookie') && !key.toLowerCase().includes('authorization')) {
|
|
35
|
-
acc[key] = headers[key];
|
|
36
|
-
}
|
|
37
|
-
return acc;
|
|
38
|
-
}, {}),
|
|
39
|
-
hasBody: !!postData,
|
|
40
|
-
timestamp: new Date().toISOString()
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
};
|
|
44
|
-
page.on('request', requestHandler);
|
|
45
|
-
// Navigate and wait
|
|
46
|
-
if (url && page.url() !== url) {
|
|
47
|
-
await page.goto(url, { waitUntil: 'networkidle2', timeout: 30000 });
|
|
48
|
-
}
|
|
49
|
-
// Wait for additional requests
|
|
50
|
-
await sleep(scanDuration);
|
|
51
|
-
page.off('request', requestHandler);
|
|
52
|
-
}
|
|
53
|
-
// Also scan page content for API endpoints
|
|
54
|
-
const discoveredAPIs = await page.evaluate(() => {
|
|
55
|
-
const apis = [];
|
|
56
|
-
const scripts = Array.from(document.querySelectorAll('script'));
|
|
57
|
-
// Common API URL patterns
|
|
58
|
-
const apiPatterns = [
|
|
59
|
-
/https?:\/\/[^"'\s]+\/api\/[^"'\s]*/gi,
|
|
60
|
-
/https?:\/\/api\.[^"'\s]+/gi,
|
|
61
|
-
/\/api\/v?\d*\/[^"'\s]*/gi,
|
|
62
|
-
/graphql/gi,
|
|
63
|
-
/rest\/v?\d*/gi
|
|
64
|
-
];
|
|
65
|
-
scripts.forEach(script => {
|
|
66
|
-
const content = script.textContent || '';
|
|
67
|
-
apiPatterns.forEach(pattern => {
|
|
68
|
-
const matches = content.match(pattern);
|
|
69
|
-
if (matches) {
|
|
70
|
-
matches.forEach(match => apis.push({
|
|
71
|
-
url: match,
|
|
72
|
-
source: 'script_content',
|
|
73
|
-
type: 'discovered'
|
|
74
|
-
}));
|
|
75
|
-
}
|
|
76
|
-
});
|
|
77
|
-
});
|
|
78
|
-
// Check for data attributes
|
|
79
|
-
const elements = Array.from(document.querySelectorAll('[data-api], [data-endpoint], [data-url]'));
|
|
80
|
-
elements.forEach(el => {
|
|
81
|
-
const apiUrl = el.getAttribute('data-api') || el.getAttribute('data-endpoint') || el.getAttribute('data-url');
|
|
82
|
-
if (apiUrl) {
|
|
83
|
-
apis.push({
|
|
84
|
-
url: apiUrl,
|
|
85
|
-
source: 'data_attribute',
|
|
86
|
-
element: el.tagName.toLowerCase()
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
});
|
|
90
|
-
return apis;
|
|
91
|
-
});
|
|
92
|
-
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}`;
|
|
93
|
-
if (apiEndpoints.length > 0) {
|
|
94
|
-
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')}`;
|
|
95
|
-
}
|
|
96
|
-
if (discoveredAPIs.length > 0) {
|
|
97
|
-
summary += `\n\nDiscovered APIs (Top 10):\n${discoveredAPIs.slice(0, 10).map((api, i) => `${i + 1}. ${api.url}\n Source: ${api.source}`).join('\n')}`;
|
|
98
|
-
}
|
|
99
|
-
return {
|
|
100
|
-
content: [
|
|
101
|
-
{
|
|
102
|
-
type: "text",
|
|
103
|
-
text: summary
|
|
104
|
-
}
|
|
105
|
-
]
|
|
106
|
-
};
|
|
107
|
-
}
|
|
108
|
-
catch (error) {
|
|
109
|
-
return {
|
|
110
|
-
content: [
|
|
111
|
-
{
|
|
112
|
-
type: "text",
|
|
113
|
-
text: `REST API Endpoint Finder Error: ${error.message}`
|
|
114
|
-
}
|
|
115
|
-
],
|
|
116
|
-
isError: true
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
/**
|
|
121
|
-
* Webhook Support - Set up and test webhooks
|
|
122
|
-
*/
|
|
123
|
-
export async function handleWebhookSupport(args) {
|
|
124
|
-
const { webhookUrl, method = 'POST', payload, headers, testMode = true } = args;
|
|
125
|
-
try {
|
|
126
|
-
if (!webhookUrl) {
|
|
127
|
-
throw new Error('Webhook URL is required');
|
|
128
|
-
}
|
|
129
|
-
const defaultHeaders = {
|
|
130
|
-
'Content-Type': 'application/json',
|
|
131
|
-
'User-Agent': 'Brave-MCP-Server/1.0',
|
|
132
|
-
...headers
|
|
133
|
-
};
|
|
134
|
-
let response;
|
|
135
|
-
if (testMode) {
|
|
136
|
-
// Test webhook with ping
|
|
137
|
-
try {
|
|
138
|
-
response = await axios({
|
|
139
|
-
method,
|
|
140
|
-
url: webhookUrl,
|
|
141
|
-
headers: defaultHeaders,
|
|
142
|
-
data: payload || { test: true, timestamp: new Date().toISOString() },
|
|
143
|
-
timeout: 10000
|
|
144
|
-
});
|
|
145
|
-
return {
|
|
146
|
-
content: [
|
|
147
|
-
{
|
|
148
|
-
type: "text",
|
|
149
|
-
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)}`
|
|
150
|
-
}
|
|
151
|
-
]
|
|
152
|
-
};
|
|
153
|
-
}
|
|
154
|
-
catch (webhookError) {
|
|
155
|
-
return {
|
|
156
|
-
content: [
|
|
157
|
-
{
|
|
158
|
-
type: "text",
|
|
159
|
-
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)}` : ''}`
|
|
160
|
-
}
|
|
161
|
-
],
|
|
162
|
-
isError: true
|
|
163
|
-
};
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
else {
|
|
167
|
-
// Production mode - set up webhook listener
|
|
168
|
-
return {
|
|
169
|
-
content: [
|
|
170
|
-
{
|
|
171
|
-
type: "text",
|
|
172
|
-
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`
|
|
173
|
-
}
|
|
174
|
-
]
|
|
175
|
-
};
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
catch (error) {
|
|
179
|
-
return {
|
|
180
|
-
content: [
|
|
181
|
-
{
|
|
182
|
-
type: "text",
|
|
183
|
-
text: `Webhook Support Error: ${error.message}`
|
|
184
|
-
}
|
|
185
|
-
],
|
|
186
|
-
isError: true
|
|
187
|
-
};
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
/**
|
|
191
|
-
* All Website API Finder - Comprehensive API discovery
|
|
192
|
-
*/
|
|
193
|
-
export async function handleAllWebsiteAPIFinder(args) {
|
|
194
|
-
const { url, deepScan = true, includeExternal = false } = args;
|
|
195
|
-
try {
|
|
196
|
-
const page = getPageInstance();
|
|
197
|
-
if (!page) {
|
|
198
|
-
throw new Error('Browser not initialized. Call browser_init first.');
|
|
199
|
-
}
|
|
200
|
-
if (url && page.url() !== url) {
|
|
201
|
-
await page.goto(url, { waitUntil: 'networkidle2', timeout: 30000 });
|
|
202
|
-
}
|
|
203
|
-
const apiDiscovery = await page.evaluate((deep, external) => {
|
|
204
|
-
const result = {
|
|
205
|
-
apis: [],
|
|
206
|
-
graphql: [],
|
|
207
|
-
rest: [],
|
|
208
|
-
websockets: [],
|
|
209
|
-
metadata: {}
|
|
210
|
-
};
|
|
211
|
-
// 1. Check for API documentation links
|
|
212
|
-
const apiLinks = Array.from(document.querySelectorAll('a[href*="api"], a[href*="docs"], a[href*="developer"]'));
|
|
213
|
-
result.documentationLinks = apiLinks.map(link => ({
|
|
214
|
-
text: link.textContent?.trim(),
|
|
215
|
-
href: link.href
|
|
216
|
-
})).slice(0, 10);
|
|
217
|
-
// 2. Scan for GraphQL
|
|
218
|
-
const graphqlIndicators = document.body.innerHTML.match(/graphql|__schema|query\s*{|mutation\s*{/gi);
|
|
219
|
-
if (graphqlIndicators) {
|
|
220
|
-
result.graphql.push({
|
|
221
|
-
found: true,
|
|
222
|
-
indicators: graphqlIndicators.length,
|
|
223
|
-
possibleEndpoints: [
|
|
224
|
-
'/graphql',
|
|
225
|
-
'/api/graphql',
|
|
226
|
-
'/v1/graphql'
|
|
227
|
-
]
|
|
228
|
-
});
|
|
229
|
-
}
|
|
230
|
-
// 3. Scan scripts for API configurations
|
|
231
|
-
const scripts = Array.from(document.querySelectorAll('script'));
|
|
232
|
-
scripts.forEach(script => {
|
|
233
|
-
const content = script.textContent || '';
|
|
234
|
-
// Look for API base URLs
|
|
235
|
-
const baseUrlPatterns = [
|
|
236
|
-
/apiUrl\s*[:=]\s*["']([^"']+)["']/gi,
|
|
237
|
-
/baseURL\s*[:=]\s*["']([^"']+)["']/gi,
|
|
238
|
-
/API_BASE\s*[:=]\s*["']([^"']+)["']/gi,
|
|
239
|
-
/endpoint\s*[:=]\s*["']([^"']+)["']/gi
|
|
240
|
-
];
|
|
241
|
-
baseUrlPatterns.forEach(pattern => {
|
|
242
|
-
const matches = Array.from(content.matchAll(pattern));
|
|
243
|
-
matches.forEach(match => {
|
|
244
|
-
if (match[1] && (external || match[1].startsWith('/'))) {
|
|
245
|
-
result.apis.push({
|
|
246
|
-
type: 'config',
|
|
247
|
-
url: match[1],
|
|
248
|
-
source: 'script'
|
|
249
|
-
});
|
|
250
|
-
}
|
|
251
|
-
});
|
|
252
|
-
});
|
|
253
|
-
// Look for WebSocket connections
|
|
254
|
-
if (content.includes('WebSocket') || content.includes('ws://') || content.includes('wss://')) {
|
|
255
|
-
const wsMatches = content.match(/wss?:\/\/[^"'\s]+/gi);
|
|
256
|
-
if (wsMatches) {
|
|
257
|
-
wsMatches.forEach(ws => {
|
|
258
|
-
result.websockets.push({
|
|
259
|
-
url: ws,
|
|
260
|
-
protocol: ws.startsWith('wss') ? 'secure' : 'unsecure'
|
|
261
|
-
});
|
|
262
|
-
});
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
});
|
|
266
|
-
// 4. Check meta tags for API info
|
|
267
|
-
const metaTags = Array.from(document.querySelectorAll('meta[name*="api"], meta[property*="api"]'));
|
|
268
|
-
result.metadata.apiMeta = metaTags.map(meta => ({
|
|
269
|
-
name: meta.getAttribute('name') || meta.getAttribute('property'),
|
|
270
|
-
content: meta.getAttribute('content')
|
|
271
|
-
}));
|
|
272
|
-
// 5. Look for REST patterns
|
|
273
|
-
const restPatterns = [
|
|
274
|
-
'/api/v1', '/api/v2', '/api/v3',
|
|
275
|
-
'/rest/v1', '/rest/v2',
|
|
276
|
-
'/api/users', '/api/products', '/api/data'
|
|
277
|
-
];
|
|
278
|
-
restPatterns.forEach(pattern => {
|
|
279
|
-
const found = document.body.innerHTML.includes(pattern);
|
|
280
|
-
if (found) {
|
|
281
|
-
result.rest.push({
|
|
282
|
-
pattern,
|
|
283
|
-
found: true
|
|
284
|
-
});
|
|
285
|
-
}
|
|
286
|
-
});
|
|
287
|
-
// 6. Check for Swagger/OpenAPI
|
|
288
|
-
const swaggerLinks = Array.from(document.querySelectorAll('a[href*="swagger"], a[href*="openapi"], link[href*="swagger"]'));
|
|
289
|
-
if (swaggerLinks.length > 0) {
|
|
290
|
-
result.swagger = swaggerLinks.map(link => ({
|
|
291
|
-
href: link.href || link.href
|
|
292
|
-
}));
|
|
293
|
-
}
|
|
294
|
-
return result;
|
|
295
|
-
}, deepScan, includeExternal);
|
|
296
|
-
// Deduplicate APIs
|
|
297
|
-
const uniqueAPIs = [...new Set(apiDiscovery.apis.map((api) => api.url))];
|
|
298
|
-
const restFound = apiDiscovery.rest.filter((r) => r.found).length;
|
|
299
|
-
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}`;
|
|
300
|
-
if (apiDiscovery.graphql.length > 0) {
|
|
301
|
-
summary += `\n\nGraphQL:\n- Indicators Found: ${apiDiscovery.graphql[0].indicators}\n- Possible Endpoints: ${apiDiscovery.graphql[0].possibleEndpoints.join(', ')}`;
|
|
302
|
-
}
|
|
303
|
-
if (uniqueAPIs.length > 0) {
|
|
304
|
-
summary += `\n\nUnique APIs (Top 10):\n${uniqueAPIs.slice(0, 10).map((api, i) => `${i + 1}. ${api}`).join('\n')}`;
|
|
305
|
-
}
|
|
306
|
-
if (apiDiscovery.websockets.length > 0) {
|
|
307
|
-
summary += `\n\nWebSockets:\n${apiDiscovery.websockets.map((ws, i) => `${i + 1}. ${ws.url} (${ws.protocol})`).join('\n')}`;
|
|
308
|
-
}
|
|
309
|
-
if (apiDiscovery.documentationLinks?.length > 0) {
|
|
310
|
-
summary += `\n\nDocumentation Links:\n${apiDiscovery.documentationLinks.slice(0, 5).map((link, i) => `${i + 1}. ${link.text}: ${link.href}`).join('\n')}`;
|
|
311
|
-
}
|
|
312
|
-
if (apiDiscovery.swagger?.length > 0) {
|
|
313
|
-
summary += `\n\nSwagger/OpenAPI:\n${apiDiscovery.swagger.map((s, i) => `${i + 1}. ${s.href}`).join('\n')}`;
|
|
314
|
-
}
|
|
315
|
-
return {
|
|
316
|
-
content: [
|
|
317
|
-
{
|
|
318
|
-
type: "text",
|
|
319
|
-
text: summary
|
|
320
|
-
}
|
|
321
|
-
]
|
|
322
|
-
};
|
|
323
|
-
}
|
|
324
|
-
catch (error) {
|
|
325
|
-
return {
|
|
326
|
-
content: [
|
|
327
|
-
{
|
|
328
|
-
type: "text",
|
|
329
|
-
text: `All Website API Finder Error: ${error.message}`
|
|
330
|
-
}
|
|
331
|
-
],
|
|
332
|
-
isError: true
|
|
333
|
-
};
|
|
334
|
-
}
|
|
335
|
-
}
|