browser-console-mcp 1.0.9 → 1.1.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.
@@ -1,2 +1,2 @@
1
- var BrowserConsoleMCP=function(){"use strict";const e=new class{constructor(e="ws://localhost:7898/browser"){this.ws=null,this.connected=!1,this.commandHistory=[],this.historyIndex=-1,this.serverUrl=e}connect(){try{this.loadHtml2Canvas().then((()=>{this.ws=new WebSocket(this.serverUrl),this.ws.onopen=()=>{this.connected=!0,console.log("%c[MCP Client] Connected to server","color: green"),this.registerConsoleCommands()},this.ws.onmessage=e=>{try{const t=JSON.parse(e.data);this.handleServerMessage(t)}catch(e){console.error("[MCP Client] Message parsing error:",e)}},this.ws.onclose=()=>{this.connected=!1,console.log("%c[MCP Client] Disconnected from server","color: orange")},this.ws.onerror=e=>{console.error("[MCP Client] WebSocket error:",e)}})).catch((e=>{console.error("[MCP Client] Failed to load html2canvas:",e)}))}catch(e){console.error("[MCP Client] Connection error:",e)}}loadHtml2Canvas(){return new Promise(((e,t)=>{if(void 0!==window.html2canvas)return console.log("[MCP Client] html2canvas already loaded"),void e(!0);console.log("[MCP Client] Loading html2canvas...");const n=document.createElement("script");n.src="https://html2canvas.hertzen.com/dist/html2canvas.min.js",n.onload=()=>{console.log("[MCP Client] html2canvas loaded from CDN"),e(!0)},n.onerror=()=>{console.log("[MCP Client] Trying local path for html2canvas...");const n=document.createElement("script");n.src="/html2canvas.min.js",n.onload=()=>{console.log("[MCP Client] html2canvas loaded from local path"),e(!0)},n.onerror=n=>{console.log("[MCP Client] Trying unpkg CDN for html2canvas...");const o=document.createElement("script");o.src="https://unpkg.com/html2canvas/dist/html2canvas.min.js",o.onload=()=>{console.log("[MCP Client] html2canvas loaded from unpkg CDN"),e(!0)},o.onerror=e=>{console.error("[MCP Client] Failed to load html2canvas:",e),t(new Error("Unable to load html2canvas library, please ensure your network connection is working"))},document.head.appendChild(o)},document.head.appendChild(n)},document.head.appendChild(n)}))}handleServerMessage(e){if("get_page_html"!==e.type)if("execute_js"!==e.type)if("get_page_title"!==e.type)if("get_elements"!==e.type)if("capture_screenshot"!==e.type)if("get_page_url"!==e.type)if("click_element"!==e.type)if("input_text"!==e.type)switch(e.type){case"command_result":console.log(`%c[MCP Server] ${e.payload?.result}`,"color: blue");break;case"error":console.error(`[MCP Server] Error: ${e.payload?.error}`);break;case"connection_status":console.log(`%c[MCP Server] ${e.message}`,"color: green");break;default:console.log(`[MCP Server] Received message type: ${e.type}`)}else{const t=e.requestId,n=e.selector,o=e.text;try{const e=document.querySelector(n);if(!e)return void this.sendError(t,`Input field not found: ${n}`);if("INPUT"!==e.tagName&&"TEXTAREA"!==e.tagName)return void this.sendError(t,`Selected element is not an input field: ${e.tagName}`);e.value=o,e.dispatchEvent(new Event("input",{bubbles:!0})),this.sendResponse(t,{success:!0,message:`Successfully input text to: ${n}`})}catch(e){this.sendError(t,`Error inputting text: ${e.message}`)}}else{const t=e.requestId,n=e.selector;try{const e=document.querySelector(n);if(!e)return void this.sendError(t,`Element not found: ${n}`);e.click(),this.sendResponse(t,{success:!0,message:`Successfully clicked element: ${n}`})}catch(e){this.sendError(t,`Error clicking element: ${e.message}`)}}else{const t=e.requestId;try{const e=window.location.href;this.sendResponse(t,{url:e})}catch(e){this.sendError(t,`Error getting URL: ${e.message}`)}}else{const t=e.requestId,n=e.selector||"body";(async()=>{try{await this.loadHtml2Canvas();const e=document.querySelector(n);if(!e)return void this.sendError(t,`Element not found: ${n}`);const o={allowTaint:!0,useCORS:!0,logging:!1,scale:window.devicePixelRatio||1,backgroundColor:null,removeContainer:!0,x:0,y:0,scrollX:0,scrollY:0,width:e.offsetWidth,height:e.offsetHeight},s=window.html2canvas;if(!s)return void this.sendError(t,"html2canvas library not properly loaded");let r=await s(e,o);if(!r)return void this.sendError(t,"Screenshot failed: unable to create canvas");const c=r.getContext("2d");if(c){const e=c.getImageData(0,0,r.width,r.height),t=this.getContentBounds(e);if(t){const e=document.createElement("canvas");e.width=t.width,e.height=t.height;const n=e.getContext("2d");n&&(n.drawImage(r,t.left,t.top,t.width,t.height,0,0,t.width,t.height),r=e)}}const i=r.toDataURL("image/png");this.sendResponse(t,{imageDataUrl:i})}catch(e){console.error("[MCP Client] Screenshot error:",e),this.sendError(t,`Screenshot error: ${e.message}`)}})()}else{const t=e.requestId,n=e.selector;try{const e=[...document.querySelectorAll(n)].map((e=>({tagName:e.tagName,id:e.id,className:e.className,textContent:e.textContent?.trim().substring(0,500)||"",attributes:[...e.attributes].reduce(((e,t)=>(e[t.name]=t.value,e)),{})})));this.sendResponse(t,{elements:e})}catch(e){this.sendError(t,`Error getting elements: ${e.message}`)}}else{const t=e.requestId;try{const e=document.title;this.sendResponse(t,{title:e})}catch(e){this.sendError(t,`Error getting title: ${e.message}`)}}else{const t=e.requestId,n=e.code;try{const e=new Function(n)();let o;try{o=JSON.stringify(e)}catch(t){o=String(e)}const s={requestId:t,result:o};this.ws?.send(JSON.stringify(s))}catch(e){console.error("[MCP Client] Error executing JavaScript:",e),this.sendError(t,`Error executing JavaScript: ${e.message}`)}}else{const t=e.requestId;try{const e=document.documentElement.outerHTML;this.sendResponse(t,{html:e})}catch(e){this.sendError(t,`Error getting HTML: ${e.message}`)}}}sendResponse(e,t){if(!this.connected||!this.ws)return void console.error("[MCP Client] Not connected to server, cannot send response");const n={requestId:e,...t};this.ws.send(JSON.stringify(n))}sendError(e,t){if(!this.connected||!this.ws)return void console.error("[MCP Client] Not connected to server, cannot send error response");const n={requestId:e,error:t};this.ws.send(JSON.stringify(n))}sendCommand(e){if(!this.connected||!this.ws)return void console.error("[MCP Client] Not connected to server");const t={type:"command",payload:{command:e}};this.ws.send(JSON.stringify(t)),this.commandHistory.push(e),this.historyIndex=this.commandHistory.length}registerConsoleCommands(){window.mcp={exec:e=>(this.sendCommand(e),"Command sent"),disconnect:()=>(this.ws&&(this.ws.close(),this.ws=null),"Disconnected"),reconnect:()=>(this.connect(),"Reconnecting..."),help:()=>"\nMCP Client Commands:\n mcp.exec(command) - Execute a command\n mcp.disconnect() - Disconnect from server\n mcp.reconnect() - Reconnect to server\n mcp.help() - Show help information\n "},console.log("%c[MCP Client] Console commands registered, use mcp.help() to see available commands","color: green")}getContentBounds(e){const{width:t,height:n,data:o}=e;let s=t,r=n,c=0,i=0,a=!1;for(let e=0;e<n;e++)for(let n=0;n<t;n++){o[4*(e*t+n)+3]>10&&(a=!0,s=Math.min(s,n),r=Math.min(r,e),c=Math.max(c,n),i=Math.max(i,e))}if(!a)return null;return s=Math.max(0,s-10),r=Math.max(0,r-10),c=Math.min(t-1,c+10),i=Math.min(n-1,i+10),{left:s,top:r,width:c-s+1,height:i-r+1}}};return e.connect(),e}();
1
+ var BrowserConsoleMCP=function(){"use strict";const e=new class{constructor(e="ws://localhost:7898/browser"){this.ws=null,this.connected=!1,this.serverUrl=e}connect(){try{this.loadHtml2Canvas().then((()=>{this.ws=new WebSocket(this.serverUrl),this.ws.onopen=()=>{this.connected=!0,console.log("%c[MCP Client] Connected to server","color: green"),this.registerConsoleCommands()},this.ws.onmessage=e=>{try{const t=JSON.parse(e.data);this.handleServerMessage(t)}catch(e){console.error("[MCP Client] Message parsing error:",e)}},this.ws.onclose=()=>{this.connected=!1,console.log("%c[MCP Client] Disconnected from server","color: orange")},this.ws.onerror=e=>{console.error("[MCP Client] WebSocket error:",e)}})).catch((e=>{console.error("[MCP Client] Failed to load html2canvas:",e)}))}catch(e){console.error("[MCP Client] Connection error:",e)}}loadHtml2Canvas(){return new Promise(((e,t)=>{if(void 0!==window.html2canvas)return console.log("[MCP Client] html2canvas already loaded"),void e(!0);console.log("[MCP Client] Loading html2canvas...");const n=document.createElement("script");n.src="https://html2canvas.hertzen.com/dist/html2canvas.min.js",n.onload=()=>{console.log("[MCP Client] html2canvas loaded from CDN"),e(!0)},n.onerror=()=>{console.log("[MCP Client] Trying local path for html2canvas...");const n=document.createElement("script");n.src="/html2canvas.min.js",n.onload=()=>{console.log("[MCP Client] html2canvas loaded from local path"),e(!0)},n.onerror=n=>{console.log("[MCP Client] Trying unpkg CDN for html2canvas...");const o=document.createElement("script");o.src="https://unpkg.com/html2canvas/dist/html2canvas.min.js",o.onload=()=>{console.log("[MCP Client] html2canvas loaded from unpkg CDN"),e(!0)},o.onerror=e=>{console.error("[MCP Client] Failed to load html2canvas:",e),t(new Error("Unable to load html2canvas library, please ensure your network connection is working"))},document.head.appendChild(o)},document.head.appendChild(n)},document.head.appendChild(n)}))}handleServerMessage(e){if("get_page_html"!==e.type)if("execute_js"!==e.type)if("get_page_title"!==e.type)if("get_elements"!==e.type)if("capture_screenshot"!==e.type)if("get_page_url"!==e.type)if("click_element"!==e.type)if("input_text"!==e.type)switch(e.type){case"command_result":console.log(`%c[MCP Server] ${e.payload?.result}`,"color: blue");break;case"error":console.error(`[MCP Server] Error: ${e.payload?.error}`);break;case"connection_status":console.log(`%c[MCP Server] ${e.message}`,"color: green");break;default:console.log(`[MCP Server] Received message type: ${e.type}`)}else{const t=e.requestId,n=e.selector,o=e.text;try{const e=document.querySelector(n);if(!e)return void this.sendError(t,`Input field not found: ${n}`);if("INPUT"!==e.tagName&&"TEXTAREA"!==e.tagName)return void this.sendError(t,`Selected element is not an input field: ${e.tagName}`);e.value=o,e.dispatchEvent(new Event("input",{bubbles:!0})),this.sendResponse(t,{success:!0,message:`Successfully input text to: ${n}`})}catch(e){this.sendError(t,`Error inputting text: ${e.message}`)}}else{const t=e.requestId,n=e.selector;try{const e=document.querySelector(n);if(!e)return void this.sendError(t,`Element not found: ${n}`);e.click(),this.sendResponse(t,{success:!0,message:`Successfully clicked element: ${n}`})}catch(e){this.sendError(t,`Error clicking element: ${e.message}`)}}else{const t=e.requestId;try{const e=window.location.href;this.sendResponse(t,{url:e})}catch(e){this.sendError(t,`Error getting URL: ${e.message}`)}}else{const t=e.requestId,n=e.selector||"body";(async()=>{try{await this.loadHtml2Canvas();const e=document.querySelector(n);if(!e)return void this.sendError(t,`Element not found: ${n}`);const o={allowTaint:!0,useCORS:!0,logging:!1,scale:window.devicePixelRatio||1,backgroundColor:null,removeContainer:!0,x:0,y:0,scrollX:0,scrollY:0,width:e.offsetWidth,height:e.offsetHeight},s=window.html2canvas;if(!s)return void this.sendError(t,"html2canvas library not properly loaded");let r=await s(e,o);if(!r)return void this.sendError(t,"Screenshot failed: unable to create canvas");const c=r.getContext("2d");if(c){const e=c.getImageData(0,0,r.width,r.height),t=this.getContentBounds(e);if(t){const e=document.createElement("canvas");e.width=t.width,e.height=t.height;const n=e.getContext("2d");n&&(n.drawImage(r,t.left,t.top,t.width,t.height,0,0,t.width,t.height),r=e)}}const i=r.toDataURL("image/png");this.sendResponse(t,{imageDataUrl:i})}catch(e){console.error("[MCP Client] Screenshot error:",e),this.sendError(t,`Screenshot error: ${e.message}`)}})()}else{const t=e.requestId,n=e.selector;try{const e=[...document.querySelectorAll(n)].map((e=>({tagName:e.tagName,id:e.id,className:e.className,textContent:e.textContent?.trim().substring(0,500)||"",attributes:[...e.attributes].reduce(((e,t)=>(e[t.name]=t.value,e)),{})})));this.sendResponse(t,{elements:e})}catch(e){this.sendError(t,`Error getting elements: ${e.message}`)}}else{const t=e.requestId;try{const e=document.title;this.sendResponse(t,{title:e})}catch(e){this.sendError(t,`Error getting title: ${e.message}`)}}else{const t=e.requestId,n=e.code;try{const e=new Function(n)();let o;try{o=JSON.stringify(e)}catch(t){o=String(e)}const s={requestId:t,result:o};this.ws?.send(JSON.stringify(s))}catch(e){console.error("[MCP Client] Error executing JavaScript:",e),this.sendError(t,`Error executing JavaScript: ${e.message}`)}}else{const t=e.requestId;try{const e=document.documentElement.outerHTML;this.sendResponse(t,{html:e})}catch(e){this.sendError(t,`Error getting HTML: ${e.message}`)}}}sendResponse(e,t){if(!this.connected||!this.ws)return void console.error("[MCP Client] Not connected to server, cannot send response");const n={requestId:e,...t};this.ws.send(JSON.stringify(n))}sendError(e,t){if(!this.connected||!this.ws)return void console.error("[MCP Client] Not connected to server, cannot send error response");const n={requestId:e,error:t};this.ws.send(JSON.stringify(n))}sendCommand(e){if(!this.connected||!this.ws)return void console.error("[MCP Client] Not connected to server");const t={type:"command",payload:{command:e}};this.ws.send(JSON.stringify(t))}registerConsoleCommands(){window.mcp={exec:e=>(this.sendCommand(e),"Command sent"),disconnect:()=>(this.ws&&(this.ws.close(),this.ws=null),"Disconnected"),reconnect:()=>(this.connect(),"Reconnecting..."),help:()=>"\nMCP Client Commands:\n mcp.exec(command) - Execute a command\n mcp.disconnect() - Disconnect from server\n mcp.reconnect() - Reconnect to server\n mcp.help() - Show help information\n "},console.log("%c[MCP Client] Console commands registered, use mcp.help() to see available commands","color: green")}getContentBounds(e){const{width:t,height:n,data:o}=e;let s=t,r=n,c=0,i=0,a=!1;for(let e=0;e<n;e++)for(let n=0;n<t;n++){o[4*(e*t+n)+3]>10&&(a=!0,s=Math.min(s,n),r=Math.min(r,e),c=Math.max(c,n),i=Math.max(i,e))}if(!a)return null;return s=Math.max(0,s-10),r=Math.max(0,r-10),c=Math.min(t-1,c+10),i=Math.min(n-1,i+10),{left:s,top:r,width:c-s+1,height:i-r+1}}};return e.connect(),e}();
2
2
  //# sourceMappingURL=browser-console-mcp.js.map
