mcp-browser-bridge 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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 adbarc92
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,117 @@
1
+ # Browser Bridge MCP
2
+
3
+ [![npm version](https://img.shields.io/npm/v/mcp-browser-bridge.svg)](https://www.npmjs.com/package/mcp-browser-bridge)
4
+
5
+ MCP server that bridges AI assistants to the browser via a WebSocket-connected extension.
6
+
7
+ ```
8
+ AI Assistant ←(MCP stdio)→ mcp-browser-bridge ←(WebSocket :7483)→ Browser Extension ←(Chrome APIs)→ Browser
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ### 1. Install the extension
14
+
15
+ Install from the Chrome Web Store (coming soon), or load manually:
16
+
17
+ 1. Download or clone this repo.
18
+ 2. Open `chrome://extensions`, enable **Developer mode**.
19
+ 3. Click **Load unpacked** and select the `extension/` folder.
20
+
21
+ Works in Chrome, Brave, Edge, and other Chromium browsers.
22
+
23
+ ### 2. Add to your MCP config
24
+
25
+ Add to your `.mcp.json` (or equivalent MCP client config):
26
+
27
+ ```json
28
+ {
29
+ "mcpServers": {
30
+ "browser-bridge": {
31
+ "command": "npx",
32
+ "args": ["-y", "mcp-browser-bridge"],
33
+ "env": { "BRIDGE_WS_PORT": "7483" }
34
+ }
35
+ }
36
+ }
37
+ ```
38
+
39
+ ### 3. Verify
40
+
41
+ Start your MCP client. The extension popup should show a green "Connected" indicator. Use the `browser_status` tool to confirm the connection.
42
+
43
+ ## Available Tools
44
+
45
+ All tools accept an optional `tabId` parameter. When omitted, they target the active tab.
46
+
47
+ | Tool | Description |
48
+ |------|-------------|
49
+ | `browser_status` | Check if the extension is connected and get active tab info |
50
+ | `browser_navigate` | Navigate a tab to a URL |
51
+ | `browser_screenshot` | Capture a screenshot of the visible area of a tab |
52
+ | `browser_evaluate` | Execute JavaScript in a tab and return the result |
53
+ | `browser_click` | Click an element by CSS selector |
54
+ | `browser_fill` | Fill a form field by CSS selector |
55
+ | `browser_get_content` | Get the text or HTML of a page or element |
56
+ | `browser_get_tabs` | List all open browser tabs |
57
+ | `browser_get_console` | Get captured console log entries from a tab |
58
+ | `browser_wait_for` | Wait for a CSS selector to appear on the page |
59
+ | `browser_send_message` | Send a custom message to the extension |
60
+
61
+ ## Configuration
62
+
63
+ The WebSocket port defaults to `7483`. To change it:
64
+
65
+ - **Server side:** Set the `BRIDGE_WS_PORT` environment variable in your MCP config.
66
+ - **Extension side:** Change the port in the extension popup and click Reconnect.
67
+
68
+ ## Compatibility
69
+
70
+ Works with any Chromium-based browser: Chrome, Brave, Edge, Arc, Vivaldi, Opera.
71
+
72
+ ## Security
73
+
74
+ - WebSocket binds to `127.0.0.1` only (no network exposure).
75
+ - Connections restricted to `chrome-extension://` origins.
76
+ - Single extension client at a time.
77
+
78
+ ## Troubleshooting
79
+
80
+ **Extension shows "Disconnected"**
81
+ Check that the MCP server is running and the port is free. Verify nothing else is using port 7483:
82
+ ```sh
83
+ # macOS/Linux
84
+ lsof -i :7483
85
+
86
+ # Windows
87
+ netstat -aon | findstr :7483
88
+ ```
89
+
90
+ **Tools return "No extension connected"**
91
+ Open the extension popup and click Reconnect. Ensure the popup shows a green "Connected" indicator.
92
+
93
+ **Screenshots fail**
94
+ The target tab must be visible and focused. Background or minimized tabs cannot be captured.
95
+
96
+ **`browser_evaluate` returns unexpected results**
97
+ Scripts run in the page's MAIN world. Results must be JSON-serializable. Promises return `{}` -- use synchronous expressions or structure async work to return a final value.
98
+
99
+ ## Development
100
+
101
+ ```bash
102
+ git clone https://github.com/adbarc92/mcp-browser-bridge.git
103
+ cd mcp-browser-bridge
104
+ npm install
105
+ npm run build
106
+ ```
107
+
108
+ To load the extension locally:
109
+
110
+ 1. Open `chrome://extensions` and enable Developer mode.
111
+ 2. Click "Load unpacked" and select the `extension/` folder.
112
+
113
+ The repo includes a `.mcp.json` configured for local development.
114
+
115
+ ## License
116
+
117
+ MIT
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,39 @@
1
+ #!/usr/bin/env node
2
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
3
+ import { BridgeWebSocketServer } from "./ws-server.js";
4
+ import { createMcpServer } from "./mcp-server.js";
5
+ import { METHODS } from "./protocol.js";
6
+ import { logger } from "./utils/logger.js";
7
+ async function main() {
8
+ const ws = new BridgeWebSocketServer();
9
+ const mcp = createMcpServer(ws);
10
+ // Log console events from the extension
11
+ ws.on(METHODS.EVENT_CONSOLE, (event) => {
12
+ logger.debug("Console event", event.params);
13
+ });
14
+ ws.on(METHODS.EVENT_TAB_UPDATED, (event) => {
15
+ logger.debug("Tab updated", event.params);
16
+ });
17
+ ws.on(METHODS.EVENT_TAB_REMOVED, (event) => {
18
+ logger.debug("Tab removed", event.params);
19
+ });
20
+ // Start WebSocket server first
21
+ ws.start();
22
+ // Connect MCP over stdio
23
+ const transport = new StdioServerTransport();
24
+ await mcp.connect(transport);
25
+ logger.info("MCP server connected via stdio");
26
+ // Graceful shutdown
27
+ const shutdown = () => {
28
+ logger.info("Shutting down...");
29
+ ws.stop();
30
+ process.exit(0);
31
+ };
32
+ process.on("SIGINT", shutdown);
33
+ process.on("SIGTERM", shutdown);
34
+ }
35
+ main().catch((err) => {
36
+ logger.error("Fatal error", err);
37
+ process.exit(1);
38
+ });
39
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAE3C,KAAK,UAAU,IAAI;IACjB,MAAM,EAAE,GAAG,IAAI,qBAAqB,EAAE,CAAC;IACvC,MAAM,GAAG,GAAG,eAAe,CAAC,EAAE,CAAC,CAAC;IAEhC,wCAAwC;IACxC,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,aAAa,EAAE,CAAC,KAAK,EAAE,EAAE;QACrC,MAAM,CAAC,KAAK,CAAC,eAAe,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,iBAAiB,EAAE,CAAC,KAAK,EAAE,EAAE;QACzC,MAAM,CAAC,KAAK,CAAC,aAAa,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,iBAAiB,EAAE,CAAC,KAAK,EAAE,EAAE;QACzC,MAAM,CAAC,KAAK,CAAC,aAAa,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;IAEH,+BAA+B;IAC/B,EAAE,CAAC,KAAK,EAAE,CAAC;IAEX,yBAAyB;IACzB,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAC7B,MAAM,CAAC,IAAI,CAAC,gCAAgC,CAAC,CAAC;IAE9C,oBAAoB;IACpB,MAAM,QAAQ,GAAG,GAAG,EAAE;QACpB,MAAM,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;QAChC,EAAE,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC;IAEF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC/B,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;AAClC,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,MAAM,CAAC,KAAK,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC;IACjC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,4 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { BridgeWebSocketServer } from "./ws-server.js";
3
+ export declare function createMcpServer(ws: BridgeWebSocketServer): McpServer;
4
+ //# sourceMappingURL=mcp-server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-server.d.ts","sourceRoot":"","sources":["../src/mcp-server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAGpE,OAAO,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAcvD,wBAAgB,eAAe,CAAC,EAAE,EAAE,qBAAqB,GAAG,SAAS,CA4NpE"}
@@ -0,0 +1,175 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { z } from "zod";
3
+ import { METHODS, SCREENSHOT_TIMEOUT_MS } from "./protocol.js";
4
+ function errorText(err) {
5
+ if (typeof err === "object" && err !== null && "message" in err) {
6
+ return err.message;
7
+ }
8
+ return String(err);
9
+ }
10
+ function textResult(text, isError = false) {
11
+ return { content: [{ type: "text", text }], isError };
12
+ }
13
+ export function createMcpServer(ws) {
14
+ const mcp = new McpServer({
15
+ name: "browser-bridge",
16
+ version: "1.1.0",
17
+ });
18
+ // 1. browser_status
19
+ mcp.tool("browser_status", "Check if the Chrome extension is connected and get active tab info", {}, async () => {
20
+ if (!ws.isConnected) {
21
+ return textResult(JSON.stringify({
22
+ connected: false,
23
+ message: "No Chrome extension connected. Load the extension and ensure it shows 'Connected'.",
24
+ }, null, 2));
25
+ }
26
+ try {
27
+ const result = await ws.send(METHODS.CONNECTION_STATUS);
28
+ return textResult(JSON.stringify({ connected: true, ...result }, null, 2));
29
+ }
30
+ catch (err) {
31
+ return textResult(`Connected but status check failed: ${errorText(err)}`, true);
32
+ }
33
+ });
34
+ // 2. browser_navigate
35
+ mcp.tool("browser_navigate", "Navigate a browser tab to the specified URL", {
36
+ url: z.string().describe("The URL to navigate to"),
37
+ tabId: z.number().optional().describe("Tab ID (defaults to active tab)"),
38
+ }, async ({ url, tabId }) => {
39
+ try {
40
+ const result = await ws.send(METHODS.NAVIGATE, { url, tabId });
41
+ return textResult(JSON.stringify(result, null, 2));
42
+ }
43
+ catch (err) {
44
+ return textResult(`Navigation failed: ${errorText(err)}`, true);
45
+ }
46
+ });
47
+ // 3. browser_screenshot
48
+ mcp.tool("browser_screenshot", "Capture a screenshot of the visible area of a browser tab", {
49
+ tabId: z.number().optional().describe("Tab ID (defaults to active tab)"),
50
+ format: z.enum(["png", "jpeg"]).optional().describe("Image format (default: png)"),
51
+ quality: z.number().min(0).max(100).optional().describe("JPEG quality (0-100, only for jpeg format)"),
52
+ }, async ({ tabId, format, quality }) => {
53
+ try {
54
+ const result = await ws.send(METHODS.SCREENSHOT, { tabId, format, quality }, SCREENSHOT_TIMEOUT_MS);
55
+ return {
56
+ content: [{
57
+ type: "image",
58
+ data: result.data,
59
+ mimeType: result.mimeType,
60
+ }],
61
+ };
62
+ }
63
+ catch (err) {
64
+ return textResult(`Screenshot failed: ${errorText(err)}`, true);
65
+ }
66
+ });
67
+ // 4. browser_evaluate
68
+ mcp.tool("browser_evaluate", "Execute JavaScript in the context of a browser tab and return the result", {
69
+ expression: z.string().describe("JavaScript expression to evaluate"),
70
+ tabId: z.number().optional().describe("Tab ID (defaults to active tab)"),
71
+ }, async ({ expression, tabId }) => {
72
+ try {
73
+ const result = await ws.send(METHODS.EVALUATE, { expression, tabId });
74
+ return textResult(JSON.stringify(result, null, 2));
75
+ }
76
+ catch (err) {
77
+ return textResult(`Evaluation failed: ${errorText(err)}`, true);
78
+ }
79
+ });
80
+ // 5. browser_click
81
+ mcp.tool("browser_click", "Click an element on the page identified by a CSS selector", {
82
+ selector: z.string().describe("CSS selector for the element to click"),
83
+ tabId: z.number().optional().describe("Tab ID (defaults to active tab)"),
84
+ }, async ({ selector, tabId }) => {
85
+ try {
86
+ const result = await ws.send(METHODS.CLICK, { selector, tabId });
87
+ return textResult(JSON.stringify(result, null, 2));
88
+ }
89
+ catch (err) {
90
+ return textResult(`Click failed: ${errorText(err)}`, true);
91
+ }
92
+ });
93
+ // 6. browser_fill
94
+ mcp.tool("browser_fill", "Fill a form field with the specified value", {
95
+ selector: z.string().describe("CSS selector for the input element"),
96
+ value: z.string().describe("Value to fill in"),
97
+ tabId: z.number().optional().describe("Tab ID (defaults to active tab)"),
98
+ }, async ({ selector, value, tabId }) => {
99
+ try {
100
+ const result = await ws.send(METHODS.FILL, { selector, value, tabId });
101
+ return textResult(JSON.stringify(result, null, 2));
102
+ }
103
+ catch (err) {
104
+ return textResult(`Fill failed: ${errorText(err)}`, true);
105
+ }
106
+ });
107
+ // 7. browser_get_content
108
+ mcp.tool("browser_get_content", "Get the HTML or text content of a page or specific element", {
109
+ tabId: z.number().optional().describe("Tab ID (defaults to active tab)"),
110
+ selector: z.string().optional().describe("CSS selector to get content of (defaults to body)"),
111
+ format: z.enum(["html", "text"]).optional().describe("Content format (default: text)"),
112
+ }, async ({ tabId, selector, format }) => {
113
+ try {
114
+ const result = await ws.send(METHODS.GET_CONTENT, { tabId, selector, format });
115
+ const content = result;
116
+ return textResult(`URL: ${content.url}\nTitle: ${content.title}\n\n${content.content}`);
117
+ }
118
+ catch (err) {
119
+ return textResult(`Get content failed: ${errorText(err)}`, true);
120
+ }
121
+ });
122
+ // 8. browser_get_tabs
123
+ mcp.tool("browser_get_tabs", "List all open browser tabs", {}, async () => {
124
+ try {
125
+ const result = await ws.send(METHODS.GET_TABS);
126
+ return textResult(JSON.stringify(result, null, 2));
127
+ }
128
+ catch (err) {
129
+ return textResult(`Get tabs failed: ${errorText(err)}`, true);
130
+ }
131
+ });
132
+ // 9. browser_get_console
133
+ mcp.tool("browser_get_console", "Get captured console log entries from a tab", {
134
+ tabId: z.number().optional().describe("Tab ID (defaults to active tab)"),
135
+ clear: z.boolean().optional().describe("Clear logs after retrieval (default: false)"),
136
+ }, async ({ tabId, clear }) => {
137
+ try {
138
+ const result = await ws.send(METHODS.GET_CONSOLE, { tabId, clear });
139
+ return textResult(JSON.stringify(result, null, 2));
140
+ }
141
+ catch (err) {
142
+ return textResult(`Get console failed: ${errorText(err)}`, true);
143
+ }
144
+ });
145
+ // 10. browser_wait_for
146
+ mcp.tool("browser_wait_for", "Wait for an element matching a CSS selector to appear on the page", {
147
+ selector: z.string().describe("CSS selector to wait for"),
148
+ tabId: z.number().optional().describe("Tab ID (defaults to active tab)"),
149
+ timeout: z.number().optional().describe("Timeout in milliseconds (default: 30000)"),
150
+ }, async ({ selector, tabId, timeout }) => {
151
+ const waitTimeout = timeout || 30000;
152
+ try {
153
+ const result = await ws.send(METHODS.WAIT_FOR, { selector, tabId, timeout: waitTimeout }, waitTimeout + 5000);
154
+ return textResult(JSON.stringify(result, null, 2));
155
+ }
156
+ catch (err) {
157
+ return textResult(`Wait failed: ${errorText(err)}`, true);
158
+ }
159
+ });
160
+ // 11. browser_send_message
161
+ mcp.tool("browser_send_message", "Send a custom message to the Chrome extension for extensibility", {
162
+ type: z.string().describe("Custom message type"),
163
+ data: z.record(z.unknown()).optional().describe("Optional data payload"),
164
+ }, async ({ type, data }) => {
165
+ try {
166
+ const result = await ws.send(METHODS.CUSTOM_MESSAGE, { type, data });
167
+ return textResult(JSON.stringify(result, null, 2));
168
+ }
169
+ catch (err) {
170
+ return textResult(`Send message failed: ${errorText(err)}`, true);
171
+ }
172
+ });
173
+ return mcp;
174
+ }
175
+ //# sourceMappingURL=mcp-server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-server.js","sourceRoot":"","sources":["../src/mcp-server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,56 @@
1
+ export interface JsonRpcRequest {
2
+ jsonrpc: "2.0";
3
+ id: string;
4
+ method: string;
5
+ params?: Record<string, unknown>;
6
+ }
7
+ export interface JsonRpcResponse {
8
+ jsonrpc: "2.0";
9
+ id: string;
10
+ result?: unknown;
11
+ error?: JsonRpcError;
12
+ }
13
+ export interface JsonRpcEvent {
14
+ jsonrpc: "2.0";
15
+ id: null;
16
+ method: string;
17
+ params?: Record<string, unknown>;
18
+ }
19
+ export interface JsonRpcError {
20
+ code: number;
21
+ message: string;
22
+ data?: unknown;
23
+ }
24
+ export type JsonRpcMessage = JsonRpcRequest | JsonRpcResponse | JsonRpcEvent;
25
+ export declare const ErrorCodes: {
26
+ readonly PARSE_ERROR: -32700;
27
+ readonly INVALID_REQUEST: -32600;
28
+ readonly METHOD_NOT_FOUND: -32601;
29
+ readonly INVALID_PARAMS: -32602;
30
+ readonly INTERNAL_ERROR: -32603;
31
+ readonly TIMEOUT: -32000;
32
+ readonly NOT_CONNECTED: -32001;
33
+ readonly ELEMENT_NOT_FOUND: -32002;
34
+ readonly EXECUTION_ERROR: -32003;
35
+ };
36
+ export declare const METHODS: {
37
+ readonly NAVIGATE: "browser.navigate";
38
+ readonly SCREENSHOT: "browser.screenshot";
39
+ readonly EVALUATE: "browser.evaluate";
40
+ readonly CLICK: "browser.click";
41
+ readonly FILL: "browser.fill";
42
+ readonly GET_CONTENT: "browser.getContent";
43
+ readonly GET_TABS: "browser.getTabs";
44
+ readonly GET_CONSOLE: "browser.getConsole";
45
+ readonly WAIT_FOR: "browser.waitFor";
46
+ readonly CONNECTION_STATUS: "connection.status";
47
+ readonly CUSTOM_MESSAGE: "browser.sendMessage";
48
+ readonly EVENT_CONSOLE: "event.console";
49
+ readonly EVENT_TAB_UPDATED: "event.tabUpdated";
50
+ readonly EVENT_TAB_REMOVED: "event.tabRemoved";
51
+ };
52
+ export declare const DEFAULT_TIMEOUT_MS = 30000;
53
+ export declare const SCREENSHOT_TIMEOUT_MS = 60000;
54
+ export declare const KEEPALIVE_INTERVAL_MS = 20000;
55
+ export declare const WS_PORT: number;
56
+ //# sourceMappingURL=protocol.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,KAAK,CAAC;IACf,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,KAAK,CAAC;IACf,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,YAAY,CAAC;CACtB;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,KAAK,CAAC;IACf,EAAE,EAAE,IAAI,CAAC;IACT,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,MAAM,cAAc,GAAG,cAAc,GAAG,eAAe,GAAG,YAAY,CAAC;AAE7E,eAAO,MAAM,UAAU;;;;;;;;;;CAUb,CAAC;AAEX,eAAO,MAAM,OAAO;;;;;;;;;;;;;;;CAkBV,CAAC;AAEX,eAAO,MAAM,kBAAkB,QAAS,CAAC;AACzC,eAAO,MAAM,qBAAqB,QAAS,CAAC;AAC5C,eAAO,MAAM,qBAAqB,QAAS,CAAC;AAC5C,eAAO,MAAM,OAAO,QAAqD,CAAC"}
@@ -0,0 +1,34 @@
1
+ export const ErrorCodes = {
2
+ PARSE_ERROR: -32700,
3
+ INVALID_REQUEST: -32600,
4
+ METHOD_NOT_FOUND: -32601,
5
+ INVALID_PARAMS: -32602,
6
+ INTERNAL_ERROR: -32603,
7
+ TIMEOUT: -32000,
8
+ NOT_CONNECTED: -32001,
9
+ ELEMENT_NOT_FOUND: -32002,
10
+ EXECUTION_ERROR: -32003,
11
+ };
12
+ export const METHODS = {
13
+ // Server -> Extension requests
14
+ NAVIGATE: "browser.navigate",
15
+ SCREENSHOT: "browser.screenshot",
16
+ EVALUATE: "browser.evaluate",
17
+ CLICK: "browser.click",
18
+ FILL: "browser.fill",
19
+ GET_CONTENT: "browser.getContent",
20
+ GET_TABS: "browser.getTabs",
21
+ GET_CONSOLE: "browser.getConsole",
22
+ WAIT_FOR: "browser.waitFor",
23
+ CONNECTION_STATUS: "connection.status",
24
+ CUSTOM_MESSAGE: "browser.sendMessage",
25
+ // Extension -> Server events
26
+ EVENT_CONSOLE: "event.console",
27
+ EVENT_TAB_UPDATED: "event.tabUpdated",
28
+ EVENT_TAB_REMOVED: "event.tabRemoved",
29
+ };
30
+ export const DEFAULT_TIMEOUT_MS = 30_000;
31
+ export const SCREENSHOT_TIMEOUT_MS = 60_000;
32
+ export const KEEPALIVE_INTERVAL_MS = 20_000;
33
+ export const WS_PORT = parseInt(process.env.BRIDGE_WS_PORT || "7483", 10);
34
+ //# sourceMappingURL=protocol.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.js","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AA6BA,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,WAAW,EAAE,CAAC,KAAK;IACnB,eAAe,EAAE,CAAC,KAAK;IACvB,gBAAgB,EAAE,CAAC,KAAK;IACxB,cAAc,EAAE,CAAC,KAAK;IACtB,cAAc,EAAE,CAAC,KAAK;IACtB,OAAO,EAAE,CAAC,KAAK;IACf,aAAa,EAAE,CAAC,KAAK;IACrB,iBAAiB,EAAE,CAAC,KAAK;IACzB,eAAe,EAAE,CAAC,KAAK;CACf,CAAC;AAEX,MAAM,CAAC,MAAM,OAAO,GAAG;IACrB,+BAA+B;IAC/B,QAAQ,EAAE,kBAAkB;IAC5B,UAAU,EAAE,oBAAoB;IAChC,QAAQ,EAAE,kBAAkB;IAC5B,KAAK,EAAE,eAAe;IACtB,IAAI,EAAE,cAAc;IACpB,WAAW,EAAE,oBAAoB;IACjC,QAAQ,EAAE,iBAAiB;IAC3B,WAAW,EAAE,oBAAoB;IACjC,QAAQ,EAAE,iBAAiB;IAC3B,iBAAiB,EAAE,mBAAmB;IACtC,cAAc,EAAE,qBAAqB;IAErC,6BAA6B;IAC7B,aAAa,EAAE,eAAe;IAC9B,iBAAiB,EAAE,kBAAkB;IACrC,iBAAiB,EAAE,kBAAkB;CAC7B,CAAC;AAEX,MAAM,CAAC,MAAM,kBAAkB,GAAG,MAAM,CAAC;AACzC,MAAM,CAAC,MAAM,qBAAqB,GAAG,MAAM,CAAC;AAC5C,MAAM,CAAC,MAAM,qBAAqB,GAAG,MAAM,CAAC;AAC5C,MAAM,CAAC,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,MAAM,EAAE,EAAE,CAAC,CAAC"}
@@ -0,0 +1,7 @@
1
+ export declare const logger: {
2
+ debug: (msg: string, data?: unknown) => void;
3
+ info: (msg: string, data?: unknown) => void;
4
+ warn: (msg: string, data?: unknown) => void;
5
+ error: (msg: string, data?: unknown) => void;
6
+ };
7
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAyBA,eAAO,MAAM,MAAM;iBACJ,MAAM,SAAS,OAAO;gBACvB,MAAM,SAAS,OAAO;gBACtB,MAAM,SAAS,OAAO;iBACrB,MAAM,SAAS,OAAO;CACpC,CAAC"}
@@ -0,0 +1,27 @@
1
+ const LEVEL_ORDER = {
2
+ debug: 0,
3
+ info: 1,
4
+ warn: 2,
5
+ error: 3,
6
+ };
7
+ const minLevel = process.env.BRIDGE_LOG_LEVEL || "info";
8
+ function shouldLog(level) {
9
+ return LEVEL_ORDER[level] >= LEVEL_ORDER[minLevel];
10
+ }
11
+ function log(level, message, data) {
12
+ if (!shouldLog(level))
13
+ return;
14
+ const timestamp = new Date().toISOString();
15
+ const prefix = `[${timestamp}] [${level.toUpperCase()}]`;
16
+ const line = data !== undefined
17
+ ? `${prefix} ${message} ${JSON.stringify(data)}`
18
+ : `${prefix} ${message}`;
19
+ process.stderr.write(line + "\n");
20
+ }
21
+ export const logger = {
22
+ debug: (msg, data) => log("debug", msg, data),
23
+ info: (msg, data) => log("info", msg, data),
24
+ warn: (msg, data) => log("warn", msg, data),
25
+ error: (msg, data) => log("error", msg, data),
26
+ };
27
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,GAA6B;IAC5C,KAAK,EAAE,CAAC;IACR,IAAI,EAAE,CAAC;IACP,IAAI,EAAE,CAAC;IACP,KAAK,EAAE,CAAC;CACT,CAAC;AAEF,MAAM,QAAQ,GAAc,OAAO,CAAC,GAAG,CAAC,gBAA6B,IAAI,MAAM,CAAC;AAEhF,SAAS,SAAS,CAAC,KAAe;IAChC,OAAO,WAAW,CAAC,KAAK,CAAC,IAAI,WAAW,CAAC,QAAQ,CAAC,CAAC;AACrD,CAAC;AAED,SAAS,GAAG,CAAC,KAAe,EAAE,OAAe,EAAE,IAAc;IAC3D,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;QAAE,OAAO;IAC9B,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC3C,MAAM,MAAM,GAAG,IAAI,SAAS,MAAM,KAAK,CAAC,WAAW,EAAE,GAAG,CAAC;IACzD,MAAM,IAAI,GAAG,IAAI,KAAK,SAAS;QAC7B,CAAC,CAAC,GAAG,MAAM,IAAI,OAAO,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE;QAChD,CAAC,CAAC,GAAG,MAAM,IAAI,OAAO,EAAE,CAAC;IAC3B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;AACpC,CAAC;AAED,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,KAAK,EAAE,CAAC,GAAW,EAAE,IAAc,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC;IAC/D,IAAI,EAAE,CAAC,GAAW,EAAE,IAAc,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,CAAC;IAC7D,IAAI,EAAE,CAAC,GAAW,EAAE,IAAc,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,CAAC;IAC7D,KAAK,EAAE,CAAC,GAAW,EAAE,IAAc,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC;CAChE,CAAC"}
@@ -0,0 +1,13 @@
1
+ import { type JsonRpcRequest, type JsonRpcError } from "../protocol.js";
2
+ export declare class PendingRequests {
3
+ private pending;
4
+ create(method: string, params?: Record<string, unknown>, timeoutMs?: number): {
5
+ request: JsonRpcRequest;
6
+ promise: Promise<unknown>;
7
+ };
8
+ resolve(id: string, result: unknown): boolean;
9
+ reject(id: string, error: JsonRpcError): boolean;
10
+ rejectAll(error: JsonRpcError): void;
11
+ get size(): number;
12
+ }
13
+ //# sourceMappingURL=pending-requests.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pending-requests.d.ts","sourceRoot":"","sources":["../../src/utils/pending-requests.ts"],"names":[],"mappings":"AACA,OAAO,EAAkC,KAAK,cAAc,EAAE,KAAK,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAUxG,qBAAa,eAAe;IAC1B,OAAO,CAAC,OAAO,CAAqC;IAEpD,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS,SAAqB,GAAG;QACxF,OAAO,EAAE,cAAc,CAAC;QACxB,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;KAC3B;IAyBD,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,OAAO;IAU7C,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,GAAG,OAAO;IAUhD,SAAS,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI;IASpC,IAAI,IAAI,IAAI,MAAM,CAEjB;CACF"}
@@ -0,0 +1,59 @@
1
+ import { v4 as uuidv4 } from "uuid";
2
+ import { ErrorCodes, DEFAULT_TIMEOUT_MS } from "../protocol.js";
3
+ import { logger } from "./logger.js";
4
+ export class PendingRequests {
5
+ pending = new Map();
6
+ create(method, params, timeoutMs = DEFAULT_TIMEOUT_MS) {
7
+ const id = uuidv4();
8
+ const request = {
9
+ jsonrpc: "2.0",
10
+ id,
11
+ method,
12
+ ...(params && { params }),
13
+ };
14
+ const promise = new Promise((resolve, reject) => {
15
+ const timer = setTimeout(() => {
16
+ this.pending.delete(id);
17
+ logger.warn(`Request timed out: ${method} (${id})`);
18
+ reject({
19
+ code: ErrorCodes.TIMEOUT,
20
+ message: `Request timed out after ${timeoutMs}ms`,
21
+ });
22
+ }, timeoutMs);
23
+ this.pending.set(id, { resolve, reject, timer, method });
24
+ });
25
+ return { request, promise };
26
+ }
27
+ resolve(id, result) {
28
+ const pending = this.pending.get(id);
29
+ if (!pending)
30
+ return false;
31
+ clearTimeout(pending.timer);
32
+ this.pending.delete(id);
33
+ logger.debug(`Request resolved: ${pending.method} (${id})`);
34
+ pending.resolve(result);
35
+ return true;
36
+ }
37
+ reject(id, error) {
38
+ const pending = this.pending.get(id);
39
+ if (!pending)
40
+ return false;
41
+ clearTimeout(pending.timer);
42
+ this.pending.delete(id);
43
+ logger.debug(`Request rejected: ${pending.method} (${id})`);
44
+ pending.reject(error);
45
+ return true;
46
+ }
47
+ rejectAll(error) {
48
+ for (const [id, pending] of this.pending) {
49
+ clearTimeout(pending.timer);
50
+ logger.debug(`Rejecting pending request: ${pending.method} (${id})`);
51
+ pending.reject(error);
52
+ }
53
+ this.pending.clear();
54
+ }
55
+ get size() {
56
+ return this.pending.size;
57
+ }
58
+ }
59
+ //# sourceMappingURL=pending-requests.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pending-requests.js","sourceRoot":"","sources":["../../src/utils/pending-requests.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import { type JsonRpcEvent } from "./protocol.js";
2
+ type EventHandler = (event: JsonRpcEvent) => void;
3
+ export declare class BridgeWebSocketServer {
4
+ private wss;
5
+ private client;
6
+ private pendingRequests;
7
+ private keepaliveTimer;
8
+ private eventHandlers;
9
+ get isConnected(): boolean;
10
+ start(): void;
11
+ stop(): void;
12
+ send(method: string, params?: Record<string, unknown>, timeoutMs?: number): Promise<unknown>;
13
+ on(event: string, handler: EventHandler): void;
14
+ private handleMessage;
15
+ private startKeepalive;
16
+ private stopKeepalive;
17
+ }
18
+ export {};
19
+ //# sourceMappingURL=ws-server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ws-server.d.ts","sourceRoot":"","sources":["../src/ws-server.ts"],"names":[],"mappings":"AACA,OAAO,EAML,KAAK,YAAY,EAGlB,MAAM,eAAe,CAAC;AAIvB,KAAK,YAAY,GAAG,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;AAElD,qBAAa,qBAAqB;IAChC,OAAO,CAAC,GAAG,CAAgC;IAC3C,OAAO,CAAC,MAAM,CAA0B;IACxC,OAAO,CAAC,eAAe,CAAyB;IAChD,OAAO,CAAC,cAAc,CAA+C;IACrE,OAAO,CAAC,aAAa,CAAqC;IAE1D,IAAI,WAAW,IAAI,OAAO,CAEzB;IAED,KAAK,IAAI,IAAI;IAkEb,IAAI,IAAI,IAAI;IAgBN,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAclG,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,IAAI;IAM9C,OAAO,CAAC,aAAa;IA4CrB,OAAO,CAAC,cAAc;IAUtB,OAAO,CAAC,aAAa;CAMtB"}
@@ -0,0 +1,160 @@
1
+ import { WebSocketServer, WebSocket } from "ws";
2
+ import { ErrorCodes, KEEPALIVE_INTERVAL_MS, WS_PORT, } from "./protocol.js";
3
+ import { PendingRequests } from "./utils/pending-requests.js";
4
+ import { logger } from "./utils/logger.js";
5
+ export class BridgeWebSocketServer {
6
+ wss = null;
7
+ client = null;
8
+ pendingRequests = new PendingRequests();
9
+ keepaliveTimer = null;
10
+ eventHandlers = new Map();
11
+ get isConnected() {
12
+ return this.client !== null && this.client.readyState === WebSocket.OPEN;
13
+ }
14
+ start() {
15
+ this.wss = new WebSocketServer({
16
+ host: "127.0.0.1",
17
+ port: WS_PORT,
18
+ verifyClient: (info) => {
19
+ const origin = info.origin || info.req.headers.origin || "";
20
+ // Allow any Chromium-based browser extension (Chrome, Brave, Edge, Arc, Vivaldi, etc.)
21
+ // Localhost-only binding (127.0.0.1) provides the primary security boundary.
22
+ const allowed = origin === "" ||
23
+ origin.endsWith("-extension://") ||
24
+ origin.startsWith("chrome-extension://");
25
+ if (!allowed) {
26
+ logger.warn(`Rejected connection from origin: ${origin}`);
27
+ return false;
28
+ }
29
+ logger.info(`Accepted connection from origin: ${origin || "(empty)"}`);
30
+ return true;
31
+ },
32
+ });
33
+ this.wss.on("listening", () => {
34
+ logger.info(`WebSocket server listening on 127.0.0.1:${WS_PORT}`);
35
+ });
36
+ this.wss.on("connection", (ws, req) => {
37
+ const origin = req.headers.origin || "unknown";
38
+ logger.info(`Extension connected from ${origin}`);
39
+ // Single client - close existing connection cleanly before reassigning
40
+ if (this.client && this.client.readyState === WebSocket.OPEN) {
41
+ logger.info("Replacing existing client connection");
42
+ const oldClient = this.client;
43
+ this.client = null; // Detach first so the old close handler is a no-op
44
+ oldClient.close(1000, "Replaced by new connection");
45
+ }
46
+ this.client = ws;
47
+ this.startKeepalive();
48
+ ws.on("message", (data) => {
49
+ this.handleMessage(data.toString());
50
+ });
51
+ ws.on("close", (code, reason) => {
52
+ logger.info(`Extension disconnected: ${code} ${reason.toString()}`);
53
+ if (this.client === ws) {
54
+ this.client = null;
55
+ this.stopKeepalive();
56
+ this.pendingRequests.rejectAll({
57
+ code: ErrorCodes.NOT_CONNECTED,
58
+ message: "Extension disconnected",
59
+ });
60
+ }
61
+ });
62
+ ws.on("error", (err) => {
63
+ logger.error("WebSocket client error", err.message);
64
+ });
65
+ });
66
+ this.wss.on("error", (err) => {
67
+ logger.error("WebSocket server error", err.message);
68
+ });
69
+ }
70
+ stop() {
71
+ this.stopKeepalive();
72
+ if (this.client) {
73
+ this.client.close(1000, "Server shutting down");
74
+ this.client = null;
75
+ }
76
+ this.pendingRequests.rejectAll({
77
+ code: ErrorCodes.INTERNAL_ERROR,
78
+ message: "Server shutting down",
79
+ });
80
+ if (this.wss) {
81
+ this.wss.close();
82
+ this.wss = null;
83
+ }
84
+ }
85
+ async send(method, params, timeoutMs) {
86
+ if (!this.isConnected) {
87
+ throw {
88
+ code: ErrorCodes.NOT_CONNECTED,
89
+ message: "No Chrome extension connected. Please open the extension and check the connection.",
90
+ };
91
+ }
92
+ const { request, promise } = this.pendingRequests.create(method, params, timeoutMs);
93
+ logger.debug(`Sending request: ${method}`, request);
94
+ this.client.send(JSON.stringify(request));
95
+ return promise;
96
+ }
97
+ on(event, handler) {
98
+ const handlers = this.eventHandlers.get(event) || [];
99
+ handlers.push(handler);
100
+ this.eventHandlers.set(event, handlers);
101
+ }
102
+ handleMessage(raw) {
103
+ // Handle keepalive
104
+ if (raw === "pong") {
105
+ logger.debug("Received pong");
106
+ return;
107
+ }
108
+ let message;
109
+ try {
110
+ message = JSON.parse(raw);
111
+ }
112
+ catch {
113
+ logger.warn("Failed to parse message", raw);
114
+ return;
115
+ }
116
+ // Response to a pending request
117
+ if ("id" in message && message.id !== null && ("result" in message || "error" in message)) {
118
+ const response = message;
119
+ if (response.error) {
120
+ this.pendingRequests.reject(response.id, response.error);
121
+ }
122
+ else {
123
+ this.pendingRequests.resolve(response.id, response.result);
124
+ }
125
+ return;
126
+ }
127
+ // Unsolicited event from extension
128
+ if ("method" in message && ("id" in message ? message.id === null : true)) {
129
+ const event = message;
130
+ logger.debug(`Received event: ${event.method}`);
131
+ const handlers = this.eventHandlers.get(event.method) || [];
132
+ for (const handler of handlers) {
133
+ try {
134
+ handler(event);
135
+ }
136
+ catch (err) {
137
+ logger.error(`Event handler error for ${event.method}`, err);
138
+ }
139
+ }
140
+ return;
141
+ }
142
+ logger.warn("Unhandled message", message);
143
+ }
144
+ startKeepalive() {
145
+ this.stopKeepalive();
146
+ this.keepaliveTimer = setInterval(() => {
147
+ if (this.isConnected) {
148
+ this.client.send("ping");
149
+ logger.debug("Sent ping");
150
+ }
151
+ }, KEEPALIVE_INTERVAL_MS);
152
+ }
153
+ stopKeepalive() {
154
+ if (this.keepaliveTimer) {
155
+ clearInterval(this.keepaliveTimer);
156
+ this.keepaliveTimer = null;
157
+ }
158
+ }
159
+ }
160
+ //# sourceMappingURL=ws-server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ws-server.js","sourceRoot":"","sources":["../src/ws-server.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "mcp-browser-bridge",
3
+ "version": "1.1.0",
4
+ "description": "MCP server that bridges AI assistants to the browser via a WebSocket-connected extension",
5
+ "type": "module",
6
+ "bin": {
7
+ "mcp-browser-bridge": "./dist/index.js"
8
+ },
9
+ "files": [
10
+ "dist/"
11
+ ],
12
+ "scripts": {
13
+ "build": "tsc",
14
+ "dev": "tsc --watch",
15
+ "prepublishOnly": "npm run build"
16
+ },
17
+ "engines": {
18
+ "node": ">=18"
19
+ },
20
+ "keywords": [
21
+ "mcp",
22
+ "browser",
23
+ "chrome",
24
+ "automation",
25
+ "testing",
26
+ "screenshot",
27
+ "websocket",
28
+ "model-context-protocol"
29
+ ],
30
+ "author": "adbarc92",
31
+ "license": "MIT",
32
+ "repository": {
33
+ "type": "git",
34
+ "url": "https://github.com/adbarc92/mcp-browser-bridge.git"
35
+ },
36
+ "dependencies": {
37
+ "@modelcontextprotocol/sdk": "^1.12.1",
38
+ "uuid": "^11.1.0",
39
+ "ws": "^8.18.0",
40
+ "zod": "^3.24.2"
41
+ },
42
+ "devDependencies": {
43
+ "@types/node": "^22.13.4",
44
+ "@types/uuid": "^10.0.0",
45
+ "@types/ws": "^8.18.0",
46
+ "typescript": "^5.7.3"
47
+ }
48
+ }