browser-console-mcp 1.0.0

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.
@@ -0,0 +1,154 @@
1
+ /**
2
+ * Browser Console MCP Server
3
+ *
4
+ * This server runs in Cursor and handles commands from the browser console
5
+ */
6
+ import { exec } from "node:child_process";
7
+ import * as http from "node:http";
8
+ import "node:process";
9
+ import { WebSocketServer } from "ws";
10
+ import { StaticFileServer } from "./static-server.js";
11
+ class BrowserConsoleMCPServer {
12
+ constructor(port = 3000, staticPort = 3001) {
13
+ this.clients = new Map();
14
+ this.port = port;
15
+ // Create HTTP server
16
+ this.httpServer = http.createServer((req, res) => {
17
+ // Redirect to static server
18
+ res.writeHead(302, {
19
+ Location: `http://localhost:${staticPort}${req.url}`,
20
+ });
21
+ res.end();
22
+ });
23
+ // Attach WebSocket server to HTTP server
24
+ this.wss = new WebSocketServer({
25
+ server: this.httpServer,
26
+ path: "/ws", // Specify WebSocket path
27
+ });
28
+ this.staticServer = new StaticFileServer(staticPort);
29
+ }
30
+ /**
31
+ * Start server
32
+ */
33
+ start() {
34
+ this.setupWebSocketServer();
35
+ this.staticServer.start();
36
+ // Start HTTP server
37
+ this.httpServer.listen(this.port, () => {
38
+ console.info(`[MCP Server] HTTP server started on port ${this.port}`);
39
+ console.info(`[MCP Server] WebSocket server path: ws://localhost:${this.port}/ws`);
40
+ console.info(`[MCP Server] Static files will be redirected to port ${this.staticServer.getPort()}`);
41
+ });
42
+ }
43
+ /**
44
+ * Setup WebSocket server
45
+ */
46
+ setupWebSocketServer() {
47
+ this.wss.on("connection", (ws) => {
48
+ const clientId = this.generateClientId();
49
+ this.clients.set(clientId, { id: clientId, ws });
50
+ console.info(`[MCP Server] Client ${clientId} connected`);
51
+ ws.on("message", (data) => {
52
+ try {
53
+ const message = JSON.parse(data.toString());
54
+ this.handleClientMessage(clientId, message);
55
+ }
56
+ catch (error) {
57
+ console.error("[MCP Server] Message parsing error:", error);
58
+ }
59
+ });
60
+ ws.on("close", () => {
61
+ this.clients.delete(clientId);
62
+ console.info(`[MCP Server] Client ${clientId} disconnected`);
63
+ });
64
+ ws.on("error", (error) => {
65
+ console.error(`[MCP Server] WebSocket error (client ${clientId}):`, error);
66
+ });
67
+ });
68
+ this.wss.on("error", (error) => {
69
+ console.error("[MCP Server] WebSocket server error:", error);
70
+ });
71
+ }
72
+ /**
73
+ * Handle client messages
74
+ */
75
+ handleClientMessage(clientId, message) {
76
+ const client = this.clients.get(clientId);
77
+ if (!client) {
78
+ console.error(`[MCP Server] Client not found: ${clientId}`);
79
+ return;
80
+ }
81
+ // Only log message type, not the full message content
82
+ console.info(`[MCP Server] Received message type ${message.type} from client ${clientId}`);
83
+ switch (message.type) {
84
+ case "command":
85
+ this.executeCommand(client, message.payload?.command);
86
+ break;
87
+ default:
88
+ this.sendErrorToClient(client, `Unknown message type: ${message.type}`);
89
+ }
90
+ }
91
+ /**
92
+ * Execute command
93
+ */
94
+ executeCommand(client, command) {
95
+ if (!command) {
96
+ this.sendErrorToClient(client, "Command is empty");
97
+ return;
98
+ }
99
+ console.info(`[MCP Server] Executing command: ${command}`);
100
+ exec(command, (error, stdout, stderr) => {
101
+ if (error) {
102
+ this.sendErrorToClient(client, `Command execution error: ${error.message}`);
103
+ return;
104
+ }
105
+ const result = stdout || stderr;
106
+ this.sendResultToClient(client, result);
107
+ });
108
+ }
109
+ /**
110
+ * Send result to client
111
+ */
112
+ sendResultToClient(client, result) {
113
+ const message = {
114
+ type: "command_result",
115
+ payload: { result },
116
+ };
117
+ client.ws.send(JSON.stringify(message));
118
+ }
119
+ /**
120
+ * Send error to client
121
+ */
122
+ sendErrorToClient(client, error) {
123
+ const message = {
124
+ type: "error",
125
+ payload: { error },
126
+ };
127
+ client.ws.send(JSON.stringify(message));
128
+ }
129
+ /**
130
+ * Generate client ID
131
+ */
132
+ generateClientId() {
133
+ return `client_${Date.now()}_${Math.floor(Math.random() * 1000)}`;
134
+ }
135
+ /**
136
+ * Stop server
137
+ */
138
+ stop() {
139
+ this.httpServer.close();
140
+ this.wss.close();
141
+ this.staticServer.stop();
142
+ console.info("[MCP Server] Server closed");
143
+ }
144
+ }
145
+ // Create and start server instance
146
+ const server = new BrowserConsoleMCPServer();
147
+ server.start();
148
+ // Handle process exit
149
+ process.on("SIGINT", () => {
150
+ console.info("[MCP Server] Shutting down server...");
151
+ server.stop();
152
+ process.exit(0);
153
+ });
154
+ export default server;
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Static File Server
3
+ *
4
+ * Used to serve client JS files
5
+ */
6
+ export declare class StaticFileServer {
7
+ private server;
8
+ private port;
9
+ private clientJsPath;
10
+ constructor(port?: number, clientJsPath?: string);
11
+ /**
12
+ * Get server port
13
+ */
14
+ getPort(): number;
15
+ /**
16
+ * Handle HTTP requests
17
+ */
18
+ private handleRequest;
19
+ /**
20
+ * Serve client JS file
21
+ */
22
+ private serveClientJs;
23
+ /**
24
+ * Serve index page
25
+ */
26
+ private serveIndexPage;
27
+ /**
28
+ * Serve html2canvas file
29
+ */
30
+ private serveStaticFile;
31
+ /**
32
+ * Start server
33
+ */
34
+ start(): void;
35
+ /**
36
+ * Stop server
37
+ */
38
+ stop(): void;
39
+ /**
40
+ * Get content type based on file extension
41
+ */
42
+ private getContentType;
43
+ }
44
+ export default StaticFileServer;
@@ -0,0 +1,205 @@
1
+ /**
2
+ * Static File Server
3
+ *
4
+ * Used to serve client JS files
5
+ */
6
+ import * as fs from "node:fs";
7
+ import * as http from "node:http";
8
+ import * as path from "node:path";
9
+ export class StaticFileServer {
10
+ constructor(port = 3001, clientJsPath = path.join(process.cwd(), "dist", "client", "browser-console-mcp.js")) {
11
+ this.port = port;
12
+ this.clientJsPath = clientJsPath;
13
+ this.server = http.createServer(this.handleRequest.bind(this));
14
+ }
15
+ /**
16
+ * Get server port
17
+ */
18
+ getPort() {
19
+ return this.port;
20
+ }
21
+ /**
22
+ * Handle HTTP requests
23
+ */
24
+ handleRequest(req, res) {
25
+ // Set CORS headers, allow access from any origin
26
+ res.setHeader("Access-Control-Allow-Origin", "*");
27
+ res.setHeader("Access-Control-Allow-Methods", "GET, OPTIONS");
28
+ res.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
29
+ // Handle preflight requests
30
+ if (req.method === "OPTIONS") {
31
+ res.writeHead(204);
32
+ res.end();
33
+ return;
34
+ }
35
+ // Only handle GET requests
36
+ if (req.method !== "GET") {
37
+ res.writeHead(405, { "Content-Type": "text/plain" });
38
+ res.end("Method Not Allowed");
39
+ return;
40
+ }
41
+ // Get request path
42
+ const requestPath = req.url || "/";
43
+ // Serve client JS file
44
+ if (requestPath === "/browser-console-mcp.js") {
45
+ this.serveClientJs(res);
46
+ }
47
+ // Serve html2canvas file
48
+ else if (requestPath === "/html2canvas.min.js") {
49
+ this.serveStaticFile(path.join(process.cwd(), "dist", "static", "html2canvas.min.js"), "application/javascript", res);
50
+ }
51
+ // Try to serve files from static directory
52
+ else if (requestPath.startsWith("/static/")) {
53
+ const filePath = path.join(process.cwd(), "dist", requestPath);
54
+ const contentType = this.getContentType(filePath);
55
+ this.serveStaticFile(filePath, contentType, res);
56
+ }
57
+ else {
58
+ // Return a simple HTML page explaining how to use
59
+ this.serveIndexPage(res);
60
+ }
61
+ }
62
+ /**
63
+ * Serve client JS file
64
+ */
65
+ serveClientJs(res) {
66
+ this.serveStaticFile(this.clientJsPath, "application/javascript", res);
67
+ }
68
+ /**
69
+ * Serve index page
70
+ */
71
+ serveIndexPage(res) {
72
+ const html = `
73
+ <!DOCTYPE html>
74
+ <html lang="en">
75
+ <head>
76
+ <meta charset="UTF-8">
77
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
78
+ <title>Browser Console MCP</title>
79
+ <style>
80
+ body {
81
+ font-family: Arial, sans-serif;
82
+ line-height: 1.6;
83
+ max-width: 800px;
84
+ margin: 0 auto;
85
+ padding: 20px;
86
+ }
87
+ pre {
88
+ background-color: #f5f5f5;
89
+ padding: 10px;
90
+ border-radius: 5px;
91
+ overflow-x: auto;
92
+ }
93
+ code {
94
+ font-family: monospace;
95
+ }
96
+ </style>
97
+ </head>
98
+ <body>
99
+ <h1>Browser Console MCP</h1>
100
+ <p>This is the Browser Console MCP static file server.</p>
101
+ <p>Client JS file is available at the following URL:</p>
102
+ <pre><code>http://localhost:${this.port}/browser-console-mcp.js</code></pre>
103
+
104
+ <h2>Usage</h2>
105
+ <p>Paste the following code in your browser console:</p>
106
+ <pre><code>// Load client script
107
+ const script = document.createElement('script');
108
+ script.src = 'http://localhost:${this.port}/browser-console-mcp.js';
109
+ document.head.appendChild(script);</code></pre>
110
+
111
+ <p>Then interact with the server using these commands:</p>
112
+ <pre><code>// Execute command
113
+ mcp.exec('ls -la');
114
+
115
+ // View help
116
+ mcp.help();
117
+
118
+ // Disconnect
119
+ mcp.disconnect();
120
+
121
+ // Reconnect
122
+ mcp.reconnect();</code></pre>
123
+ </body>
124
+ </html>
125
+ `;
126
+ res.writeHead(200, { "Content-Type": "text/html" });
127
+ res.end(html);
128
+ }
129
+ /**
130
+ * Serve html2canvas file
131
+ */
132
+ serveStaticFile(filePath, contentType, res) {
133
+ try {
134
+ if (fs.existsSync(filePath)) {
135
+ const fileContent = fs.readFileSync(filePath);
136
+ // Set correct content type and cache control headers
137
+ res.writeHead(200, {
138
+ "Content-Type": contentType,
139
+ "Cache-Control": "no-cache, no-store, must-revalidate",
140
+ Pragma: "no-cache",
141
+ Expires: "0",
142
+ });
143
+ res.end(fileContent);
144
+ console.info(`[Static Server] Successfully served static file: ${filePath}`);
145
+ }
146
+ else {
147
+ console.error(`[Static Server] Static file not found: ${filePath}`);
148
+ res.writeHead(404, { "Content-Type": "text/plain" });
149
+ res.end("File not found");
150
+ }
151
+ }
152
+ catch (error) {
153
+ console.error("[Static Server] Error serving static file:", error);
154
+ res.writeHead(500, { "Content-Type": "text/plain" });
155
+ res.end("Internal Server Error");
156
+ }
157
+ }
158
+ /**
159
+ * Start server
160
+ */
161
+ start() {
162
+ this.server.listen(this.port, () => {
163
+ console.info(`[Static Server] Server started, listening on port ${this.port}`);
164
+ console.info(`[Static Server] Client JS file URL: http://localhost:${this.port}/browser-console-mcp.js`);
165
+ });
166
+ }
167
+ /**
168
+ * Stop server
169
+ */
170
+ stop() {
171
+ this.server.close(() => {
172
+ console.info("[Static Server] Server closed");
173
+ });
174
+ }
175
+ /**
176
+ * Get content type based on file extension
177
+ */
178
+ getContentType(filePath) {
179
+ const ext = path.extname(filePath).toLowerCase();
180
+ switch (ext) {
181
+ case ".html":
182
+ return "text/html";
183
+ case ".js":
184
+ return "application/javascript";
185
+ case ".css":
186
+ return "text/css";
187
+ case ".json":
188
+ return "application/json";
189
+ case ".png":
190
+ return "image/png";
191
+ case ".jpg":
192
+ case ".jpeg":
193
+ return "image/jpeg";
194
+ case ".gif":
195
+ return "image/gif";
196
+ case ".svg":
197
+ return "image/svg+xml";
198
+ case ".ico":
199
+ return "image/x-icon";
200
+ default:
201
+ return "application/octet-stream";
202
+ }
203
+ }
204
+ }
205
+ export default StaticFileServer;