@@ -38,8 +38,6 @@ declare class BrowserConsoleMCP {
38
38
  private ws;
39
39
  private serverUrl;
40
40
  private connected;
41
- private commandHistory;
42
- private historyIndex;
43
41
  constructor(serverUrl?: string);
44
42
  /**
45
43
  * Connect to MCP server
@@ -7,8 +7,6 @@ class BrowserConsoleMCP {
7
7
  constructor(serverUrl = "ws://localhost:7898/browser") {
8
8
  this.ws = null;
9
9
  this.connected = false;
10
- this.commandHistory = [];
11
- this.historyIndex = -1;
12
10
  this.serverUrl = serverUrl;
13
11
  }
14
12
  /**
@@ -367,8 +365,6 @@ class BrowserConsoleMCP {
367
365
  payload: { command },
368
366
  };
369
367
  this.ws.send(JSON.stringify(message));
370
- this.commandHistory.push(command);
371
- this.historyIndex = this.commandHistory.length;
372
368
  }
373
369
  /**
374
370
  * Register console commands
package/package.json CHANGED
@@ -1,69 +1,70 @@
1
1
  {
2
- "name": "browser-console-mcp",
3
- "version": "1.0.9",
4
- "description": "MCP client for browser console and server for Cursor",
5
- "main": "dist/server/index.js",
6
- "type": "module",
7
- "bin": {
8
- "browser-console-mcp": "./bin/browser-mcp-server.js"
9
- },
10
- "keywords": [
11
- "mcp",
12
- "browser",
13
- "console",
14
- "cursor",
15
- "ai",
16
- "claude",
17
- "anthropic",
18
- "automation"
19
- ],
20
- "author": "super-yolin",
21
- "license": "MIT",
22
- "repository": {
23
- "type": "git",
24
- "url": "git+https://github.com/super-yolin/browser-console-mcp.git"
25
- },
26
- "bugs": {
27
- "url": "https://github.com/super-yolin/browser-console-mcp/issues"
28
- },
29
- "homepage": "https://github.com/super-yolin/browser-console-mcp#readme",
30
- "engines": {
31
- "node": ">=16.0.0"
32
- },
33
- "devDependencies": {
34
- "@rollup/plugin-commonjs": "^25.0.7",
35
- "@rollup/plugin-node-resolve": "^15.2.3",
36
- "@rollup/plugin-typescript": "^11.1.6",
37
- "@types/node": "^20.17.46",
38
- "@types/ws": "^8.18.1",
39
- "html2canvas": "^1.4.1",
40
- "rollup": "^4.12.1",
41
- "rollup-plugin-terser": "^7.0.2",
42
- "tslib": "^2.8.1",
43
- "typescript": "^5.4.2"
44
- },
45
- "dependencies": {
46
- "@modelcontextprotocol/sdk": "^1.5.0",
47
- "ws": "^8.16.0",
48
- "zod": "^3.24.4"
49
- },
50
- "peerDependencies": {
51
- "html2canvas": "^1.4.1"
52
- },
53
- "peerDependenciesMeta": {
54
- "html2canvas": {
55
- "optional": true
56
- }
57
- },
58
- "scripts": {
59
- "build": "tsc",
60
- "build:client": "rollup -c",
61
- "build:browser": "rollup -c rollup.browser.config.js",
62
- "copy:html2canvas": "node bin/copy-html2canvas.js",
63
- "copy:browser-inject": "node bin/copy-browser-inject.js",
64
- "build:all": "pnpm build && pnpm build:client && pnpm build:browser && pnpm copy:html2canvas && pnpm copy:browser-inject",
65
- "dev": "tsc --watch",
66
- "start": "node dist/server/index.js",
67
- "start:browser": "node dist/browser/index.js"
68
- }
69
- }
2
+ "name": "browser-console-mcp",
3
+ "version": "1.1.0",
4
+ "description": "Let your AI assistant control the browser via MCP",
5
+ "main": "dist/browser/index.js",
6
+ "type": "module",
7
+ "bin": {
8
+ "browser-console-mcp": "bin/browser-mcp-server.js"
9
+ },
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "build:client": "rollup -c",
13
+ "build:browser": "rollup -c rollup.browser.config.js",
14
+ "copy:html2canvas": "node bin/copy-html2canvas.js",
15
+ "copy:browser-inject": "node bin/copy-browser-inject.js",
16
+ "build:all": "pnpm build && pnpm build:client && pnpm build:browser && pnpm copy:html2canvas && pnpm copy:browser-inject",
17
+ "dev": "tsc --watch",
18
+ "start": "node dist/server/index.js",
19
+ "start:browser": "node dist/browser/index.js",
20
+ "prepare": "pnpm build:all && mkdir -p bin"
21
+ },
22
+ "keywords": [
23
+ "mcp",
24
+ "browser",
25
+ "console",
26
+ "cursor",
27
+ "ai",
28
+ "claude",
29
+ "anthropic",
30
+ "automation"
31
+ ],
32
+ "author": "super-yolin",
33
+ "license": "MIT",
34
+ "repository": {
35
+ "type": "git",
36
+ "url": "git+https://github.com/super-yolin/browser-console-mcp.git"
37
+ },
38
+ "bugs": {
39
+ "url": "https://github.com/super-yolin/browser-console-mcp/issues"
40
+ },
41
+ "homepage": "https://github.com/super-yolin/browser-console-mcp#readme",
42
+ "engines": {
43
+ "node": ">=16.0.0"
44
+ },
45
+ "devDependencies": {
46
+ "@rollup/plugin-commonjs": "^25.0.7",
47
+ "@rollup/plugin-node-resolve": "^15.2.3",
48
+ "@rollup/plugin-typescript": "^11.1.6",
49
+ "@types/node": "^20.17.46",
50
+ "@types/ws": "^8.18.1",
51
+ "html2canvas": "^1.4.1",
52
+ "rollup": "^4.12.1",
53
+ "rollup-plugin-terser": "^7.0.2",
54
+ "tslib": "^2.8.1",
55
+ "typescript": "^5.4.2"
56
+ },
57
+ "dependencies": {
58
+ "@modelcontextprotocol/sdk": "^1.5.0",
59
+ "ws": "^8.16.0",
60
+ "zod": "^3.24.4"
61
+ },
62
+ "peerDependencies": {
63
+ "html2canvas": "^1.4.1"
64
+ },
65
+ "peerDependenciesMeta": {
66
+ "html2canvas": {
67
+ "optional": true
68
+ }
69
+ }
70
+ }
package/readme.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Browser Console MCP
2
2
 
3
- Browser console MCP client and Cursor MCP server. Let your AI assistant control the browser!
3
+ Browser console MCP client and server. Let your AI assistant control the browser!
4
4
 
5
5
  **Language**: [English](#english) | [中文](#中文) | [日本語](#日本語) | [한국어](#한국어)
6
6
 
@@ -8,33 +8,52 @@ Browser console MCP client and Cursor MCP server. Let your AI assistant control
8
8
 
9
9
  ### Introduction
10
10
 
11
- Browser Console MCP is a tool that allows Cursor's Claude AI assistant to interact with the browser through the MCP (Model Context Protocol) protocol. It provides a browser client and an MCP server, enabling the AI assistant to perform the following operations:
11
+ Browser Console MCP is a relay server that lets any MCP-compatible AI client (Cursor, Claude Desktop, etc.) interact with your browser in real time. Inject the client script into any page and your AI can:
12
12
 
13
13
  - Get page HTML content
14
14
  - Execute JavaScript code
15
15
  - Get page title and URL
16
- - Get elements using CSS selectors
16
+ - Query elements using CSS selectors
17
17
  - Capture page screenshots
18
- - Click page elements
19
- - Input text into form fields
18
+ - Click elements
19
+ - Fill in form fields
20
+
21
+ ### How it works
22
+
23
+ The relay server runs locally and bridges two connections:
24
+
25
+ 1. **Browser side** — a small script injected into the page connects via WebSocket (`/browser`)
26
+ 2. **AI client side** — the MCP server communicates with Cursor / Claude Desktop via stdio
27
+
28
+ All browser commands go through this relay; nothing is sent to any external service.
20
29
 
21
30
  ### Usage
22
31
 
23
- #### Inject MCP Client in Browser
32
+ #### Step 1 Start the relay server
33
+
34
+ The server starts automatically when your MCP client launches it. Or run it manually:
35
+
36
+ ```bash
37
+ npx browser-console-mcp
38
+ ```
39
+
40
+ Open `http://localhost:7898` in your browser to check connection status and get the bookmarklet.
41
+
42
+ #### Step 2 — Inject the client into your browser
43
+
44
+ Drag the **Browser MCP** bookmarklet from `http://localhost:7898` to your bookmarks bar, then click it on any page.
24
45
 
25
- Execute the following code in your browser console:
46
+ Or paste this into the browser console:
26
47
 
27
48
  ```javascript
28
- // ======== IMPORTANT: Inject MCP server ========
29
49
  var s = document.createElement('script');
30
50
  s.src = 'http://localhost:7898/browser-inject.js';
31
51
  document.head.appendChild(s);
32
- // ==============================================
33
52
  ```
34
53
 
35
- #### MCP Configuration
54
+ #### Step 3 — Configure your MCP client
36
55
 
37
- Create a `.cursor/mcp.json` file in your home directory:
56
+ **Cursor** add to `~/.cursor/mcp.json`:
38
57
 
39
58
  ```json
40
59
  {
@@ -51,18 +70,40 @@ Create a `.cursor/mcp.json` file in your home directory:
51
70
  }
52
71
  ```
53
72
 
54
- #### Using in Cursor
73
+ **Claude Desktop** add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
55
74
 
56
- In Cursor, your AI assistant can now use the following tools:
75
+ ```json
76
+ {
77
+ "mcpServers": {
78
+ "browser-mcp": {
79
+ "command": "npx",
80
+ "args": ["-y", "browser-console-mcp"],
81
+ "env": {
82
+ "PORT": "7898"
83
+ }
84
+ }
85
+ }
86
+ }
87
+ ```
88
+
89
+ #### Available tools
90
+
91
+ | Tool | Description |
92
+ |------|-------------|
93
+ | `executeJS` | Execute JavaScript in the page context |
94
+ | `getPageHTML` | Get full page HTML |
95
+ | `getPageTitle` | Get page title |
96
+ | `getPageURL` | Get current URL |
97
+ | `getElements` | Query elements by CSS selector |
98
+ | `captureScreenshot` | Screenshot the page or a specific element |
99
+ | `clickElement` | Click an element by CSS selector |
100
+ | `inputText` | Type into an input or textarea |
101
+
102
+ #### Troubleshooting
57
103
 
58
- - `mcp_browser-mcp_executeJS`: Execute JavaScript code
59
- - `mcp_browser-mcp_getPageHTML`: Get page HTML
60
- - `mcp_browser-mcp_getPageTitle`: Get page title
61
- - `mcp_browser-mcp_getElements`: Get elements using CSS selectors
62
- - `mcp_browser-mcp_captureScreenshot`: Capture page screenshot
63
- - `mcp_browser-mcp_getPageURL`: Get page URL
64
- - `mcp_browser-mcp_clickElement`: Click page elements
65
- - `mcp_browser-mcp_inputText`: Input text into form fields
104
+ - **No browser connection** — make sure you've injected the client script on the target page. The status page at `http://localhost:7898` shows live connection counts.
105
+ - **Screenshot is blank** — try targeting a specific element: `captureScreenshot({selector: ".main-content"})`. Some pages block canvas rendering due to CSP.
106
+ - **Port conflict** — change `PORT` in the MCP config and use the same port in the inject URL.
66
107
 
67
108
  ### License
68
109
 
@@ -72,33 +113,52 @@ MIT
72
113
 
73
114
  ### 简介
74
115
 
75
- Browser Console MCP 是一个工具,允许 Cursor Claude AI 助手通过 MCP(Model Context Protocol)协议与浏览器进行交互。它提供了一个浏览器客户端和一个 MCP 服务器,使 AI 助手能够执行以下操作:
116
+ Browser Console MCP 是一个本地中继服务器,让任何支持 MCP 协议的 AI 客户端(Cursor、Claude Desktop 等)能够实时控制浏览器。在页面中注入客户端脚本后,AI 可以:
76
117
 
77
118
  - 获取页面 HTML 内容
78
119
  - 执行 JavaScript 代码
79
120
  - 获取页面标题和 URL
80
- - 使用 CSS 选择器获取元素
81
- - 截取页面截图
121
+ - 使用 CSS 选择器查询元素
122
+ - 截取页面或指定元素的截图
82
123
  - 点击页面元素
83
124
  - 向输入框填入文本
84
125
 
126
+ ### 工作原理
127
+
128
+ 中继服务器在本地运行,连接两端:
129
+
130
+ 1. **浏览器端** — 注入页面的脚本通过 WebSocket(`/browser`)连接服务器
131
+ 2. **AI 客户端** — MCP 服务器通过 stdio 与 Cursor / Claude Desktop 通信
132
+
133
+ 所有指令都在本地转发,不经过任何外部服务。
134
+
85
135
  ### 使用方法
86
136
 
87
- #### 在浏览器中注入 MCP 客户端
137
+ #### 第一步 启动中继服务器
88
138
 
89
- 在浏览器控制台中执行以下代码:
139
+ MCP 客户端会自动启动服务器。也可以手动运行:
140
+
141
+ ```bash
142
+ npx browser-console-mcp
143
+ ```
144
+
145
+ 打开 `http://localhost:7898` 查看连接状态和书签工具。
146
+
147
+ #### 第二步 — 在浏览器中注入客户端
148
+
149
+ 把 `http://localhost:7898` 页面上的 **Browser MCP** 书签拖到浏览器书签栏,然后在任意页面点击它。
150
+
151
+ 或者直接在控制台粘贴:
90
152
 
91
153
  ```javascript
92
- // ======== 重要: 注入MCP服务器 ========
93
154
  var s = document.createElement('script');
94
155
  s.src = 'http://localhost:7898/browser-inject.js';
95
156
  document.head.appendChild(s);
96
- // ====================================
97
157
  ```
98
158
 
99
- #### MCP 配置
159
+ #### 第三步 — 配置 MCP 客户端
100
160
 
101
- 在您的主目录中创建 `.cursor/mcp.json` 文件:
161
+ **Cursor** — 编辑 `~/.cursor/mcp.json`:
102
162
 
103
163
  ```json
104
164
  {
@@ -115,18 +175,40 @@ document.head.appendChild(s);
115
175
  }
116
176
  ```
117
177
 
118
- #### Cursor 中使用
178
+ **Claude Desktop** 编辑 `~/Library/Application Support/Claude/claude_desktop_config.json`:
119
179
 
120
- 在 Cursor 中,你的 AI 助手现在可以使用以下工具:
180
+ ```json
181
+ {
182
+ "mcpServers": {
183
+ "browser-mcp": {
184
+ "command": "npx",
185
+ "args": ["-y", "browser-console-mcp"],
186
+ "env": {
187
+ "PORT": "7898"
188
+ }
189
+ }
190
+ }
191
+ }
192
+ ```
193
+
194
+ #### 可用工具
195
+
196
+ | 工具 | 说明 |
197
+ |------|------|
198
+ | `executeJS` | 在页面上下文中执行 JavaScript |
199
+ | `getPageHTML` | 获取完整页面 HTML |
200
+ | `getPageTitle` | 获取页面标题 |
201
+ | `getPageURL` | 获取当前 URL |
202
+ | `getElements` | 用 CSS 选择器查询元素 |
203
+ | `captureScreenshot` | 截取页面或指定元素截图 |
204
+ | `clickElement` | 点击指定元素 |
205
+ | `inputText` | 向输入框或文本域填入文本 |
121
206
 
122
- - `mcp_browser-mcp_executeJS`: 执行 JavaScript 代码
123
- - `mcp_browser-mcp_getPageHTML`: 获取页面 HTML
124
- - `mcp_browser-mcp_getPageTitle`: 获取页面标题
125
- - `mcp_browser-mcp_getElements`: 使用 CSS 选择器获取元素
126
- - `mcp_browser-mcp_captureScreenshot`: 截取页面截图
127
- - `mcp_browser-mcp_getPageURL`: 获取页面 URL
128
- - `mcp_browser-mcp_clickElement`: 点击页面元素
129
- - `mcp_browser-mcp_inputText`: 向输入框填入文本
207
+ #### 常见问题
208
+
209
+ - **提示无浏览器连接** — 确认已在目标页面注入客户端脚本,`http://localhost:7898` 会显示实时连接数。
210
+ - **截图空白** — 试试指定具体元素:`captureScreenshot({selector: ".main-content"})`,部分页面的 CSP 策略会阻止 canvas 渲染。
211
+ - **端口冲突** — 在 MCP 配置中修改 `PORT`,注入 URL 中也使用相同端口。
130
212
 
131
213
  ### 许可证
132
214
 
@@ -136,33 +218,33 @@ MIT
136
218
 
137
219
  ### はじめに
138
220
 
139
- Browser Console MCPは、CursorClaude AIアシスタントがMCP(Model Context Protocol)プロトコルを通じてブラウザと対話できるようにするツールです。ブラウザクライアントとMCPサーバーを提供し、AIアシスタントが以下の操作を実行できるようにします:
221
+ Browser Console MCPは、MCP対応AIクライアント(CursorClaude Desktopなど)がブラウザをリアルタイムで操作できるようにするローカル中継サーバーです。ページにクライアントスクリプトを注入すると、AIが以下の操作を実行できます:
140
222
 
141
223
  - ページのHTML内容の取得
142
224
  - JavaScriptコードの実行
143
225
  - ページタイトルとURLの取得
144
226
  - CSSセレクタを使用した要素の取得
145
- - ページのスクリーンショット撮影
227
+ - ページまたは特定要素のスクリーンショット撮影
146
228
  - ページ要素のクリック
147
229
  - 入力フィールドへのテキスト入力
148
230
 
149
231
  ### 使用方法
150
232
 
151
- #### ブラウザにMCPクライアントを注入
233
+ #### ステップ1 — ブラウザにクライアントを注入
152
234
 
153
235
  ブラウザのコンソールで以下のコードを実行します:
154
236
 
155
237
  ```javascript
156
- // ======== 重要: MCPサーバーを注入 ========
157
238
  var s = document.createElement('script');
158
239
  s.src = 'http://localhost:7898/browser-inject.js';
159
240
  document.head.appendChild(s);
160
- // ========================================
161
241
  ```
162
242
 
163
- #### MCP設定
243
+ または `http://localhost:7898` のブックマークレットを使用してください。
244
+
245
+ #### ステップ2 — MCP設定
164
246
 
165
- ホームディレクトリに `.cursor/mcp.json` ファイルを作成します:
247
+ **Cursor** — `~/.cursor/mcp.json` に追加:
166
248
 
167
249
  ```json
168
250
  {
@@ -179,18 +261,34 @@ document.head.appendChild(s);
179
261
  }
180
262
  ```
181
263
 
182
- #### Cursorでの使用
264
+ **Claude Desktop** — `~/Library/Application Support/Claude/claude_desktop_config.json` に追加:
265
+
266
+ ```json
267
+ {
268
+ "mcpServers": {
269
+ "browser-mcp": {
270
+ "command": "npx",
271
+ "args": ["-y", "browser-console-mcp"],
272
+ "env": {
273
+ "PORT": "7898"
274
+ }
275
+ }
276
+ }
277
+ }
278
+ ```
183
279
 
184
- Cursorでは、AIアシスタントが以下のツールを使用できるようになります:
280
+ #### 利用可能なツール
185
281
 
186
- - `mcp_browser-mcp_executeJS`: JavaScriptコードを実行
187
- - `mcp_browser-mcp_getPageHTML`: ページのHTMLを取得
188
- - `mcp_browser-mcp_getPageTitle`: ページタイトルを取得
189
- - `mcp_browser-mcp_getElements`: CSSセレクタを使用して要素を取得
190
- - `mcp_browser-mcp_captureScreenshot`: ページのスクリーンショットを撮影
191
- - `mcp_browser-mcp_getPageURL`: ページURLを取得
192
- - `mcp_browser-mcp_clickElement`: ページ要素をクリック
193
- - `mcp_browser-mcp_inputText`: 入力フィールドにテキストを入力
282
+ | ツール | 説明 |
283
+ |--------|------|
284
+ | `executeJS` | ページコンテキストでJavaScriptを実行 |
285
+ | `getPageHTML` | ページの全HTMLを取得 |
286
+ | `getPageTitle` | ページタイトルを取得 |
287
+ | `getPageURL` | 現在のURLを取得 |
288
+ | `getElements` | CSSセレクタで要素を取得 |
289
+ | `captureScreenshot` | ページまたは特定要素のスクリーンショット |
290
+ | `clickElement` | 要素をクリック |
291
+ | `inputText` | 入力フィールドにテキストを入力 |
194
292
 
195
293
  ### ライセンス
196
294
 
@@ -200,33 +298,33 @@ MIT
200
298
 
201
299
  ### 소개
202
300
 
203
- Browser Console MCP는 Cursor의 Claude AI 어시스턴트가 MCP(Model Context Protocol) 프로토콜을 통해 브라우저와 상호작용할 수 있게 해주는 도구입니다. 브라우저 클라이언트와 MCP 서버를 제공하여 AI 어시스턴트가 다음 작업을 수행할 수 있도록 합니다:
301
+ Browser Console MCP는 MCP 호환 AI 클라이언트(Cursor, Claude Desktop 등) 브라우저를 실시간으로 제어할 수 있게 해주는 로컬 릴레이 서버입니다. 페이지에 클라이언트 스크립트를 주입하면 AI 다음 작업을 수행할 수 있습니다:
204
302
 
205
303
  - 페이지 HTML 콘텐츠 가져오기
206
304
  - JavaScript 코드 실행하기
207
305
  - 페이지 제목 및 URL 가져오기
208
- - CSS 선택자를 사용하여 요소 가져오기
209
- - 페이지 스크린샷 캡처하기
306
+ - CSS 선택자로 요소 가져오기
307
+ - 페이지 또는 특정 요소 스크린샷 캡처하기
210
308
  - 페이지 요소 클릭하기
211
309
  - 입력 필드에 텍스트 입력하기
212
310
 
213
311
  ### 사용 방법
214
312
 
215
- #### 브라우저에 MCP 클라이언트 주입하기
313
+ #### 1단계 — 브라우저에 클라이언트 주입하기
216
314
 
217
315
  브라우저 콘솔에서 다음 코드를 실행하세요:
218
316
 
219
317
  ```javascript
220
- // ======== 중요: MCP 서버 주입 ========
221
318
  var s = document.createElement('script');
222
319
  s.src = 'http://localhost:7898/browser-inject.js';
223
320
  document.head.appendChild(s);
224
- // ===================================
225
321
  ```
226
322
 
227
- #### MCP 구성
323
+ 또는 `http://localhost:7898`의 북마크릿을 사용하세요.
324
+
325
+ #### 2단계 — MCP 클라이언트 설정
228
326
 
229
- 디렉토리에 `.cursor/mcp.json` 파일을 생성하세요:
327
+ **Cursor** `~/.cursor/mcp.json`에 추가:
230
328
 
231
329
  ```json
232
330
  {
@@ -243,18 +341,34 @@ document.head.appendChild(s);
243
341
  }
244
342
  ```
245
343
 
246
- #### Cursor에서 사용하기
344
+ **Claude Desktop** — `~/Library/Application Support/Claude/claude_desktop_config.json`에 추가:
247
345
 
248
- Cursor에서 AI 어시스턴트는 이제 다음 도구들을 사용할 수 있습니다:
346
+ ```json
347
+ {
348
+ "mcpServers": {
349
+ "browser-mcp": {
350
+ "command": "npx",
351
+ "args": ["-y", "browser-console-mcp"],
352
+ "env": {
353
+ "PORT": "7898"
354
+ }
355
+ }
356
+ }
357
+ }
358
+ ```
249
359
 
250
- - `mcp_browser-mcp_executeJS`: JavaScript 코드 실행하기
251
- - `mcp_browser-mcp_getPageHTML`: 페이지 HTML 가져오기
252
- - `mcp_browser-mcp_getPageTitle`: 페이지 제목 가져오기
253
- - `mcp_browser-mcp_getElements`: CSS 선택자로 요소 가져오기
254
- - `mcp_browser-mcp_captureScreenshot`: 페이지 스크린샷 캡처하기
255
- - `mcp_browser-mcp_getPageURL`: 페이지 URL 가져오기
256
- - `mcp_browser-mcp_clickElement`: 페이지 요소 클릭하기
257
- - `mcp_browser-mcp_inputText`: 입력 필드에 텍스트 입력하기
360
+ #### 사용 가능한 도구
361
+
362
+ | 도구 | 설명 |
363
+ |------|------|
364
+ | `executeJS` | 페이지 컨텍스트에서 JavaScript 실행 |
365
+ | `getPageHTML` | 전체 페이지 HTML 가져오기 |
366
+ | `getPageTitle` | 페이지 제목 가져오기 |
367
+ | `getPageURL` | 현재 URL 가져오기 |
368
+ | `getElements` | CSS 선택자로 요소 가져오기 |
369
+ | `captureScreenshot` | 페이지 또는 특정 요소 스크린샷 |
370
+ | `clickElement` | 요소 클릭하기 |
371
+ | `inputText` | 입력 필드에 텍스트 입력하기 |
258
372
 
259
373
  ### 라이선스
260
374