lark-mcp-server 0.0.7 → 0.0.10

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/index.js +127 -3
  2. package/package.json +2 -1
package/index.js CHANGED
@@ -5,6 +5,13 @@ import EventSource from 'eventsource';
5
5
  import fs from 'fs';
6
6
  import os from 'os';
7
7
  import path from 'path';
8
+ import { fileURLToPath } from 'url';
9
+
10
+ // 获取当前包版本
11
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
12
+ const packageJson = JSON.parse(fs.readFileSync(path.join(__dirname, 'package.json'), 'utf-8'));
13
+ const CURRENT_VERSION = packageJson.version;
14
+ const PACKAGE_NAME = packageJson.name;
8
15
 
9
16
  // 解析命令行参数
10
17
  const args = process.argv.slice(2);
@@ -16,7 +23,7 @@ for (const arg of args) {
16
23
  }
17
24
  }
18
25
 
19
- const SERVER_URL = params.server || 'https://basic.dev.peblla.top';
26
+ const SERVER_URL = params.server || 'https://basic.dev.peblla.top/api/feishu';
20
27
  const USER_NAME = params.user || 'default';
21
28
 
22
29
  // 日志输出到 stderr,不影响 stdio 通信
@@ -26,6 +33,79 @@ const log = (...args) => console.error('[lark-mcp-proxy]', ...args);
26
33
  const TOKEN_DIR = path.join(os.homedir(), '.lark-mcp');
27
34
  const TOKEN_FILE = path.join(TOKEN_DIR, 'tokens.json');
28
35
 
36
+ // 版本检测配置
37
+ const VERSION_CHECK_FILE = path.join(TOKEN_DIR, 'version-check.json');
38
+ const VERSION_CHECK_INTERVAL = 24 * 60 * 60 * 1000; // 24 小时检查一次
39
+
40
+ // 检查是否需要更新
41
+ async function checkForUpdates() {
42
+ try {
43
+ // 检查上次检查时间,避免频繁请求
44
+ let lastCheck = 0;
45
+ if (fs.existsSync(VERSION_CHECK_FILE)) {
46
+ const data = JSON.parse(fs.readFileSync(VERSION_CHECK_FILE, 'utf-8'));
47
+ lastCheck = data.lastCheck || 0;
48
+ }
49
+
50
+ if (Date.now() - lastCheck < VERSION_CHECK_INTERVAL) {
51
+ return; // 24小时内已检查过
52
+ }
53
+
54
+ // 从 npm registry 获取最新版本
55
+ const res = await fetch(`https://registry.npmmirror.com/${PACKAGE_NAME}/latest`, {
56
+ timeout: 5000,
57
+ });
58
+
59
+ if (!res.ok) return;
60
+
61
+ const data = await res.json();
62
+ const latestVersion = data.version;
63
+
64
+ // 保存检查时间
65
+ if (!fs.existsSync(TOKEN_DIR)) {
66
+ fs.mkdirSync(TOKEN_DIR, { recursive: true, mode: 0o700 });
67
+ }
68
+ fs.writeFileSync(VERSION_CHECK_FILE, JSON.stringify({
69
+ lastCheck: Date.now(),
70
+ latestVersion,
71
+ }), { mode: 0o600 });
72
+
73
+ // 比较版本
74
+ if (latestVersion && latestVersion !== CURRENT_VERSION) {
75
+ if (compareVersions(latestVersion, CURRENT_VERSION) > 0) {
76
+ log('');
77
+ log('╔════════════════════════════════════════════════════════════╗');
78
+ log('║ 🚀 New version available! ║');
79
+ log(`║ Current: ${CURRENT_VERSION.padEnd(10)} → Latest: ${latestVersion.padEnd(10)} ║`);
80
+ log('║ ║');
81
+ log('║ To update, run: ║');
82
+ log('║ npx lark-mcp-server@latest --user=YOUR_USER ║');
83
+ log('║ ║');
84
+ log('║ Or clear npx cache: ║');
85
+ log('║ rm -rf ~/.npm/_npx/*lark* && restart your IDE ║');
86
+ log('╚════════════════════════════════════════════════════════════╝');
87
+ log('');
88
+ }
89
+ }
90
+ } catch (e) {
91
+ // 版本检查失败不影响正常使用
92
+ }
93
+ }
94
+
95
+ // 版本比较函数
96
+ function compareVersions(v1, v2) {
97
+ const parts1 = v1.split('.').map(Number);
98
+ const parts2 = v2.split('.').map(Number);
99
+
100
+ for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) {
101
+ const p1 = parts1[i] || 0;
102
+ const p2 = parts2[i] || 0;
103
+ if (p1 > p2) return 1;
104
+ if (p1 < p2) return -1;
105
+ }
106
+ return 0;
107
+ }
108
+
29
109
  // 加载本地 token
