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
- // Main tool call handler
115
- console.error("🔍 [DEBUG] Registering tool call handler...");
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, TOOL_NAMES } from '../tool-definitions.js';
5
- // Import all handlers
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, handleWait } from '../handlers/navigation-handlers.js';
8
- import { handleClick, handleType, handleSolveCaptcha, handleRandomScroll } from '../handlers/interaction-handlers.js';
9
- import { handleGetContent, handleFindSelector } from '../handlers/content-handlers.js';
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
- switch (toolName) {
132
- case TOOL_NAMES.BROWSER_INIT:
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, TOOL_NAMES } from '../tool-definitions.js';
4
- // Import all handlers
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, handleWait } from '../handlers/navigation-handlers.js';
7
- import { handleClick, handleType, handleSolveCaptcha, handleRandomScroll } from '../handlers/interaction-handlers.js';
8
- import { handleGetContent, handleFindSelector } from '../handlers/content-handlers.js';
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
- switch (toolName) {
211
- case TOOL_NAMES.BROWSER_INIT:
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
- expect(response.status).toBe(500);
115
- expect(data.success).toBe(false);
116
- expect(data.error).toContain('Unknown tool');
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.6",
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",