mcp-log-query-server 1.0.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/README.md ADDED
@@ -0,0 +1,151 @@
1
+ # Log Query MCP Server
2
+
3
+ 通过 SSH 堡垒机查询 Kubernetes 容器日志的 MCP Server。
4
+
5
+ ## 功能
6
+
7
+ - **query_log**: 查询服务容器的最近日志
8
+ - **search_log**: 在日志中搜索关键词
9
+ - **list_services**: 列出可用服务
10
+ - **test_connection**: 测试 SSH 连接
11
+
12
+ ## 安装
13
+
14
+ ```bash
15
+ cd mcp-log-query
16
+ npm install
17
+ ```
18
+
19
+ ## 配置
20
+
21
+ ### 1. 修改服务器配置
22
+
23
+ 编辑 `config.js` 文件,配置:
24
+
25
+ - `JUMP_HOST`: 堡垒机连接信息
26
+ - `K8S_SERVER`: K8s 服务器信息
27
+ - `SERVICES`: 服务/容器映射
28
+
29
+ ### 2. 添加到 VSCode MCP 配置
30
+
31
+ 在 VSCode 设置中添加 MCP Server 配置:
32
+
33
+ **方式一:settings.json**
34
+
35
+ ```json
36
+ {
37
+ "augment.advanced": {
38
+ "mcpServers": [
39
+ {
40
+ "name": "log-query",
41
+ "command": "node",
42
+ "args": ["D:/project/main/aug2api-master/mcp-log-query/index.js"],
43
+ "env": {}
44
+ }
45
+ ]
46
+ }
47
+ }
48
+ ```
49
+
50
+ **方式二:mcp.json**
51
+
52
+ 在项目根目录创建 `.augment/mcp.json`:
53
+
54
+ ```json
55
+ {
56
+ "mcpServers": {
57
+ "log-query": {
58
+ "command": "node",
59
+ "args": ["./mcp-log-query/index.js"]
60
+ }
61
+ }
62
+ }
63
+ ```
64
+
65
+ ## 使用示例
66
+
67
+ ### 查询日志
68
+
69
+ ```
70
+ 帮我查一下 clife-senior-health 的最近 200 行日志
71
+ ```
72
+
73
+ AI 会调用:
74
+ ```json
75
+ {
76
+ "tool": "query_log",
77
+ "arguments": {
78
+ "service": "clife-senior-health",
79
+ "lines": 200
80
+ }
81
+ }
82
+ ```
83
+
84
+ ### 搜索错误
85
+
86
+ ```
87
+ 搜索 health 服务的 error 日志
88
+ ```
89
+
90
+ AI 会调用:
91
+ ```json
92
+ {
93
+ "tool": "search_log",
94
+ "arguments": {
95
+ "service": "health",
96
+ "keyword": "error"
97
+ }
98
+ }
99
+ ```
100
+
101
+ ### 列出服务
102
+
103
+ ```
104
+ 有哪些服务可以查日志?
105
+ ```
106
+
107
+ AI 会调用:
108
+ ```json
109
+ {
110
+ "tool": "list_services",
111
+ "arguments": {}
112
+ }
113
+ ```
114
+
115
+ ## 添加新服务
116
+
117
+ 在 `config.js` 的 `SERVICES` 对象中添加:
118
+
119
+ ```javascript
120
+ 'new-service': {
121
+ name: 'new-service',
122
+ description: '新服务描述',
123
+ namespace: 'saas-itest',
124
+ podPattern: 'new-service-app',
125
+ logPath: '/www/logs/new-service-app/normal_logs/',
126
+ aliases: ['new', '新服务']
127
+ }
128
+ ```
129
+
130
+ ## 故障排除
131
+
132
+ ### 连接超时
133
+
134
+ 1. 检查网络是否能访问堡垒机
135
+ 2. 确认堡垒机账号密码正确
136
+ 3. 增加 `DEFAULTS.connectTimeout` 值
137
+
138
+ ### 命令执行失败
139
+
140
+ 1. 确认 K8s 服务器 IP 正确
141
+ 2. 确认 Pod 名称模式正确
142
+ 3. 确认日志路径存在
143
+
144
+ ### 调试模式
145
+
146
+ 运行时查看 stderr 输出:
147
+
148
+ ```bash
149
+ node index.js 2>&1
150
+ ```
151
+
package/config.js ADDED
@@ -0,0 +1,474 @@
1
+ /**
2
+ * Log Query MCP Server - 配置文件
3
+ *
4
+ * 包含:
5
+ * - 堡垒机连接信息
6
+ * - K8s 服务器信息
7
+ * - 服务/容器映射
8
+ */
9
+
10
+ // 堡垒机配置 - 从环境变量读取
11
+ export const JUMP_HOST = {
12
+ host: process.env.MCP_JUMP_HOST || '',
13
+ port: parseInt(process.env.MCP_JUMP_PORT || '22'),
14
+ username: process.env.MCP_JUMP_USERNAME || '',
15
+ password: process.env.MCP_JUMP_PASSWORD || ''
16
+ };
17
+
18
+ // K8s 服务器配置 - 从环境变量读取
19
+ export const K8S_SERVER = {
20
+ host: process.env.MCP_K8S_HOST || '',
21
+ // 堡垒机选择服务器后的选项
22
+ selectOption: process.env.MCP_K8S_SELECT || '1'
23
+ };
24
+
25
+ // 服务配置映射
26
+ // key: 服务名称
27
+ // value: 容器和日志路径信息
28
+ export const SERVICES = {
29
+ 'clife-senior-admin': {
30
+ name: 'clife-senior-admin',
31
+ description: '养老管理后台服务',
32
+ namespace: 'saas-itest',
33
+ podPattern: 'clife-senior-admin-app',
34
+ logPath: '/www/logs/clife-senior-admin-app/normal_logs',
35
+ logFile: 'normal.log',
36
+ aliases: ['admin', '管理', '后台']
37
+ },
38
+ 'clife-senior-approval': {
39
+ name: 'clife-senior-approval',
40
+ description: '养老审批服务',
41
+ namespace: 'saas-itest',
42
+ podPattern: 'clife-senior-approval-app',
43
+ logPath: '/www/logs/clife-senior-approval-app/normal_logs',
44
+ logFile: 'normal.log',
45
+ aliases: ['approval', '审批']
46
+ },
47
+ 'clife-senior-archives': {
48
+ name: 'clife-senior-archives',
49
+ description: '养老档案服务',
50
+ namespace: 'saas-itest',
51
+ podPattern: 'clife-senior-archives-app',
52
+ logPath: '/www/logs/clife-senior-archives-app/normal_logs',
53
+ logFile: 'normal.log',
54
+ aliases: ['archives', '档案']
55
+ },
56
+ 'clife-senior-assess': {
57
+ name: 'clife-senior-assess',
58
+ description: '养老评估服务',
59
+ namespace: 'saas-itest',
60
+ podPattern: 'clife-senior-assess-app',
61
+ logPath: '/www/logs/clife-senior-assess-app/normal_logs',
62
+ logFile: 'normal.log',
63
+ aliases: ['assess', '评估']
64
+ },
65
+ 'clife-senior-common': {
66
+ name: 'clife-senior-common',
67
+ description: '养老公共服务',
68
+ namespace: 'saas-itest',
69
+ podPattern: 'clife-senior-common-app',
70
+ logPath: '/www/logs/clife-senior-common-app/normal_logs',
71
+ logFile: 'normal.log',
72
+ aliases: ['common', '公共']
73
+ },
74
+ 'clife-senior-core': {
75
+ name: 'clife-senior-core',
76
+ description: '养老核心服务',
77
+ namespace: 'saas-itest',
78
+ podPattern: 'clife-senior-core-app',
79
+ logPath: '/www/logs/clife-senior-core-app/normal_logs',
80
+ logFile: 'normal.log',
81
+ aliases: ['core', '核心']
82
+ },
83
+ 'clife-senior-device-center': {
84
+ name: 'clife-senior-device-center',
85
+ description: '养老设备中心服务',
86
+ namespace: 'saas-itest',
87
+ podPattern: 'clife-senior-device-center-app',
88
+ logPath: '/www/logs/clife-senior-device-center-app/normal_logs',
89
+ logFile: 'normal.log',
90
+ aliases: ['device-center', '设备中心']
91
+ },
92
+ 'clife-senior-device-warn': {
93
+ name: 'clife-senior-device-warn',
94
+ description: '养老设备告警服务',
95
+ namespace: 'saas-itest',
96
+ podPattern: 'clife-senior-device-warn-app',
97
+ logPath: '/www/logs/clife-senior-device-warn-app/normal_logs',
98
+ logFile: 'normal.log',
99
+ aliases: ['device-warn', '设备告警']
100
+ },
101
+ 'clife-senior-dispatch': {
102
+ name: 'clife-senior-dispatch',
103
+ description: '养老调度服务',
104
+ namespace: 'saas-itest',
105
+ podPattern: 'clife-senior-dispatch-app',
106
+ logPath: '/www/logs/clife-senior-dispatch-app/normal_logs',
107
+ logFile: 'normal.log',
108
+ aliases: ['dispatch', '调度']
109
+ },
110
+ 'clife-senior-evaluation': {
111
+ name: 'clife-senior-evaluation',
112
+ description: '养老评价服务',
113
+ namespace: 'saas-itest',
114
+ podPattern: 'clife-senior-evaluation-app',
115
+ logPath: '/www/logs/clife-senior-evaluation-app/normal_logs',
116
+ logFile: 'normal.log',
117
+ aliases: ['evaluation', '评价']
118
+ },
119
+ 'clife-senior-finance-new': {
120
+ name: 'clife-senior-finance-new',
121
+ description: '养老财务服务',
122
+ namespace: 'saas-itest',
123
+ podPattern: 'clife-senior-finance-new-app',
124
+ logPath: '/www/logs/clife-senior-finance-new-app/normal_logs',
125
+ logFile: 'normal.log',
126
+ aliases: ['finance-new', 'finance', '财务']
127
+ },
128
+ 'clife-senior-gateway': {
129
+ name: 'clife-senior-gateway',
130
+ description: '养老网关服务',
131
+ namespace: 'saas-itest',
132
+ podPattern: 'clife-senior-gateway-app',
133
+ logPath: '/www/logs/clife-senior-gateway-app/normal_logs',
134
+ logFile: 'normal.log',
135
+ aliases: ['gateway', '网关']
136
+ },
137
+ 'clife-senior-generate': {
138
+ name: 'clife-senior-generate',
139
+ description: '养老生成服务',
140
+ namespace: 'saas-itest',
141
+ podPattern: 'clife-senior-generate-app',
142
+ logPath: '/www/logs/clife-senior-generate-app/normal_logs',
143
+ logFile: 'normal.log',
144
+ aliases: ['generate', '生成']
145
+ },
146
+ 'clife-senior-gov': {
147
+ name: 'clife-senior-gov',
148
+ description: '养老政务服务',
149
+ namespace: 'saas-itest',
150
+ podPattern: 'clife-senior-gov-app',
151
+ logPath: '/www/logs/clife-senior-gov-app/normal_logs',
152
+ logFile: 'normal.log',
153
+ aliases: ['gov', '政务']
154
+ },
155
+ 'clife-senior-health': {
156
+ name: 'clife-senior-health',
157
+ description: '养老健康服务',
158
+ namespace: 'saas-itest',
159
+ podPattern: 'clife-senior-health-app',
160
+ logPath: '/www/logs/clife-senior-health-app/normal_logs',
161
+ logFile: 'normal.log',
162
+ aliases: ['health', '健康']
163
+ },
164
+ 'clife-senior-health-scene': {
165
+ name: 'clife-senior-health-scene',
166
+ description: '养老健康场景服务',
167
+ namespace: 'saas-itest',
168
+ podPattern: 'clife-senior-health-scene-app',
169
+ logPath: '/www/logs/clife-senior-health-scene-app/normal_logs',
170
+ logFile: 'normal.log',
171
+ aliases: ['health-scene', '健康场景']
172
+ },
173
+ 'clife-senior-home': {
174
+ name: 'clife-senior-home',
175
+ description: '养老居家服务',
176
+ namespace: 'saas-itest',
177
+ podPattern: 'clife-senior-home-app',
178
+ logPath: '/www/logs/clife-senior-home-app/normal_logs',
179
+ logFile: 'normal.log',
180
+ aliases: ['home', '居家']
181
+ },
182
+ 'clife-senior-logger': {
183
+ name: 'clife-senior-logger',
184
+ description: '养老日志服务',
185
+ namespace: 'saas-itest',
186
+ podPattern: 'clife-senior-logger-app',
187
+ logPath: '/www/logs/clife-senior-logger-app/normal_logs',
188
+ logFile: 'normal.log',
189
+ aliases: ['logger', '日志']
190
+ },
191
+ 'clife-senior-mall': {
192
+ name: 'clife-senior-mall',
193
+ description: '养老商城服务',
194
+ namespace: 'saas-itest',
195
+ podPattern: 'clife-senior-mall-app',
196
+ logPath: '/www/logs/clife-senior-mall-app/normal_logs',
197
+ logFile: 'normal.log',
198
+ aliases: ['mall', '商城']
199
+ },
200
+ 'clife-senior-meal-asst-app': {
201
+ name: 'clife-senior-meal-asst-app',
202
+ description: '养老助餐服务',
203
+ namespace: 'saas-itest',
204
+ podPattern: 'clife-senior-meal-asst-app',
205
+ logPath: '/www/logs/clife-senior-meal-asst-app/normal_logs',
206
+ logFile: 'normal.log',
207
+ aliases: ['meal-asst', 'meal', '助餐']
208
+ },
209
+ 'clife-senior-message': {
210
+ name: 'clife-senior-message',
211
+ description: '养老消息服务',
212
+ namespace: 'saas-itest',
213
+ podPattern: 'clife-senior-message-app',
214
+ logPath: '/www/logs/clife-senior-message-app/normal_logs',
215
+ logFile: 'normal.log',
216
+ aliases: ['message', '消息']
217
+ },
218
+ 'clife-senior-open': {
219
+ name: 'clife-senior-open',
220
+ description: '养老开放平台服务',
221
+ namespace: 'saas-itest',
222
+ podPattern: 'clife-senior-open-app',
223
+ logPath: '/www/logs/clife-senior-open-app/normal_logs',
224
+ logFile: 'normal.log',
225
+ aliases: ['open', '开放平台']
226
+ },
227
+ 'clife-senior-optimal-aging': {
228
+ name: 'clife-senior-optimal-aging',
229
+ description: '养老优化服务',
230
+ namespace: 'saas-itest',
231
+ podPattern: 'clife-senior-optimal-aging-app',
232
+ logPath: '/www/logs/clife-senior-optimal-aging-app/normal_logs',
233
+ logFile: 'normal.log',
234
+ aliases: ['optimal-aging', '优化']
235
+ },
236
+ 'clife-senior-org-manage': {
237
+ name: 'clife-senior-org-manage',
238
+ description: '养老机构管理服务',
239
+ namespace: 'saas-itest',
240
+ podPattern: 'clife-senior-org-manage-app',
241
+ logPath: '/www/logs/clife-senior-org-manage-app/normal_logs',
242
+ logFile: 'normal.log',
243
+ aliases: ['org-manage', 'org', '机构管理', '机构']
244
+ },
245
+ 'clife-senior-public': {
246
+ name: 'clife-senior-public',
247
+ description: '养老公共服务',
248
+ namespace: 'saas-itest',
249
+ podPattern: 'clife-senior-public-app',
250
+ logPath: '/www/logs/clife-senior-public-app/normal_logs',
251
+ logFile: 'normal.log',
252
+ aliases: ['public', '公共服务']
253
+ },
254
+ 'clife-senior-scene': {
255
+ name: 'clife-senior-scene',
256
+ description: '养老场景服务',
257
+ namespace: 'saas-itest',
258
+ podPattern: 'clife-senior-scene-app',
259
+ logPath: '/www/logs/clife-senior-scene-app/normal_logs',
260
+ logFile: 'normal.log',
261
+ aliases: ['scene', '场景']
262
+ },
263
+ 'clife-senior-state-engine': {
264
+ name: 'clife-senior-state-engine',
265
+ description: '养老状态引擎服务',
266
+ namespace: 'saas-itest',
267
+ podPattern: 'clife-senior-state-engine-app',
268
+ logPath: '/www/logs/clife-senior-state-engine-app/normal_logs',
269
+ logFile: 'normal.log',
270
+ aliases: ['state-engine', '状态引擎']
271
+ },
272
+ 'clife-senior-statistic': {
273
+ name: 'clife-senior-statistic',
274
+ description: '养老统计服务',
275
+ namespace: 'saas-itest',
276
+ podPattern: 'clife-senior-statistic-app',
277
+ logPath: '/www/logs/clife-senior-statistic-app/normal_logs',
278
+ logFile: 'normal.log',
279
+ aliases: ['statistic', '统计']
280
+ },
281
+ 'clife-senior-subsidy': {
282
+ name: 'clife-senior-subsidy',
283
+ description: '养老补贴服务',
284
+ namespace: 'saas-itest',
285
+ podPattern: 'clife-senior-subsidy-app',
286
+ logPath: '/www/logs/clife-senior-subsidy-app/normal_logs',
287
+ logFile: 'normal.log',
288
+ aliases: ['subsidy', '补贴']
289
+ },
290
+ 'clife-senior-third-request': {
291
+ name: 'clife-senior-third-request',
292
+ description: '养老第三方请求服务',
293
+ namespace: 'saas-itest',
294
+ podPattern: 'clife-senior-third-request-app',
295
+ logPath: '/www/logs/clife-senior-third-request-app/normal_logs',
296
+ logFile: 'normal.log',
297
+ aliases: ['third-request', '第三方请求']
298
+ },
299
+ 'clife-senior-third-service': {
300
+ name: 'clife-senior-third-service',
301
+ description: '养老第三方服务',
302
+ namespace: 'saas-itest',
303
+ podPattern: 'clife-senior-third-service-app',
304
+ logPath: '/www/logs/clife-senior-third-service-app/normal_logs',
305
+ logFile: 'normal.log',
306
+ aliases: ['third-service', '第三方服务']
307
+ },
308
+ 'clife-senior-work-order-center': {
309
+ name: 'clife-senior-work-order-center',
310
+ description: '养老工单中心服务',
311
+ namespace: 'saas-itest',
312
+ podPattern: 'clife-senior-work-order-center-app',
313
+ logPath: '/www/logs/clife-senior-work-order-center-app/normal_logs',
314
+ logFile: 'normal.log',
315
+ aliases: ['work-order-center', 'work-order', '工单中心', '工单']
316
+ }
317
+ };
318
+
319
+ // 根据别名查找服务
320
+ // @param {string} nameOrAlias - 服务名称或别名
321
+ // @param {string} namespace - 可选,指定 namespace(覆盖服务配置中的默认值)
322
+ export function findService(nameOrAlias, namespace = null) {
323
+ const lower = nameOrAlias.toLowerCase();
324
+ let service = null;
325
+
326
+ // 精确匹配
327
+ if (SERVICES[lower]) {
328
+ service = SERVICES[lower];
329
+ }
330
+
331
+ // 别名匹配
332
+ if (!service) {
333
+ for (const [key, svc] of Object.entries(SERVICES)) {
334
+ if (svc.aliases.some(alias => alias.toLowerCase() === lower)) {
335
+ service = svc;
336
+ break;
337
+ }
338
+ // 部分匹配
339
+ if (key.includes(lower) || svc.name.includes(lower)) {
340
+ service = svc;
341
+ break;
342
+ }
343
+ }
344
+ }
345
+
346
+ // 如果找到服务且指定了 namespace,则覆盖默认值
347
+ if (service && namespace) {
348
+ return {
349
+ ...service,
350
+ namespace: namespace
351
+ };
352
+ }
353
+
354
+ return service;
355
+ }
356
+
357
+ // 获取所有服务列表
358
+ export function getAllServices() {
359
+ return Object.values(SERVICES).map(s => ({
360
+ name: s.name,
361
+ description: s.description,
362
+ aliases: s.aliases
363
+ }));
364
+ }
365
+
366
+ // 默认配置
367
+ export const DEFAULTS = {
368
+ // 默认查询行数
369
+ lines: 100,
370
+ // 命令超时(毫秒)
371
+ timeout: 30000,
372
+ // SSH 连接超时
373
+ connectTimeout: 10000
374
+ };
375
+
376
+
377
+
378
+ // 默认 namespace 配置
379
+ export const DEFAULT_NAMESPACE = 'saas-itest';
380
+
381
+ // 支持的 namespace 列表
382
+ export const NAMESPACES = {
383
+ 'saas-itest': { description: 'SAAS测试环境', default: true },
384
+ 'saas-prod': { description: 'SAAS生产环境' },
385
+ 'whood-itest': { description: 'WHOOD测试环境' },
386
+ 'whood-prod': { description: 'WHOOD生产环境' }
387
+ };
388
+
389
+ // 工作目录到 namespace 的映射规则
390
+ // 根据本地项目目录自动推断应该查询哪个 namespace
391
+ export const WORKSPACE_MAPPINGS = [
392
+ {
393
+ // D:\shulian\whood\* 目录下的项目 → whood-itest
394
+ pathPattern: /[/\\]shulian[/\\]whood[/\\]/i,
395
+ namespace: 'whood-itest',
396
+ description: 'WHOOD项目目录'
397
+ },
398
+ {
399
+ // D:\shulian\saas\* 目录下的项目 → saas-itest
400
+ pathPattern: /[/\\]shulian[/\\]saas[/\\]/i,
401
+ namespace: 'saas-itest',
402
+ description: 'SAAS项目目录'
403
+ }
404
+ ];
405
+
406
+ /**
407
+ * 根据工作目录路径自动检测 namespace 和服务名
408
+ * @param {string} workspacePath - 当前工作目录路径,如 D:\shulian\whood\clife-senior-mall
409
+ * @returns {Object} 检测结果 { namespace, service, serviceName, confidence }
410
+ */
411
+ export function detectContextFromPath(workspacePath) {
412
+ if (!workspacePath) {
413
+ return {
414
+ success: false,
415
+ error: '未提供工作目录路径',
416
+ namespace: DEFAULT_NAMESPACE,
417
+ service: null,
418
+ serviceName: null
419
+ };
420
+ }
421
+
422
+ // 标准化路径分隔符
423
+ const normalizedPath = workspacePath.replace(/\\/g, '/');
424
+
425
+ // 1. 检测 namespace
426
+ let detectedNamespace = DEFAULT_NAMESPACE;
427
+ let namespaceSource = 'default';
428
+
429
+ for (const mapping of WORKSPACE_MAPPINGS) {
430
+ if (mapping.pathPattern.test(workspacePath)) {
431
+ detectedNamespace = mapping.namespace;
432
+ namespaceSource = mapping.description;
433
+ break;
434
+ }
435
+ }
436
+
437
+ // 2. 从路径中提取服务名
438
+ // 尝试匹配 clife-senior-xxx 格式的目录名
439
+ const serviceMatch = normalizedPath.match(/clife-senior-([a-zA-Z0-9-]+)/i);
440
+ let detectedServiceName = null;
441
+ let detectedService = null;
442
+
443
+ if (serviceMatch) {
444
+ // 尝试查找完整的服务名
445
+ const fullServiceName = `clife-senior-${serviceMatch[1]}`;
446
+ detectedService = findServiceByName(fullServiceName);
447
+
448
+ if (detectedService) {
449
+ detectedServiceName = detectedService.name;
450
+ } else {
451
+ // 服务名可能是别名
452
+ detectedServiceName = serviceMatch[1];
453
+ }
454
+ }
455
+
456
+ return {
457
+ success: true,
458
+ namespace: detectedNamespace,
459
+ namespaceSource: namespaceSource,
460
+ service: detectedService,
461
+ serviceName: detectedServiceName,
462
+ originalPath: workspacePath
463
+ };
464
+ }
465
+
466
+ /**
467
+ * 根据服务名精确查找服务配置(不做别名匹配)
468
+ * @param {string} serviceName - 服务名称
469
+ * @returns {Object|null} 服务配置
470
+ */
471
+ function findServiceByName(serviceName) {
472
+ const lower = serviceName.toLowerCase();
473
+ return SERVICES[lower] || null;
474
+ }