kibbutz-mcp 1.0.1 → 1.0.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.
Files changed (2) hide show
  1. package/build/index.js +75 -59
  2. package/package.json +1 -1
package/build/index.js CHANGED
@@ -8,13 +8,15 @@ import { z } from 'zod';
8
8
  import { spawn } from 'child_process';
9
9
  import fs from 'fs';
10
10
  import path from 'path';
11
- let wss;
12
- let extensionSocket = null;
11
+ let mcpSocket = null;
12
+ let socket = null;
13
13
  let token = null;
14
+ let port = null;
15
+ let wsPromise = null;
14
16
  const map = new Map();
15
17
  const server = new McpServer({
16
18
  name: 'kibbutz-mcp',
17
- version: '1.0.1',
19
+ version: '1.0.2',
18
20
  });
19
21
  function findChromeExecutable() {
20
22
  const platform = process.platform;
@@ -56,20 +58,36 @@ function openChromeWithExtension(wsPort) {
56
58
  });
57
59
  child.unref();
58
60
  }
59
- const sendAndWaitForReply = (message, args) => {
60
- if (!extensionSocket || extensionSocket.readyState !== WebSocket.OPEN) {
61
+ const sendAndWaitForReply = async (message, args) => {
62
+ if (!token) {
63
+ try {
64
+ await new Promise((resolve, reject) => {
65
+ const timeout = setTimeout(() => {
66
+ wsPromise = null;
67
+ reject(new Error('Timeout waiting for MCP extension WebSocket connection'));
68
+ }, 10000);
69
+ wsPromise = () => {
70
+ clearTimeout(timeout);
71
+ resolve();
72
+ };
73
+ openChromeWithExtension(port);
74
+ });
75
+ }
76
+ catch (error) { }
77
+ }
78
+ if (!mcpSocket || mcpSocket.readyState !== WebSocket.OPEN) {
61
79
  return Promise.resolve({
62
80
  content: [
63
81
  {
64
82
  type: 'text',
65
83
  text: `Connection failed: The MCP server cannot reach the Chrome extension.
66
84
 
67
- Please check the following:
68
- 1. Is the browser open?
69
- 2. Is the MCP switch inside the extension popup turned ON?
85
+ Please check the following:
86
+ 1. Is the browser open?
87
+ 2. Is the MCP switch inside the extension popup turned ON?
70
88
 
71
- If the issue persists, copy and paste this URL into your browser address bar:
72
- chrome-extension://bpfjmggaaiigpfahhmpmacfhlemnhhip/kibbutz-mcp.html`,
89
+ If the issue persists, copy and paste this URL into your browser address bar:
90
+ chrome-extension://bpfjmggaaiigpfahhmpmacfhlemnhhip/KIBBUTZ-MCP.html`,
73
91
  },
74
92
  ],
75
93
  isError: true,
@@ -86,7 +104,7 @@ chrome-extension://bpfjmggaaiigpfahhmpmacfhlemnhhip/kibbutz-mcp.html`,
86
104
  },
87
105
  reject,
88
106
  });
89
- extensionSocket?.send(JSON.stringify({
107
+ mcpSocket?.send(JSON.stringify({
90
108
  id,
91
109
  message,
92
110
  args,
@@ -220,30 +238,28 @@ server.registerTool('UPDATE_GROUP_MCP', {
220
238
  },
221
239
  }, (args) => sendAndWaitForReply('UPDATE_GROUP_MCP', args));
222
240
  async function main() {
223
- const httpServer = createServer((req, res) => {
224
- try {
225
- const url = new URL(req.url || '', `http://${req.headers.host}`);
226
- const retToken = url.searchParams.get('token');
227
- const verify = retToken === token;
228
- if (verify) {
229
- token = uuidv4();
241
+ const httpServer = createServer();
242
+ const wss = new WebSocketServer({ noServer: true });
243
+ const wssMcp = new WebSocketServer({ noServer: true });
244
+ wss.on('connection', (ws) => {
245
+ socket = ws;
246
+ ws.on('error', console.error);
247
+ ws.on('close', () => {
248
+ if (socket === ws) {
249
+ socket = null;
230
250
  }
231
- res.writeHead(404);
232
- res.end(JSON.stringify({ verify }));
233
- }
234
- catch (e) {
235
- console.error('Failed to parse URL:', req.url, e);
236
- res.writeHead(404);
237
- res.end(JSON.stringify({ verify: false }));
238
- }
251
+ });
239
252
  });
240
- wss = new WebSocketServer({ noServer: true });
241
- wss.on('connection', (ws, request) => {
242
- extensionSocket = ws;
253
+ wssMcp.on('connection', (ws) => {
254
+ mcpSocket = ws;
255
+ if (wsPromise) {
256
+ wsPromise();
257
+ wsPromise = null;
258
+ }
243
259
  ws.on('error', console.error);
244
260
  ws.on('close', () => {
245
- if (extensionSocket === ws) {
246
- extensionSocket = null;
261
+ if (mcpSocket === ws) {
262
+ mcpSocket = null;
247
263
  }
248
264
  for (const { reject } of map.values()) {
249
265
  reject(new Error('Extension WebSocket closed'));
@@ -251,49 +267,49 @@ async function main() {
251
267
  map.clear();
252
268
  });
253
269
  ws.on('message', (data) => {
254
- try {
255
- const text = data.toString();
256
- if (text === 'ping')
257
- return;
258
- const response = JSON.parse(text);
259
- if (response.id && map.has(response.id)) {
260
- const pending = map.get(response.id);
261
- pending.resolve(response.result);
262
- map.delete(response.id);
263
- }
264
- }
265
- catch (_e) {
266
- console.error('Failed to parse message from extension:', data);
270
+ const text = data.toString();
271
+ const response = JSON.parse(text);
272
+ if (response.id && map.has(response.id)) {
273
+ const pending = map.get(response.id);
274
+ pending.resolve(response.result);
275
+ map.delete(response.id);
267
276
  }
268
277
  });
269
278
  });
270
279
  httpServer.on('upgrade', (request, socket, head) => {
271
- if (request.headers.origin !== 'chrome-extension://bpfjmggaaiigpfahhmpmacfhlemnhhip') {
280
+ if (request.headers['sec-websocket-protocol'] !== token) {
272
281
  socket.write('HTTP/1.1 401 Unauthorized\r\n\r\n');
273
282
  socket.destroy();
274
283
  return;
275
284
  }
276
- wss.clients.forEach((ws) => ws.terminate());
277
- wss.handleUpgrade(request, socket, head, (ws) => {
278
- wss.emit('connection', ws, request);
279
- });
285
+ const { pathname } = new URL(request.url || '', `wss:127.0.0.1:${port}`);
286
+ if (pathname === '/ping') {
287
+ wss.clients.forEach((ws) => ws.terminate());
288
+ wss.handleUpgrade(request, socket, head, (ws) => {
289
+ wss.emit('connection', ws, request);
290
+ });
291
+ }
292
+ else if (pathname === '/mcp') {
293
+ wssMcp.clients.forEach((ws) => ws.terminate());
294
+ wssMcp.handleUpgrade(request, socket, head, (ws) => {
295
+ wssMcp.emit('connection', ws, request);
296
+ });
297
+ }
280
298
  });
281
299
  httpServer.listen(0, () => {
282
- const port = httpServer.address().port;
283
- openChromeWithExtension(port);
300
+ port = httpServer.address().port;
284
301
  });
285
302
  const transport = new StdioServerTransport();
286
303
  await server.connect(transport);
287
304
  process.stdin.on('end', () => {
288
- try {
289
- openChromeWithExtension(0);
290
- }
291
- catch (err) {
292
- console.error('Failed to open Chrome with extension:', err);
293
- }
305
+ wss.clients.forEach((ws) => ws.terminate());
306
+ wssMcp.clients.forEach((ws) => ws.terminate());
307
+ });
308
+ process.on('SIGTERM', () => {
309
+ wss.clients.forEach((ws) => ws.terminate());
310
+ wssMcp.clients.forEach((ws) => ws.terminate());
294
311
  });
295
312
  }
296
- main().catch((error) => {
297
- console.error('Server error:', error);
313
+ main().catch(() => {
298
314
  process.exit(1);
299
315
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kibbutz-mcp",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "",
5
5
  "main": "build/index.js",
6
6
  "scripts": {