what-devtools-mcp 0.6.0 → 0.6.2

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/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "what-devtools-mcp",
3
- "version": "0.6.0",
3
+ "version": "0.6.2",
4
4
  "description": "MCP server bridging AI agents to live What Framework app state via WebSocket",
5
5
  "type": "module",
6
6
  "bin": {
7
- "what-devtools-mcp": "./src/index.js"
7
+ "what-devtools-mcp": "src/index.js"
8
8
  },
9
9
  "exports": {
10
10
  ".": "./src/index.js",
@@ -20,7 +20,7 @@
20
20
  "zod": "^3.25.0"
21
21
  },
22
22
  "peerDependencies": {
23
- "what-devtools": ">=0.6.0"
23
+ "what-devtools": "^0.6.2"
24
24
  },
25
25
  "keywords": [
26
26
  "what-framework",
package/src/bridge.js CHANGED
@@ -5,11 +5,15 @@
5
5
  */
6
6
 
7
7
  import { WebSocketServer } from 'ws';
8
+ import { randomBytes } from 'crypto';
9
+ import { createServer } from 'http';
10
+ import { writeFileSync, mkdirSync } from 'fs';
11
+ import { join } from 'path';
8
12
 
9
13
  const MAX_EVENT_LOG = 1000;
10
14
  const MAX_ERROR_LOG = 100;
11
15
 
12
- export function createBridge({ port = 9229 } = {}) {
16
+ export function createBridge({ port = 9229, host = '127.0.0.1' } = {}) {
13
17
  let latestSnapshot = null;
14
18
  const eventLog = [];
15
19
  const errorLog = [];
@@ -25,7 +29,64 @@ export function createBridge({ port = 9229 } = {}) {
25
29
  // Baseline snapshot for diff tool
26
30
  let baselineSnapshot = null;
27
31
 
28
- const wss = new WebSocketServer({ port });
32
+ // Use a fixed token from env if provided, otherwise generate a random one.
33
+ // Set WHAT_MCP_TOKEN to share the same token between bridge and Vite plugin.
34
+ const authToken = process.env.WHAT_MCP_TOKEN || randomBytes(24).toString('hex');
35
+
36
+ const wss = new WebSocketServer({ host, port, verifyClient: ({ req }) => {
37
+ // Require a valid token query parameter to connect
38
+ try {
39
+ const url = new URL(req.url, `http://${host}:${port}`);
40
+ return url.searchParams.get('token') === authToken;
41
+ } catch {
42
+ return false;
43
+ }
44
+ }});
45
+
46
+ // --- Token Discovery ---
47
+ // Two mechanisms so the browser client can find the token automatically:
48
+ //
49
+ // 1. HTTP endpoint: GET http://localhost:{port+1}/__what_mcp_token returns the token
50
+ // The client fetches this on startup before connecting the WebSocket.
51
+ //
52
+ // 2. File: writes token to node_modules/.cache/what-devtools-mcp/token
53
+ // The Vite plugin reads this at transform time.
54
+
55
+ const discoveryPort = port + 1;
56
+ const httpServer = createServer((req, res) => {
57
+ // CORS headers so the browser can fetch from any origin
58
+ res.setHeader('Access-Control-Allow-Origin', '*');
59
+ res.setHeader('Access-Control-Allow-Methods', 'GET');
60
+ res.setHeader('Cache-Control', 'no-store');
61
+
62
+ if (req.url === '/__what_mcp_token') {
63
+ res.writeHead(200, { 'Content-Type': 'application/json' });
64
+ res.end(JSON.stringify({ token: authToken, wsPort: port }));
65
+ } else {
66
+ res.writeHead(404);
67
+ res.end('Not found');
68
+ }
69
+ });
70
+
71
+ httpServer.listen(discoveryPort, host, () => {
72
+ console.error(`[what-devtools-mcp] Token discovery on http://${host}:${discoveryPort}/__what_mcp_token`);
73
+ });
74
+ httpServer.on('error', () => {
75
+ // Discovery port unavailable — not critical, file-based fallback still works
76
+ console.error(`[what-devtools-mcp] Token discovery port ${discoveryPort} unavailable (non-fatal)`);
77
+ });
78
+
79
+ // Write token to a well-known file path for Vite plugin to read
80
+ try {
81
+ const cacheDir = join(process.cwd(), 'node_modules', '.cache', 'what-devtools-mcp');
82
+ mkdirSync(cacheDir, { recursive: true });
83
+ writeFileSync(join(cacheDir, 'token'), JSON.stringify({ token: authToken, port, discoveryPort }));
84
+ } catch {
85
+ // Non-fatal — HTTP discovery is the primary mechanism
86
+ }
87
+
88
+ console.error(`[what-devtools-mcp] Bridge listening on ws://${host}:${port}`);
89
+ console.error(`[what-devtools-mcp] Auth token: ${authToken}`);
29
90
 
30
91
  wss.on('connection', (ws) => {
31
92
  browserSocket = ws;
@@ -130,6 +191,7 @@ export function createBridge({ port = 9229 } = {}) {
130
191
 
131
192
  function saveBaseline() {
132
193
  baselineSnapshot = latestSnapshot ? JSON.parse(JSON.stringify(latestSnapshot)) : null;
194
+ if (baselineSnapshot) baselineSnapshot._savedAt = Date.now();
133
195
  return !!baselineSnapshot;
134
196
  }
135
197
 
@@ -153,6 +215,7 @@ export function createBridge({ port = 9229 } = {}) {
153
215
  pendingCommands.delete(id);
154
216
  }
155
217
  wss.close();
218
+ httpServer.close();
156
219
  }
157
220
 
158
221
  return {
@@ -167,5 +230,6 @@ export function createBridge({ port = 9229 } = {}) {
167
230
  saveBaseline,
168
231
  getBaseline,
169
232
  close,
233
+ authToken,
170
234
  };
171
235
  }