brave-real-browser-mcp-server 2.12.6 ā 2.12.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.
- package/README.md +411 -1285
- package/dist/index.js +9 -5
- package/dist/transports/http-transport.js +8 -32
- package/dist/transports/sse-transport.js +8 -32
- package/dist/transports/sse-transport.test.js +9 -5
- package/package.json +15 -7
- package/scripts/patch-puppeteer-screen-recorder.cjs +60 -0
- package/scripts/update-to-latest.cjs +120 -0
package/dist/index.js
CHANGED
|
@@ -111,11 +111,8 @@ server.setRequestHandler(ListPromptsRequestSchema, async () => {
|
|
|
111
111
|
console.error("š [DEBUG] Prompts list requested");
|
|
112
112
|
return { prompts: [] };
|
|
113
113
|
});
|
|
114
|
-
//
|
|
115
|
-
|
|
116
|
-
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
117
|
-
const { name, arguments: args } = request.params;
|
|
118
|
-
console.error(`š [DEBUG] Tool call received: ${name} with args: ${JSON.stringify(args)}`);
|
|
114
|
+
// Tool execution function - exported for use in transports
|
|
115
|
+
export async function executeToolByName(name, args) {
|
|
119
116
|
try {
|
|
120
117
|
let result;
|
|
121
118
|
switch (name) {
|
|
@@ -492,6 +489,13 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
492
489
|
isError: true,
|
|
493
490
|
};
|
|
494
491
|
}
|
|
492
|
+
}
|
|
493
|
+
// Main tool call handler
|
|
494
|
+
console.error("š [DEBUG] Registering tool call handler...");
|
|
495
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
496
|
+
const { name, arguments: args } = request.params;
|
|
497
|
+
console.error(`š [DEBUG] Tool call received: ${name} with args: ${JSON.stringify(args)}`);
|
|
498
|
+
return await executeToolByName(name, args);
|
|
495
499
|
});
|
|
496
500
|
// Main function - now using multi-protocol launcher
|
|
497
501
|
import { main as launcherMain } from "./launcher.js";
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import express from 'express';
|
|
2
2
|
import { createServer } from 'http';
|
|
3
3
|
import { WebSocketServer } from 'ws';
|
|
4
|
-
import { TOOLS
|
|
5
|
-
|
|
4
|
+
import { TOOLS } from '../tool-definitions.js';
|
|
5
|
+
import { executeToolByName } from '../index.js';
|
|
6
|
+
// Import specific handlers for direct endpoints (for backward compatibility)
|
|
6
7
|
import { handleBrowserInit, handleBrowserClose } from '../handlers/browser-handlers.js';
|
|
7
|
-
import { handleNavigate
|
|
8
|
-
import { handleClick, handleType
|
|
9
|
-
import { handleGetContent
|
|
10
|
-
import { handleSaveContentAsMarkdown } from '../handlers/file-handlers.js';
|
|
8
|
+
import { handleNavigate } from '../handlers/navigation-handlers.js';
|
|
9
|
+
import { handleClick, handleType } from '../handlers/interaction-handlers.js';
|
|
10
|
+
import { handleGetContent } from '../handlers/content-handlers.js';
|
|
11
11
|
export class HttpTransport {
|
|
12
12
|
app;
|
|
13
13
|
server = null;
|
|
@@ -128,32 +128,8 @@ export class HttpTransport {
|
|
|
128
128
|
});
|
|
129
129
|
}
|
|
130
130
|
async executeTool(toolName, args) {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
return await handleBrowserInit(args || {});
|
|
134
|
-
case TOOL_NAMES.NAVIGATE:
|
|
135
|
-
return await handleNavigate(args);
|
|
136
|
-
case TOOL_NAMES.GET_CONTENT:
|
|
137
|
-
return await handleGetContent(args || {});
|
|
138
|
-
case TOOL_NAMES.CLICK:
|
|
139
|
-
return await handleClick(args);
|
|
140
|
-
case TOOL_NAMES.TYPE:
|
|
141
|
-
return await handleType(args);
|
|
142
|
-
case TOOL_NAMES.WAIT:
|
|
143
|
-
return await handleWait(args);
|
|
144
|
-
case TOOL_NAMES.BROWSER_CLOSE:
|
|
145
|
-
return await handleBrowserClose();
|
|
146
|
-
case TOOL_NAMES.SOLVE_CAPTCHA:
|
|
147
|
-
return await handleSolveCaptcha(args);
|
|
148
|
-
case TOOL_NAMES.RANDOM_SCROLL:
|
|
149
|
-
return await handleRandomScroll();
|
|
150
|
-
case TOOL_NAMES.FIND_SELECTOR:
|
|
151
|
-
return await handleFindSelector(args);
|
|
152
|
-
case TOOL_NAMES.SAVE_CONTENT_AS_MARKDOWN:
|
|
153
|
-
return await handleSaveContentAsMarkdown(args);
|
|
154
|
-
default:
|
|
155
|
-
throw new Error(`Unknown tool: ${toolName}`);
|
|
156
|
-
}
|
|
131
|
+
// Use universal tool executor from index.ts (supports all 110 tools)
|
|
132
|
+
return await executeToolByName(toolName, args);
|
|
157
133
|
}
|
|
158
134
|
setupWebSocket() {
|
|
159
135
|
if (!this.server || !this.config.enableWebSocket)
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import express from 'express';
|
|
2
2
|
import { createServer } from 'http';
|
|
3
|
-
import { TOOLS
|
|
4
|
-
|
|
3
|
+
import { TOOLS } from '../tool-definitions.js';
|
|
4
|
+
import { executeToolByName } from '../index.js';
|
|
5
|
+
// Import specific handlers for direct endpoints (for backward compatibility)
|
|
5
6
|
import { handleBrowserInit, handleBrowserClose } from '../handlers/browser-handlers.js';
|
|
6
|
-
import { handleNavigate
|
|
7
|
-
import { handleClick, handleType
|
|
8
|
-
import { handleGetContent
|
|
9
|
-
import { handleSaveContentAsMarkdown } from '../handlers/file-handlers.js';
|
|
7
|
+
import { handleNavigate } from '../handlers/navigation-handlers.js';
|
|
8
|
+
import { handleClick, handleType } from '../handlers/interaction-handlers.js';
|
|
9
|
+
import { handleGetContent } from '../handlers/content-handlers.js';
|
|
10
10
|
export class SseTransport {
|
|
11
11
|
app;
|
|
12
12
|
server = null;
|
|
@@ -207,32 +207,8 @@ export class SseTransport {
|
|
|
207
207
|
});
|
|
208
208
|
}
|
|
209
209
|
async executeTool(toolName, args) {
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
return await handleBrowserInit(args || {});
|
|
213
|
-
case TOOL_NAMES.NAVIGATE:
|
|
214
|
-
return await handleNavigate(args);
|
|
215
|
-
case TOOL_NAMES.GET_CONTENT:
|
|
216
|
-
return await handleGetContent(args || {});
|
|
217
|
-
case TOOL_NAMES.CLICK:
|
|
218
|
-
return await handleClick(args);
|
|
219
|
-
case TOOL_NAMES.TYPE:
|
|
220
|
-
return await handleType(args);
|
|
221
|
-
case TOOL_NAMES.WAIT:
|
|
222
|
-
return await handleWait(args);
|
|
223
|
-
case TOOL_NAMES.BROWSER_CLOSE:
|
|
224
|
-
return await handleBrowserClose();
|
|
225
|
-
case TOOL_NAMES.SOLVE_CAPTCHA:
|
|
226
|
-
return await handleSolveCaptcha(args);
|
|
227
|
-
case TOOL_NAMES.RANDOM_SCROLL:
|
|
228
|
-
return await handleRandomScroll();
|
|
229
|
-
case TOOL_NAMES.FIND_SELECTOR:
|
|
230
|
-
return await handleFindSelector(args);
|
|
231
|
-
case TOOL_NAMES.SAVE_CONTENT_AS_MARKDOWN:
|
|
232
|
-
return await handleSaveContentAsMarkdown(args);
|
|
233
|
-
default:
|
|
234
|
-
throw new Error(`Unknown tool: ${toolName}`);
|
|
235
|
-
}
|
|
210
|
+
// Use universal tool executor from index.ts (supports all 110 tools)
|
|
211
|
+
return await executeToolByName(toolName, args);
|
|
236
212
|
}
|
|
237
213
|
sendEvent(res, eventType, data) {
|
|
238
214
|
const eventData = `event: ${eventType}\ndata: ${JSON.stringify(data)}\n\n`;
|
|
@@ -111,9 +111,11 @@ describe('SSE Transport', () => {
|
|
|
111
111
|
body: JSON.stringify({}),
|
|
112
112
|
});
|
|
113
113
|
const data = await response.json();
|
|
114
|
-
|
|
115
|
-
expect(
|
|
116
|
-
expect(data.
|
|
114
|
+
// MCP format: errors are returned in content with isError flag
|
|
115
|
+
expect(response.status).toBe(200);
|
|
116
|
+
expect(data.success).toBe(true);
|
|
117
|
+
expect(data.result.isError).toBe(true);
|
|
118
|
+
expect(data.result.content[0].text).toContain('Unknown tool');
|
|
117
119
|
});
|
|
118
120
|
it('should validate tool arguments', async () => {
|
|
119
121
|
const response = await fetch(`http://${TEST_HOST}:${TEST_PORT}/tools/navigate`, {
|
|
@@ -124,8 +126,10 @@ describe('SSE Transport', () => {
|
|
|
124
126
|
body: JSON.stringify({ /* missing url */}),
|
|
125
127
|
});
|
|
126
128
|
const data = await response.json();
|
|
127
|
-
|
|
128
|
-
expect(
|
|
129
|
+
// MCP format: validation errors are returned with success=true but result.isError=true
|
|
130
|
+
expect(response.status).toBe(200);
|
|
131
|
+
expect(data.success).toBe(true);
|
|
132
|
+
expect(data.result.isError).toBe(true);
|
|
129
133
|
});
|
|
130
134
|
});
|
|
131
135
|
describe('CORS Headers', () => {
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "brave-real-browser-mcp-server",
|
|
3
|
-
"version": "2.12.
|
|
3
|
+
"version": "2.12.8",
|
|
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",
|
|
7
7
|
"scripts": {
|
|
8
|
-
"postinstall": "node scripts/update-to-latest.cjs || echo 'Auto-update skipped'",
|
|
8
|
+
"postinstall": "node scripts/patch-puppeteer-screen-recorder.cjs && node scripts/update-to-latest.cjs || echo 'Auto-update skipped'",
|
|
9
9
|
"clean": "rimraf dist",
|
|
10
10
|
"clean:cache": "npm cache clean --force",
|
|
11
11
|
"fix-cache-permissions": "echo 'Run: sudo chown -R $(whoami):$(id -gn) ~/.npm' && echo 'This fixes npm cache permission issues'",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"axios": "^1.6.5",
|
|
43
43
|
"brave-real-browser": "^1.5.102",
|
|
44
44
|
"brave-real-launcher": "^1.2.18",
|
|
45
|
-
"brave-real-puppeteer-core": "^24.
|
|
45
|
+
"brave-real-puppeteer-core": "^24.26.1",
|
|
46
46
|
"cheerio": "^1.0.0-rc.12",
|
|
47
47
|
"chrono-node": "^2.7.0",
|
|
48
48
|
"compromise": "^14.13.0",
|
|
@@ -53,10 +53,10 @@
|
|
|
53
53
|
"natural": "^6.12.0",
|
|
54
54
|
"pixelmatch": "^5.3.0",
|
|
55
55
|
"pngjs": "^7.0.0",
|
|
56
|
-
"puppeteer-screen-recorder": "^3.0.
|
|
56
|
+
"puppeteer-screen-recorder": "^3.0.6",
|
|
57
57
|
"sentiment": "^5.0.2",
|
|
58
58
|
"tesseract.js": "^5.0.5",
|
|
59
|
-
"turndown": "^7.2.
|
|
59
|
+
"turndown": "^7.2.2",
|
|
60
60
|
"vscode-languageserver": "^9.0.1",
|
|
61
61
|
"vscode-languageserver-textdocument": "^1.0.12",
|
|
62
62
|
"ws": "^8.18.3",
|
|
@@ -117,6 +117,8 @@
|
|
|
117
117
|
},
|
|
118
118
|
"files": [
|
|
119
119
|
"dist/**/*",
|
|
120
|
+
"scripts/**/*",
|
|
121
|
+
".npmrc",
|
|
120
122
|
"README.md",
|
|
121
123
|
"LICENSE"
|
|
122
124
|
],
|
|
@@ -132,7 +134,13 @@
|
|
|
132
134
|
"overrides": {
|
|
133
135
|
"puppeteer": "npm:brave-real-puppeteer-core@latest",
|
|
134
136
|
"puppeteer-core": "npm:brave-real-puppeteer-core@latest",
|
|
135
|
-
"
|
|
136
|
-
|
|
137
|
+
"puppeteer-screen-recorder": {
|
|
138
|
+
"puppeteer": "npm:brave-real-puppeteer-core@latest",
|
|
139
|
+
"fluent-ffmpeg": "latest"
|
|
140
|
+
},
|
|
141
|
+
"fluent-ffmpeg": "latest",
|
|
142
|
+
"glob": "latest",
|
|
143
|
+
"inflight": "latest",
|
|
144
|
+
"tar-fs": "latest"
|
|
137
145
|
}
|
|
138
146
|
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Patch script for puppeteer-screen-recorder
|
|
5
|
+
*
|
|
6
|
+
* This script patches the peerDependencies in puppeteer-screen-recorder's package.json
|
|
7
|
+
* to use brave-real-puppeteer-core instead of the old puppeteer@19.0.0
|
|
8
|
+
*
|
|
9
|
+
* Runs automatically after npm install via postinstall hook
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const fs = require('fs');
|
|
13
|
+
const path = require('path');
|
|
14
|
+
|
|
15
|
+
// Path to puppeteer-screen-recorder's package.json
|
|
16
|
+
const packagePath = path.join(
|
|
17
|
+
process.cwd(),
|
|
18
|
+
'node_modules',
|
|
19
|
+
'puppeteer-screen-recorder',
|
|
20
|
+
'package.json'
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
// Skip if package doesn't exist
|
|
24
|
+
if (!fs.existsSync(packagePath)) {
|
|
25
|
+
console.log('ā¹ļø puppeteer-screen-recorder not found, skipping patch');
|
|
26
|
+
process.exit(0);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
try {
|
|
30
|
+
console.log('š§ Patching puppeteer-screen-recorder peerDependencies...');
|
|
31
|
+
|
|
32
|
+
// Read the package.json
|
|
33
|
+
const packageJson = JSON.parse(fs.readFileSync(packagePath, 'utf8'));
|
|
34
|
+
|
|
35
|
+
// Check if patch is needed
|
|
36
|
+
if (packageJson.peerDependencies && packageJson.peerDependencies.puppeteer) {
|
|
37
|
+
const currentValue = packageJson.peerDependencies.puppeteer;
|
|
38
|
+
|
|
39
|
+
// Only patch if it's the old version
|
|
40
|
+
if (currentValue === '19.0.0' || !currentValue.includes('brave-real-puppeteer-core')) {
|
|
41
|
+
// Update to brave-real-puppeteer-core
|
|
42
|
+
packageJson.peerDependencies.puppeteer = 'npm:brave-real-puppeteer-core@>=24.0.0';
|
|
43
|
+
|
|
44
|
+
// Write back to file
|
|
45
|
+
fs.writeFileSync(packagePath, JSON.stringify(packageJson, null, 2), 'utf8');
|
|
46
|
+
|
|
47
|
+
console.log(' ā puppeteer-screen-recorder patched successfully');
|
|
48
|
+
console.log(' ā peerDependencies.puppeteer: npm:brave-real-puppeteer-core@>=24.0.0');
|
|
49
|
+
} else {
|
|
50
|
+
console.log(' ā puppeteer-screen-recorder already patched');
|
|
51
|
+
}
|
|
52
|
+
} else {
|
|
53
|
+
console.log(' ā ļø No puppeteer peerDependency found');
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
} catch (error) {
|
|
57
|
+
console.error('ā ļø Failed to patch puppeteer-screen-recorder:', error.message);
|
|
58
|
+
console.log('ā¹ļø Continuing anyway...');
|
|
59
|
+
process.exit(0); // Don't fail the install
|
|
60
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Auto-update script for brave-real-browser-mcp-server
|
|
5
|
+
*
|
|
6
|
+
* This script automatically updates all dependencies to their latest versions
|
|
7
|
+
* when npm install is run. It ensures the project always uses the most recent
|
|
8
|
+
* compatible versions while maintaining all functionality.
|
|
9
|
+
*
|
|
10
|
+
* Features:
|
|
11
|
+
* - Updates brave-real-browser to latest
|
|
12
|
+
* - Updates @modelcontextprotocol/sdk to latest
|
|
13
|
+
* - Skips in CI environments to prevent infinite loops
|
|
14
|
+
* - Silent mode to avoid cluttering install output
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
const { execSync } = require('child_process');
|
|
18
|
+
const path = require('path');
|
|
19
|
+
const fs = require('fs');
|
|
20
|
+
|
|
21
|
+
// Skip in CI environments to prevent recursive installs
|
|
22
|
+
const isCIEnvironment = process.env.CI === 'true' ||
|
|
23
|
+
process.env.GITHUB_ACTIONS === 'true' ||
|
|
24
|
+
process.env.SKIP_AUTO_UPDATE === 'true';
|
|
25
|
+
|
|
26
|
+
if (isCIEnvironment) {
|
|
27
|
+
console.log('ā¹ļø Auto-update skipped in CI environment');
|
|
28
|
+
process.exit(0);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Check if we're in the root of the package
|
|
32
|
+
const packageJsonPath = path.join(process.cwd(), 'package.json');
|
|
33
|
+
if (!fs.existsSync(packageJsonPath)) {
|
|
34
|
+
console.log('ā¹ļø Not in package root, skipping auto-update');
|
|
35
|
+
process.exit(0);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
console.log('\nš Auto-updating dependencies to latest versions...\n');
|
|
39
|
+
|
|
40
|
+
// List of packages to always keep at latest version
|
|
41
|
+
const packagesToUpdate = [
|
|
42
|
+
'brave-real-browser',
|
|
43
|
+
'brave-real-launcher',
|
|
44
|
+
'brave-real-puppeteer-core',
|
|
45
|
+
'@modelcontextprotocol/sdk',
|
|
46
|
+
'turndown',
|
|
47
|
+
'@types/turndown',
|
|
48
|
+
'puppeteer-screen-recorder',
|
|
49
|
+
'rimraf'
|
|
50
|
+
];
|
|
51
|
+
|
|
52
|
+
try {
|
|
53
|
+
// Update each package to latest
|
|
54
|
+
for (const pkg of packagesToUpdate) {
|
|
55
|
+
try {
|
|
56
|
+
console.log(` Updating ${pkg}...`);
|
|
57
|
+
execSync(`npm install ${pkg}@latest --save --no-audit --no-fund`, {
|
|
58
|
+
stdio: 'pipe',
|
|
59
|
+
cwd: process.cwd()
|
|
60
|
+
});
|
|
61
|
+
console.log(` ā ${pkg} updated to latest`);
|
|
62
|
+
} catch (error) {
|
|
63
|
+
console.log(` ā ļø Could not update ${pkg} (non-critical)`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
console.log('\nā
All dependencies updated to latest versions!\n');
|
|
68
|
+
|
|
69
|
+
// Show current versions
|
|
70
|
+
console.log('š¦ Current versions:');
|
|
71
|
+
for (const pkg of packagesToUpdate) {
|
|
72
|
+
try {
|
|
73
|
+
const version = execSync(`npm list ${pkg} --depth=0 --json`, {
|
|
74
|
+
stdio: 'pipe',
|
|
75
|
+
encoding: 'utf8'
|
|
76
|
+
});
|
|
77
|
+
const parsed = JSON.parse(version);
|
|
78
|
+
const installedVersion = parsed.dependencies?.[pkg]?.version || 'not found';
|
|
79
|
+
console.log(` ${pkg}: ${installedVersion}`);
|
|
80
|
+
} catch (error) {
|
|
81
|
+
// Ignore errors
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Step 4: Run npm audit fix to resolve security vulnerabilities
|
|
86
|
+
console.log('\nš Running security audit fix...');
|
|
87
|
+
try {
|
|
88
|
+
execSync('npm audit fix --force', {
|
|
89
|
+
stdio: 'pipe',
|
|
90
|
+
cwd: process.cwd()
|
|
91
|
+
});
|
|
92
|
+
console.log(' ā Security vulnerabilities fixed');
|
|
93
|
+
} catch (error) {
|
|
94
|
+
// Check if there are still vulnerabilities
|
|
95
|
+
try {
|
|
96
|
+
const auditResult = execSync('npm audit --json', {
|
|
97
|
+
stdio: 'pipe',
|
|
98
|
+
encoding: 'utf8'
|
|
99
|
+
});
|
|
100
|
+
const audit = JSON.parse(auditResult);
|
|
101
|
+
if (audit.metadata && audit.metadata.vulnerabilities) {
|
|
102
|
+
const total = audit.metadata.vulnerabilities.total || 0;
|
|
103
|
+
if (total === 0) {
|
|
104
|
+
console.log(' ā No security vulnerabilities found');
|
|
105
|
+
} else {
|
|
106
|
+
console.log(` ā ļø ${total} vulnerabilities remaining (may require manual review)`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
} catch (auditError) {
|
|
110
|
+
console.log(' ā¹ļø Security audit completed');
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
console.log('');
|
|
115
|
+
|
|
116
|
+
} catch (error) {
|
|
117
|
+
console.error('ā ļø Auto-update encountered an error:', error.message);
|
|
118
|
+
console.log('ā¹ļø Continuing with current versions...\n');
|
|
119
|
+
process.exit(0); // Don't fail the install
|
|
120
|
+
}
|