30
110
  function loadLocalToken(userName) {
31
111
  try {
@@ -108,12 +188,43 @@ async function refreshLocalToken() {
108
188
  }
109
189
  }
110
190
 
191
+ // 优雅退出
192
+ function gracefulExit(reason) {
193
+ log(`Exiting: ${reason}`);
194
+ process.exit(0);
195
+ }
196
+
197
+ // 处理退出信号
198
+ process.on('SIGTERM', () => gracefulExit('SIGTERM'));
199
+ process.on('SIGINT', () => gracefulExit('SIGINT'));
200
+ process.on('SIGHUP', () => gracefulExit('SIGHUP'));
201
+
202
+ // 检测父进程是否存活(每 30 秒检查一次)
203
+ const PARENT_CHECK_INTERVAL = 30000;
204
+ const parentPid = process.ppid;
205
+
206
+ const parentCheckTimer = setInterval(() => {
207
+ try {
208
+ process.kill(parentPid, 0);
209
+ } catch (e) {
210
+ gracefulExit('Parent process exited');
211
+ }
212
+ }, PARENT_CHECK_INTERVAL);
213
+
214
+ // 让定时器不阻止进程退出
215
+ parentCheckTimer.unref();
216
+
111
217
  // 存储 messages endpoint 和授权 URL
112
218
  let messagesEndpoint = null;
113
219
  let authUrl = null;
114
220
  let sseConnected = false;
115
221
  let pendingRequests = new Map();
116
222
 
223
+ // SSE 重连配置
224
+ const MAX_RECONNECT_ATTEMPTS = 10;
225
+ const RECONNECT_INTERVAL = 3000;
226
+ let reconnectAttempts = 0;
227
+
117
228
  function normalizeEndpoint(endpoint) {
118
229
  try {
119
230
  const url = new URL(endpoint);
@@ -139,6 +250,7 @@ function connectSSE() {
139
250
  messagesEndpoint = normalizeEndpoint(event.data);
140
251
  log(`Got endpoint: ${messagesEndpoint}`);
141
252
  sseConnected = true;
253
+ reconnectAttempts = 0; // 连接成功,重置重试计数
142
254
  });
143
255
 
144
256
  // 监听 token 事件(OAuth 回调后服务器推送)
@@ -198,7 +310,15 @@ function connectSSE() {
198
310
  log('SSE error, reconnecting...');
199
311
  sseConnected = false;
200
312
  es.close();
201
- setTimeout(connectSSE, 3000);
313
+
314
+ reconnectAttempts++;
315
+ if (reconnectAttempts >= MAX_RECONNECT_ATTEMPTS) {
316
+ log(`Max reconnect attempts (${MAX_RECONNECT_ATTEMPTS}) reached, exiting`);
317
+ process.exit(1);
318
+ }
319
+
320
+ log(`Reconnect attempt ${reconnectAttempts}/${MAX_RECONNECT_ATTEMPTS}`);
321
+ setTimeout(connectSSE, RECONNECT_INTERVAL);
202
322
  };
203
323
  }
204
324
 
@@ -328,6 +448,10 @@ process.stdin.on('end', () => {
328
448
  });
329
449
 
330
450
  // 启动
331
- log(`Starting proxy for user: ${USER_NAME}`);
451
+ log(`Starting proxy for user: ${USER_NAME} (v${CURRENT_VERSION})`);
332
452
  log(`Server: ${SERVER_URL}`);
453
+
454
+ // 异步检查更新(不阻塞启动)
455
+ checkForUpdates();
456
+
333
457
  connectSSE();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lark-mcp-server",
3
- "version": "0.0.7",
3
+ "version": "0.0.10",
4
4
  "description": "飞书 MCP 本地代理 - 让 AI 编程工具读取飞书文档,Token 本地安全存储",
5
5
  "type": "module",
6
6
  "bin": {
@@ -8,6 +8,7 @@
8
8
  },
9
9
  "files": [
10
10
  "index.js",
11
+ "package.json",
11
12
  "README.md"
12
13
  ],
13
14
  "keywords": [