mcp-log-query-server 3.6.1 → 3.7.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
@@ -586,10 +586,26 @@ export const LOKI_ENVIRONMENTS = {
586
586
  orgId: parseInt(process.env.MCP_GRAFANA_ORG_ID || '1'),
587
587
  username: process.env.MCP_GRAFANA_USER || 'loki',
588
588
  password: process.env.MCP_GRAFANA_PASSWORD || 'nihao123!!',
589
- defaultProject: 'senior',
589
+ defaultProject: 'senior', // 用于 {project="senior"} label 过滤
590
+ pathProject: 'senior', // 用于 filename 路径中的 project 段
590
591
  hasProjectLabel: true // CMS 有 project 标签,可用 {project="senior"} 查询
591
592
  },
592
593
 
594
+ // 预发布环境(华为云)— 共享 CMS 的 Grafana / Loki,仅 project 标签为 pre-senior
595
+ // 注意:filename 路径里的 project 段仍然是 'senior'(不是 'pre-senior'),所以 pathProject 单独配置
596
+ 'pre': {
597
+ description: '预发布环境(华为云,与 CMS 共用 Grafana)',
598
+ grafanaUrl: process.env.MCP_GRAFANA_URL || 'http://10.6.14.2:3000',
599
+ datasourceUid: process.env.MCP_GRAFANA_LOKI_UID || 'af2718a2-9c32-4364-a495-3bb29035199c',
600
+ datasourceId: parseInt(process.env.MCP_GRAFANA_DATASOURCE_ID || '35'),
601
+ orgId: parseInt(process.env.MCP_GRAFANA_ORG_ID || '1'),
602
+ username: process.env.MCP_GRAFANA_USER || 'loki',
603
+ password: process.env.MCP_GRAFANA_PASSWORD || 'nihao123!!',
604
+ defaultProject: 'pre-senior', // 用于 {project="pre-senior"} label 过滤
605
+ pathProject: 'senior', // filename 路径里仍是 senior(注意:与 label 不同)
606
+ hasProjectLabel: true
607
+ },
608
+
593
609
  // ---- 私有化环境(均无 project 标签,通过 filename 正则匹配) ----
594
610
 
595
611
  // 城阳私有化
