brave-real-browser-mcp-server 2.12.6 → 2.12.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/README.md
CHANGED
|
@@ -189,282 +189,6 @@ npx brave-real-browser-mcp-server@latest --mode http --port 3000
|
|
|
189
189
|
💡 [HTTP] Universal mode - works with ALL AI IDEs
|
|
190
190
|
```
|
|
191
191
|
|
|
192
|
-
#### Step 2: Verify WebSocket Connection
|
|
193
|
-
|
|
194
|
-
Test WebSocket connection using browser console or Node.js:
|
|
195
|
-
|
|
196
|
-
**Using Browser Console:**
|
|
197
|
-
|
|
198
|
-
```javascript
|
|
199
|
-
// Open browser console (F12) and paste:
|
|
200
|
-
const ws = new WebSocket('ws://localhost:3000');
|
|
201
|
-
|
|
202
|
-
ws.onopen = () => {
|
|
203
|
-
console.log('✅ WebSocket connected!');
|
|
204
|
-
|
|
205
|
-
// Test tool execution
|
|
206
|
-
ws.send(JSON.stringify({
|
|
207
|
-
id: 1,
|
|
208
|
-
tool: 'browser_init',
|
|
209
|
-
args: {}
|
|
210
|
-
}));
|
|
211
|
-
};
|
|
212
|
-
|
|
213
|
-
ws.onmessage = (event) => {
|
|
214
|
-
console.log('📥 Response:', JSON.parse(event.data));
|
|
215
|
-
};
|
|
216
|
-
|
|
217
|
-
ws.onerror = (error) => {
|
|
218
|
-
console.error('❌ WebSocket error:', error);
|
|
219
|
-
};
|
|
220
|
-
|
|
221
|
-
ws.onclose = () => {
|
|
222
|
-
console.log('🔴 WebSocket disconnected');
|
|
223
|
-
};
|
|
224
|
-
```
|
|
225
|
-
|
|
226
|
-
**Using Node.js:**
|
|
227
|
-
|
|
228
|
-
```javascript
|
|
229
|
-
// Install ws package: npm install ws
|
|
230
|
-
const WebSocket = require('ws');
|
|
231
|
-
|
|
232
|
-
const ws = new WebSocket('ws://localhost:3000');
|
|
233
|
-
|
|
234
|
-
ws.on('open', () => {
|
|
235
|
-
console.log('✅ WebSocket connected!');
|
|
236
|
-
|
|
237
|
-
// Execute a tool
|
|
238
|
-
ws.send(JSON.stringify({
|
|
239
|
-
id: 1,
|
|
240
|
-
tool: 'browser_init',
|
|
241
|
-
args: {}
|
|
242
|
-
}));
|
|
243
|
-
});
|
|
244
|
-
|
|
245
|
-
ws.on('message', (data) => {
|
|
246
|
-
console.log('📥 Response:', JSON.parse(data));
|
|
247
|
-
});
|
|
248
|
-
|
|
249
|
-
ws.on('error', (error) => {
|
|
250
|
-
console.error('❌ Error:', error);
|
|
251
|
-
});
|
|
252
|
-
|
|
253
|
-
ws.on('close', () => {
|
|
254
|
-
console.log('🔴 Connection closed');
|
|
255
|
-
});
|
|
256
|
-
```
|
|
257
|
-
|
|
258
|
-
#### Step 3: WebSocket Message Format
|
|
259
|
-
|
|
260
|
-
**Request Format:**
|
|
261
|
-
|
|
262
|
-
```json
|
|
263
|
-
{
|
|
264
|
-
"id": 1,
|
|
265
|
-
"tool": "tool_name",
|
|
266
|
-
"args": {
|
|
267
|
-
"param1": "value1",
|
|
268
|
-
"param2": "value2"
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
```
|
|
272
|
-
|
|
273
|
-
**Response Format:**
|
|
274
|
-
|
|
275
|
-
```json
|
|
276
|
-
{
|
|
277
|
-
"id": 1,
|
|
278
|
-
"success": true,
|
|
279
|
-
"result": {
|
|
280
|
-
"content": [
|
|
281
|
-
{
|
|
282
|
-
"type": "text",
|
|
283
|
-
"text": "Result data"
|
|
284
|
-
}
|
|
285
|
-
]
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
```
|
|
289
|
-
|
|
290
|
-
**Error Response:**
|
|
291
|
-
|
|
292
|
-
```json
|
|
293
|
-
{
|
|
294
|
-
"id": 1,
|
|
295
|
-
"success": false,
|
|
296
|
-
"error": "Error message"
|
|
297
|
-
}
|
|
298
|
-
```
|
|
299
|
-
|
|
300
|
-
#### Step 4: Example - Complete Browser Automation via WebSocket
|
|
301
|
-
|
|
302
|
-
```javascript
|
|
303
|
-
const WebSocket = require('ws');
|
|
304
|
-
const ws = new WebSocket('ws://localhost:3000');
|
|
305
|
-
|
|
306
|
-
let messageId = 0;
|
|
307
|
-
|
|
308
|
-
function sendCommand(tool, args) {
|
|
309
|
-
return new Promise((resolve, reject) => {
|
|
310
|
-
const id = ++messageId;
|
|
311
|
-
|
|
312
|
-
const handler = (data) => {
|
|
313
|
-
const response = JSON.parse(data);
|
|
314
|
-
if (response.id === id) {
|
|
315
|
-
ws.removeListener('message', handler);
|
|
316
|
-
if (response.success) {
|
|
317
|
-
resolve(response.result);
|
|
318
|
-
} else {
|
|
319
|
-
reject(new Error(response.error));
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
};
|
|
323
|
-
|
|
324
|
-
ws.on('message', handler);
|
|
325
|
-
|
|
326
|
-
ws.send(JSON.stringify({ id, tool, args }));
|
|
327
|
-
});
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
ws.on('open', async () => {
|
|
331
|
-
try {
|
|
332
|
-
// Step 1: Initialize browser
|
|
333
|
-
console.log('Initializing browser...');
|
|
334
|
-
await sendCommand('browser_init', {});
|
|
335
|
-
|
|
336
|
-
// Step 2: Navigate to URL
|
|
337
|
-
console.log('Navigating to page...');
|
|
338
|
-
await sendCommand('navigate', { url: 'https://example.com' });
|
|
339
|
-
|
|
340
|
-
// Step 3: Get page content
|
|
341
|
-
console.log('Getting content...');
|
|
342
|
-
const content = await sendCommand('get_content', { type: 'text' });
|
|
343
|
-
console.log('Content:', content);
|
|
344
|
-
|
|
345
|
-
// Step 4: Close browser
|
|
346
|
-
console.log('Closing browser...');
|
|
347
|
-
await sendCommand('browser_close', {});
|
|
348
|
-
|
|
349
|
-
console.log('✅ Automation complete!');
|
|
350
|
-
ws.close();
|
|
351
|
-
} catch (error) {
|
|
352
|
-
console.error('❌ Error:', error);
|
|
353
|
-
ws.close();
|
|
354
|
-
}
|
|
355
|
-
});
|
|
356
|
-
```
|
|
357
|
-
|
|
358
|
-
#### Step 5: WebSocket Client Libraries
|
|
359
|
-
|
|
360
|
-
**JavaScript/Node.js:**
|
|
361
|
-
```bash
|
|
362
|
-
npm install ws
|
|
363
|
-
```
|
|
364
|
-
|
|
365
|
-
**Python:**
|
|
366
|
-
```bash
|
|
367
|
-
pip install websockets
|
|
368
|
-
```
|
|
369
|
-
|
|
370
|
-
```python
|
|
371
|
-
import asyncio
|
|
372
|
-
import websockets
|
|
373
|
-
import json
|
|
374
|
-
|
|
375
|
-
async def automation():
|
|
376
|
-
uri = "ws://localhost:3000"
|
|
377
|
-
async with websockets.connect(uri) as websocket:
|
|
378
|
-
# Initialize browser
|
|
379
|
-
await websocket.send(json.dumps({
|
|
380
|
-
"id": 1,
|
|
381
|
-
"tool": "browser_init",
|
|
382
|
-
"args": {}
|
|
383
|
-
}))
|
|
384
|
-
response = await websocket.recv()
|
|
385
|
-
print(f"Response: {response}")
|
|
386
|
-
|
|
387
|
-
# Navigate
|
|
388
|
-
await websocket.send(json.dumps({
|
|
389
|
-
"id": 2,
|
|
390
|
-
"tool": "navigate",
|
|
391
|
-
"args": {"url": "https://example.com"}
|
|
392
|
-
}))
|
|
393
|
-
response = await websocket.recv()
|
|
394
|
-
print(f"Response: {response}")
|
|
395
|
-
|
|
396
|
-
asyncio.run(automation())
|
|
397
|
-
```
|
|
398
|
-
|
|
399
|
-
**Go:**
|
|
400
|
-
```bash
|
|
401
|
-
go get github.com/gorilla/websocket
|
|
402
|
-
```
|
|
403
|
-
|
|
404
|
-
```go
|
|
405
|
-
package main
|
|
406
|
-
|
|
407
|
-
import (
|
|
408
|
-
"encoding/json"
|
|
409
|
-
"fmt"
|
|
410
|
-
"github.com/gorilla/websocket"
|
|
411
|
-
)
|
|
412
|
-
|
|
413
|
-
type Message struct {
|
|
414
|
-
ID int `json:"id"`
|
|
415
|
-
Tool string `json:"tool"`
|
|
416
|
-
Args map[string]interface{} `json:"args"`
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
func main() {
|
|
420
|
-
ws, _, err := websocket.DefaultDialer.Dial("ws://localhost:3000", nil)
|
|
421
|
-
if err != nil {
|
|
422
|
-
panic(err)
|
|
423
|
-
}
|
|
424
|
-
defer ws.Close()
|
|
425
|
-
|
|
426
|
-
// Initialize browser
|
|
427
|
-
msg := Message{
|
|
428
|
-
ID: 1,
|
|
429
|
-
Tool: "browser_init",
|
|
430
|
-
Args: make(map[string]interface{}),
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
ws.WriteJSON(msg)
|
|
434
|
-
|
|
435
|
-
var response map[string]interface{}
|
|
436
|
-
ws.ReadJSON(&response)
|
|
437
|
-
fmt.Printf("Response: %+v\n", response)
|
|
438
|
-
}
|
|
439
|
-
```
|
|
440
|
-
|
|
441
|
-
**PHP:**
|
|
442
|
-
```bash
|
|
443
|
-
composer require textalk/websocket
|
|
444
|
-
```
|
|
445
|
-
|
|
446
|
-
```php
|
|
447
|
-
<?php
|
|
448
|
-
require 'vendor/autoload.php';
|
|
449
|
-
|
|
450
|
-
use WebSocket\Client;
|
|
451
|
-
|
|
452
|
-
$client = new Client("ws://localhost:3000");
|
|
453
|
-
|
|
454
|
-
// Initialize browser
|
|
455
|
-
$client->send(json_encode([
|
|
456
|
-
'id' => 1,
|
|
457
|
-
'tool' => 'browser_init',
|
|
458
|
-
'args' => new stdClass()
|
|
459
|
-
]));
|
|
460
|
-
|
|
461
|
-
$response = json_decode($client->receive());
|
|
462
|
-
echo "Response: " . print_r($response, true);
|
|
463
|
-
|
|
464
|
-
$client->close();
|
|
465
|
-
?>
|
|
466
|
-
```
|
|
467
|
-
|
|
468
192
|
#### Step 6: WebSocket Advanced Features
|
|
469
193
|
|
|
470
194
|
**Connection Options:**
|
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`, {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "brave-real-browser-mcp-server",
|
|
3
|
-
"version": "2.12.
|
|
3
|
+
"version": "2.12.7",
|
|
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",
|