mcp-log-query-server 3.1.0 → 3.3.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/config.js CHANGED
@@ -314,6 +314,24 @@ export const SERVICES = {
314
314
  logPath: '/www/logs/clife-senior-work-order-center-app/normal_logs',
315
315
  logFile: 'normal.log',
316
316
  aliases: ['work-order-center', 'work-order', '工单中心', '工单']
317
+ },
318
+ 'clife-senior-station-assistant-bff': {
319
+ name: 'clife-senior-station-assistant-bff',
320
+ description: '养老驿站助手BFF服务',
321
+ namespace: 'saas-itest',
322
+ podPattern: 'clife-senior-station-assistant-bff-app',
323
+ logPath: '/www/logs/clife-senior-station-assistant-bff-app/normal_logs',
324
+ logFile: 'normal.log',
325
+ aliases: ['station-assistant-bff', 'station-assistant', '驿站助手', '驿站BFF']
326
+ },
327
+ 'clife-senior-third-bff': {
328
+ name: 'clife-senior-third-bff',
329
+ description: '养老第三方BFF服务',
330
+ namespace: 'saas-itest',
331
+ podPattern: 'clife-senior-third-bff-app',
332
+ logPath: '/www/logs/clife-senior-third-bff-app/normal_logs',
333
+ logFile: 'normal.log',
334
+ aliases: ['third-bff', '第三方BFF']
317
335
  }
318
336
  };
319
337
 
package/index.js CHANGED
@@ -34,6 +34,23 @@ import {
34
34
  listLokiEnvironments as getLokiEnvList, listLokiServices as getLokiSvcList
35
35
  } from './loki-client.js';
36
36
 
37
+ // 超时配置
38
+ const REQUEST_TIMEOUT = 60000; // MCP 请求兜底超时 60s
39
+ const WATCHDOG_TIMEOUT = 120000; // 进程看门狗 120s,卡死则强制退出
40
+
41
+ function withTimeout(promise, ms, label) {
42
+ return Promise.race([
43
+ promise,
44
+ new Promise((_, reject) =>
45
+ setTimeout(() => reject(new Error(`${label} 超时(${ms}ms)`)), ms)
46
+ ),
47
+ ]);
48
+ }
49
+
50
+ // 进程级安全网
51
+ process.on('unhandledRejection', (err) => console.error('[unhandledRejection]', err));
52
+ process.on('uncaughtException', (err) => { console.error('[uncaughtException]', err); process.exit(1); });
53
+
37
54
  // 创建 MCP Server
38
55
  const server = new Server(
39
56
  {
@@ -320,7 +337,38 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
320
337
  // 处理工具调用
321
338
  server.setRequestHandler(CallToolRequestSchema, async (request) => {
322
339
  const { name, arguments: args } = request.params;
340
+ const startTime = Date.now();
341
+
342
+ // 进程级看门狗:如果整个请求卡死超时,强制重启进程
343
+ const watchdog = setTimeout(() => {
344
+ console.error(`[Watchdog] ${name} 卡死超过 ${WATCHDOG_TIMEOUT}ms,强制退出进程`);
345
+ process.exit(1);
346
+ }, WATCHDOG_TIMEOUT);
347
+ watchdog.unref();
348
+
349
+ try {
350
+ const result = await withTimeout(
351
+ handleToolCall(name, args),
352
+ REQUEST_TIMEOUT,
353
+ name
354
+ );
355
+ clearTimeout(watchdog);
356
+ console.error(`[MCP] ${name} ${Date.now() - startTime}ms`);
357
+ return result;
358
+ } catch (error) {
359
+ clearTimeout(watchdog);
360
+ console.error(`[Error] ${name} ${Date.now() - startTime}ms: ${error.message}`);
361
+ return {
362
+ content: [{ type: 'text', text: `## 执行错误\n\n❌ ${error.message}` }],
363
+ isError: true
364
+ };
365
+ }
366
+ });
323
367
 
368
+ /**
369
+ * 实际的工具调用处理逻辑
370
+ */
371
+ async function handleToolCall(name, args) {
324
372
  try {
325
373
  switch (name) {
326
374
  case 'query_log': {
@@ -741,7 +789,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
741
789
  };
742
790
  }
743
791
  } catch (error) {
744
- console.error(`[MCP] 错误: ${error.message}`);
792
+ console.error(`[MCP] 工具内部错误: ${error.message}`);
745
793
  return {
746
794
  content: [{
747
795
  type: 'text',
@@ -750,13 +798,13 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
750
798
  isError: true
751
799
  };
752
800
  }
753
- });
801
+ }
754
802
 
755
803
  // 启动服务器
756
804
  async function main() {
757
805
  const transport = new StdioServerTransport();
758
806
  await server.connect(transport);
759
- console.error('[MCP] Log Query Server v3.1.0 已启动 (支持 Loki 生产环境日志)');
807
+ console.error('[MCP] Log Query Server v3.2.0 已启动 (支持超时保护 + 进程看门狗)');
760
808
  }
761
809
 
762
810
  main().catch((error) => {
package/loki-client.js CHANGED
@@ -11,6 +11,9 @@
11
11
 
12
12
  import { LOKI_ENVIRONMENTS, LOKI_DEFAULTS } from './config.js';
13
13
 
14
+ // Loki 查询超时(毫秒)
15
+ const LOKI_FETCH_TIMEOUT = 30000;
16
+
14
17
  // 时间范围自动递进策略(毫秒)
15
18
  const AUTO_RANGE_STEPS = [
16
19
  { range: 5 * 60 * 1000, label: '5 分钟' },
@@ -63,11 +66,27 @@ export async function queryLoki(envName, expr, options = {}) {
63
66
 
64
67
  console.error(`[Loki] 查询: env=${envName}, expr=${expr}`);
65
68
 
66
- const resp = await fetch(url, {
67
- method: 'POST',
68
- headers: buildHeaders(env),
69
- body: JSON.stringify(body)
70
- });
69
+ // 带超时的 fetch
70
+ const controller = new AbortController();
71
+ const timer = setTimeout(() => controller.abort(), LOKI_FETCH_TIMEOUT);
72
+
73
+ let resp;
74
+ try {
75
+ resp = await fetch(url, {
76
+ method: 'POST',
77
+ headers: buildHeaders(env),
78
+ body: JSON.stringify(body),
79
+ signal: controller.signal
80
+ });
81
+ } catch (e) {
82
+ clearTimeout(timer);
83
+ if (e.name === 'AbortError') {
84
+ throw new Error(`Loki 查询超时(${LOKI_FETCH_TIMEOUT}ms)`);
85
+ }
86
+ throw e;
87
+ } finally {
88
+ clearTimeout(timer);
89
+ }
71
90
 
72
91
  if (!resp.ok) {
73
92
  const text = await resp.text();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mcp-log-query-server",
3
- "version": "3.1.0",
3
+ "version": "3.3.0",
4
4
  "description": "MCP Server for querying server logs via SSH jump host and Grafana Loki API",
5
5
  "main": "index.js",
6
6
  "type": "module",