@@ -669,6 +685,14 @@ export const LOKI_ENV_ALIASES = {
669
685
  '生产': 'cms',
670
686
  '生产环境': 'cms',
671
687
  'cms': 'cms',
688
+ // 预发布
689
+ 'pre': 'pre',
690
+ 'preprod': 'pre',
691
+ 'pre-prod': 'pre',
692
+ 'staging': 'pre',
693
+ '预发': 'pre',
694
+ '预发布': 'pre',
695
+ '预发布环境': 'pre',
672
696
  // 城阳
673
697
  '城阳': 'chengyang',
674
698
  'chengyang': 'chengyang',
package/index.js CHANGED
@@ -84,7 +84,7 @@ process.on('uncaughtException', (err) => log(`[uncaughtException] ${err && err.s
84
84
  const server = new Server(
85
85
  {
86
86
  name: 'mcp-log-query',
87
- version: '3.6.1',
87
+ version: '3.7.0',
88
88
  },
89
89
  {
90
90
  capabilities: {
@@ -118,7 +118,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
118
118
  },
119
119
  env: {
120
120
  type: 'string',
121
- description: '环境标识,不指定则查询测试环境(走 SSH)。可选值:cms/prod/生产(CMS生产环境)、城阳/cy/chengyang、临颖/ly/linying、漯河/lh/luohe、德阳/dy/deyang、旌阳/jy/jingyang(私有化环境)'
121
+ description: '环境标识,不指定则查询测试环境(走 SSH)。可选值:cms/prod/生产(CMS生产环境)、pre/预发/预发布(预发布环境,与 CMS 共用 Grafana)、城阳/cy/chengyang、临颖/ly/linying、漯河/lh/luohe、德阳/dy/deyang、旌阳/jy/jingyang(私有化环境)'
122
122
  },
123
123
  from: {
124
124
  type: 'string',
@@ -162,7 +162,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
162
162
  },
163
163
  env: {
164
164
  type: 'string',
165
- description: '环境标识,不指定则查询测试环境(走 SSH)。可选值:cms/prod/生产(CMS生产环境)、城阳/cy/chengyang、临颖/ly/linying、漯河/lh/luohe、德阳/dy/deyang、旌阳/jy/jingyang(私有化环境)'
165
+ description: '环境标识,不指定则查询测试环境(走 SSH)。可选值:cms/prod/生产(CMS生产环境)、pre/预发/预发布(预发布环境,与 CMS 共用 Grafana)、城阳/cy/chengyang、临颖/ly/linying、漯河/lh/luohe、德阳/dy/deyang、旌阳/jy/jingyang(私有化环境)'
166
166
  },
167
167
  from: {
168
168
  type: 'string',
@@ -303,7 +303,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
303
303
  },
304
304
  env: {
305
305
  type: 'string',
306
- description: '环境标识,不指定则查询测试环境(走 SSH)。可选值:cms/prod/生产(CMS生产环境)、城阳/cy/chengyang、临颖/ly/linying、漯河/lh/luohe、德阳/dy/deyang、旌阳/jy/jingyang(私有化环境)'
306
+ description: '环境标识,不指定则查询测试环境(走 SSH)。可选值:cms/prod/生产(CMS生产环境)、pre/预发/预发布(预发布环境,与 CMS 共用 Grafana)、城阳/cy/chengyang、临颖/ly/linying、漯河/lh/luohe、德阳/dy/deyang、旌阳/jy/jingyang(私有化环境)'
307
307
  },
308
308
  from: {
309
309
  type: 'string',
@@ -349,7 +349,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
349
349
  properties: {
350
350
  env: {
351
351
  type: 'string',
352
- description: '环境标识。可选值:cms/prod/生产(CMS生产环境)、城阳/cy/chengyang、临颖/ly/linying、漯河/lh/luohe、德阳/dy/deyang、旌阳/jy/jingyang(私有化环境)',
352
+ description: '环境标识。可选值:cms/prod/生产(CMS生产环境)、pre/预发/预发布(预发布环境,与 CMS 共用 Grafana)、城阳/cy/chengyang、临颖/ly/linying、漯河/lh/luohe、德阳/dy/deyang、旌阳/jy/jingyang(私有化环境)',
353
353
  default: 'cms'
354
354
  },
355
355
  project: {
@@ -900,7 +900,7 @@ async function main() {
900
900
  const transport = new StdioServerTransport();
901
901
  await server.connect(transport);
902
902
  const logPath = getLogFilePath();
903
- log(`[MCP] Log Query Server v3.6.1 已启动 (仅文件日志,避免 stderr backpressure 阻塞 event loop)`);
903
+ log(`[MCP] Log Query Server v3.7.0 已启动 (仅文件日志,避免 stderr backpressure 阻塞 event loop)`);
904
904
  if (logPath) log(`[MCP] 本地日志文件: ${logPath}`);
905
905
  }
906
906
 
package/loki-client.js CHANGED
@@ -362,21 +362,29 @@ export function groupLogsByService(lokiResult) {
362
362
  /**
363
363
  * 构建按服务查询的 LogQL 表达式
364
364
  * 根据环境是否有 project 标签,自动选择不同的 filename 路径格式:
365
- * - 有 project 标签(CMS): /data/services/logs/senior/clife-senior-health-app/normal_logs/normal.log
365
+ * - 有 project 标签(CMS / 预发布): /data/services/logs/senior/clife-senior-health-app/normal_logs/normal.log
366
366
  * - 无 project 标签(私有化): /data/services/logs/clife-senior-health-app/normal_logs/normal.log
367
367
  *
368
- * @param {string} project - 项目名,如 'senior'
368
+ * 注意 path label 的差异:
369
+ * - 预发布 label 是 'pre-senior'(用于 LogQL 标签匹配,不在这里)
370
+ * - 预发布 path 仍然是 'senior'(写在 filename 路径里)
371
+ * 通过环境配置的 pathProject 字段单独控制路径段,避免与 label 混用
372
+ *
373
+ * @param {string} project - 项目 label,如 'senior' / 'pre-senior'(仅当环境无 pathProject 字段时回退使用)
369
374
  * @param {string} servicePodPattern - 服务目录名,如 'clife-senior-health-app'
370
375
  * @param {string} keyword - 搜索关键词(可选)
371
- * @param {string} envName - 环境名称,如 'cms'、'chengyang'
376
+ * @param {string} envName - 环境名称,如 'cms'、'pre'、'chengyang'
372
377
  */
373
378
  export function buildServiceLogQL(project, servicePodPattern, keyword = '', envName = '') {
374
379
  const env = envName ? LOKI_ENVIRONMENTS[envName] : null;
375
380
  const hasProject = env ? env.hasProjectLabel !== false : true;
381
+ // 路径段优先使用 env.pathProject(预发布需要 label='pre-senior' 但 path='senior'),回退到 project
382
+ const pathSegment = (env && env.pathProject) || project;
376
383
 
377
- // CMS: /data/services/logs/senior/xxx-app/... 私有化: /data/services/logs/xxx-app/...
384
+ // project 标签的环境: /data/services/logs/{pathSegment}/xxx-app/...
385
+ // 无 project 标签的环境: /data/services/logs/xxx-app/...
378
386
  const filename = hasProject
379
- ? `/data/services/logs/${project}/${servicePodPattern}/normal_logs/normal.log`
387
+ ? `/data/services/logs/${pathSegment}/${servicePodPattern}/normal_logs/normal.log`
380
388
  : `/data/services/logs/${servicePodPattern}/normal_logs/normal.log`;
381
389
 
382
390
  let expr = `{filename="${filename}"}`;
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "mcp-log-query-server",
3
- "version": "3.6.1",
3
+ "version": "3.7.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",
7
7
  "bin": {
8
- "mcp-log-query": "./index.js"
8
+ "mcp-log-query": "index.js"
9
9
  },
10
10
  "files": [
11
11
  "index.js",
@@ -37,7 +37,7 @@
37
37
  "license": "MIT",
38
38
  "repository": {
39
39
  "type": "git",
40
- "url": "https://github.com/huawang1258/mcp-services.git"
40
+ "url": "git+https://github.com/huawang1258/mcp-services.git"
41
41
  },
42
42
  "homepage": "https://github.com/huawang1258/mcp-services#readme"
43
43
  }