@junjun-org/bd-ke-mcp 1.0.0 → 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/index.js +404 -238
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -78,7 +78,7 @@ function loadConfig() {
78
78
  const fileContent = fs.readFileSync(configFile, "utf8");
79
79
  const fileConfig = JSON.parse(fileContent);
80
80
  Object.assign(config, fileConfig);
81
- logger.info("已加载配置文件", { path: configFile });
81
+ logger.debug("已加载配置文件", { path: configFile });
82
82
  } catch (error) {
83
83
  logger.error("配置文件加载失败", { error: error.message });
84
84
  }
@@ -143,16 +143,23 @@ async function fetchWithTimeout(url, options = {}, timeoutMs = FETCH_TIMEOUT) {
143
143
 
144
144
  /**
145
145
  * KE API 请求
146
+ * @param {string} method - HTTP 方法
147
+ * @param {string} urlPath - API 路径
148
+ * @param {Object} options - 请求选项
149
+ * @param {string} options.domain - KE 平台域名,未指定时从配置文件获取
150
+ * @param {string} options.access_token - 访问令牌,未指定时从配置文件获取
151
+ * @param {Object} options.body - 请求体
152
+ * @param {Object} options.headers - 额外的请求头
146
153
  */
147
154
  async function keRequest(method, urlPath, options = {}) {
148
- const domain = getConfig("domain");
149
- const accessToken = getConfig("access_token");
155
+ const domain = options.domain || getConfig("domain");
156
+ const accessToken = options.access_token || getConfig("access_token");
150
157
 
151
158
  if (!domain) {
152
- throw new Error("配置项 domain 未设置");
159
+ throw new Error("参数 domain 未指定且配置文件中未设置");
153
160
  }
154
161
  if (!accessToken) {
155
- throw new Error("配置项 access_token 未设置");
162
+ throw new Error("参数 access_token 未指定且配置文件中未设置");
156
163
  }
157
164
 
158
165
  const url = `${domain.replace(/\/+$/, "")}/${urlPath.replace(/^\/+/, "")}`;
@@ -187,26 +194,135 @@ async function keRequest(method, urlPath, options = {}) {
187
194
 
188
195
  // ==================== 工具实现 ====================
189
196
 
197
+ /**
198
+ · * ke_config_reset - 重置/更新 KE MCP 配置参数
199
+ * 将配置写入当前项目空间下的 .mcp/bd-ke-mcp.json 文件
200
+ * @param {Object} config - 配置选项
201
+ * @param {string} config.domain - KE 平台域名(用户输入)
202
+ * @param {string} config.access_token - 访问令牌(用户输入)
203
+ * @param {string} config.tenant - 租户名称(从 ke_tenants_list 获取后选择)
204
+ * @param {string} config.project - 项目名称(从 ke_projects_list 获取后选择)
205
+ * @param {string} config.application - 应用名称(从 ke_app_list 获取后选择)
206
+ * @param {string} config.env - 环境名称(从 ke_env_list 获取后选择)
207
+ */
208
+ async function keConfigReset(config) {
209
+ const projectRoot = getProjectRoot();
210
+
211
+ if (!projectRoot) {
212
+ throw new Error("PROJECT_ROOT 环境变量未设置,无法确定项目路径");
213
+ }
214
+
215
+ const mcpDir = path.join(projectRoot, ".mcp");
216
+ const configFile = path.join(mcpDir, CONFIG_FILE_NAME);
217
+
218
+ // 确保 .mcp 目录存在
219
+ if (!fs.existsSync(mcpDir)) {
220
+ fs.mkdirSync(mcpDir, { recursive: true });
221
+ logger.info("已创建 .mcp 目录", { path: mcpDir });
222
+ }
223
+
224
+ // 读取现有配置(如果存在)
225
+ let existingConfig = {};
226
+ if (fs.existsSync(configFile)) {
227
+ try {
228
+ const fileContent = fs.readFileSync(configFile, "utf8");
229
+ existingConfig = JSON.parse(fileContent);
230
+ logger.info("已读取现有配置文件", { path: configFile });
231
+ } catch (error) {
232
+ logger.warn("读取现有配置文件失败,将创建新配置", { error: error.message });
233
+ }
234
+ }
235
+
236
+ // 合并配置(新配置覆盖旧配置)
237
+ const newConfig = { ...existingConfig };
238
+
239
+ // 只更新提供的非空配置项
240
+ if (config.domain !== undefined && config.domain !== "") {
241
+ newConfig.domain = config.domain;
242
+ }
243
+ if (config.access_token !== undefined && config.access_token !== "") {
244
+ newConfig.access_token = config.access_token;
245
+ }
246
+ if (config.tenant !== undefined && config.tenant !== "") {
247
+ newConfig.tenant = config.tenant;
248
+ }
249
+ if (config.project !== undefined && config.project !== "") {
250
+ newConfig.project = config.project;
251
+ }
252
+ if (config.application !== undefined && config.application !== "") {
253
+ newConfig.application = config.application;
254
+ }
255
+ if (config.env !== undefined && config.env !== "") {
256
+ newConfig.env = config.env;
257
+ }
258
+
259
+ // 写入配置文件
260
+ try {
261
+ fs.writeFileSync(configFile, JSON.stringify(newConfig, null, 2) + "\n", "utf8");
262
+ logger.info("配置已写入", { path: configFile });
263
+ } catch (error) {
264
+ throw new Error(`写入配置文件失败: ${error.message}`);
265
+ }
266
+
267
+ // 重新加载全局配置
268
+ reloadConfig();
269
+
270
+ // 构建返回消息
271
+ let result = `KE 配置已成功保存\n`;
272
+ result += `配置文件路径: ${configFile}\n\n`;
273
+ result += `当前配置:\n`;
274
+ result += ` domain: ${newConfig.domain || "(未设置)"}\n`;
275
+ result += ` access_token: ${newConfig.access_token ? "******(已设置)" : "(未设置)"}\n`;
276
+ result += ` tenant: ${newConfig.tenant || "(未设置)"}\n`;
277
+ result += ` project: ${newConfig.project || "(未设置)"}\n`;
278
+ result += ` application: ${newConfig.application || "(未设置)"}\n`;
279
+ result += ` env: ${newConfig.env || "(未设置)"}\n`;
280
+
281
+ return result;
282
+ }
283
+
190
284
  /**
191
285
  * ke_app_restart - 重启 KE 应用(通过删除 Pod)
286
+ * @param {Object} options - 配置选项
287
+ * @param {string} options.domain - KE 平台域名,未指定时从配置文件获取
288
+ * @param {string} options.access_token - 访问令牌,未指定时从配置文件获取
289
+ * @param {string} options.tenant - 租户名称,未指定时从配置文件获取
290
+ * @param {string} options.project - 项目名称,未指定时从配置文件获取
291
+ * @param {string} options.application - 应用名称,未指定时从配置文件获取
292
+ * @param {string} options.env - 环境名称,未指定时从配置文件获取
192
293
  */
193
- async function keAppRestart() {
294
+ async function keAppRestart(options = {}) {
194
295
  reloadConfig();
195
296
 
196
- const application = getConfig("application");
197
- const env = getConfig("env");
297
+ // 配置项优先从参数获取,未指定则从配置文件获取
298
+ const domain = options.domain || getConfig("domain");
299
+ const accessToken = options.access_token || getConfig("access_token");
300
+ const tenant = options.tenant || getConfig("tenant");
301
+ const project = options.project || getConfig("project");
302
+ const application = options.application || getConfig("application");
303
+ const env = options.env || getConfig("env");
198
304
 
199
- if (!application || !env) {
200
- throw new Error("配置项 application 或 env 未设置");
305
+ if (!tenant) {
306
+ throw new Error("参数 tenant 未指定且配置文件中未设置");
307
+ }
308
+ if (!project) {
309
+ throw new Error("参数 project 未指定且配置文件中未设置");
310
+ }
311
+ if (!application) {
312
+ throw new Error("参数 application 未指定且配置文件中未设置");
313
+ }
314
+ if (!env) {
315
+ throw new Error("参数 env 未指定且配置文件中未设置");
201
316
  }
202
317
 
203
- const namespace = getTenantNamespace();
318
+ const namespace = `${tenant}-${project}`;
319
+ const requestOptions = { domain, access_token: accessToken };
204
320
 
205
321
  logger.info("重启应用", { application, env, namespace });
206
322
 
207
323
  // 1. 获取应用状态
208
324
  const statusUrl = `amp/v4/namespace/${namespace}/env/${env}/applications/${application}/appstatus/view?canary=false`;
209
- const statusData = await keRequest("GET", statusUrl);
325
+ const statusData = await keRequest("GET", statusUrl, requestOptions);
210
326
 
211
327
  // 2. 提取 Pod 名称
212
328
  const podNames = [];
@@ -233,7 +349,7 @@ async function keAppRestart() {
233
349
  for (const podName of podNames) {
234
350
  try {
235
351
  const deleteUrl = `amp/v4/namespace/${namespace}/env/${env}/applications/${application}/pods/${podName}/delete?cluster=${env}`;
236
- await keRequest("DELETE", deleteUrl);
352
+ await keRequest("DELETE", deleteUrl, requestOptions);
237
353
  deletedPods.push(podName);
238
354
  logger.info(`已删除 Pod: ${podName}`);
239
355
  } catch (error) {
@@ -268,17 +384,35 @@ async function keAppRestart() {
268
384
 
269
385
  /**
270
386
  * ke_pipeline_list - 获取流水线列表
387
+ * @param {Object} options - 配置选项
388
+ * @param {string} options.domain - KE 平台域名,未指定时从配置文件获取
389
+ * @param {string} options.access_token - 访问令牌,未指定时从配置文件获取
390
+ * @param {string} options.tenant - 租户名称,未指定时从配置文件获取
391
+ * @param {string} options.project - 项目名称,未指定时从配置文件获取
392
+ * @param {string} options.application - 应用名称(可选),未指定时从配置文件获取
393
+ * @param {number} options.page - 页码,默认 1
394
+ * @param {number} options.pageSize - 每页数量,默认 20
271
395
  */
272
- async function kePipelineList(page = 1, pageSize = 20) {
396
+ async function kePipelineList(options = {}) {
273
397
  reloadConfig();
274
398
 
275
- const domain = getConfig("domain");
276
- const tenant = getConfig("tenant");
277
- const project = getConfig("project");
278
- const application = getConfig("application");
399
+ // 配置项优先从参数获取,未指定则从配置文件获取
400
+ const domain = options.domain || getConfig("domain");
401
+ const accessToken = options.access_token || getConfig("access_token");
402
+ const tenant = options.tenant || getConfig("tenant");
403
+ const project = options.project || getConfig("project");
404
+ const application = options.application || getConfig("application");
405
+ const page = options.page || 1;
406
+ const pageSize = options.pageSize || 20;
279
407
 
280
- if (!tenant || !project) {
281
- throw new Error("配置项 tenant 或 project 未设置");
408
+ if (!domain) {
409
+ throw new Error("参数 domain 未指定且配置文件中未设置");
410
+ }
411
+ if (!tenant) {
412
+ throw new Error("参数 tenant 未指定且配置文件中未设置");
413
+ }
414
+ if (!project) {
415
+ throw new Error("参数 project 未指定且配置文件中未设置");
282
416
  }
283
417
 
284
418
  // 构建 label 参数
@@ -298,7 +432,7 @@ async function kePipelineList(page = 1, pageSize = 20) {
298
432
 
299
433
  logger.info("获取流水线列表", { group, application });
300
434
 
301
- const data = await keRequest("GET", url);
435
+ const data = await keRequest("GET", url, { domain, access_token: accessToken });
302
436
  const pipelinesData = data.rtnData?.data || [];
303
437
  const envMapping = data.rtnData?.env || {};
304
438
  const totalCount = data.rtnData?.count || 0;
@@ -334,17 +468,21 @@ async function kePipelineList(page = 1, pageSize = 20) {
334
468
 
335
469
  /**
336
470
  * ke_pipeline_info - 获取流水线信息
471
+ * @param {Object} options - 配置选项
472
+ * @param {string} options.access_token - 访问令牌,未指定时从配置文件获取
473
+ * @param {string} options.pipelineUrl - 流水线地址(必填)
337
474
  */
338
- async function kePipelineInfo(pipelineUrl) {
475
+ async function kePipelineInfo(options = {}) {
339
476
  reloadConfig();
340
477
 
478
+ const accessToken = options.access_token || getConfig("access_token");
479
+ const pipelineUrl = options.pipelineUrl;
480
+
341
481
  if (!pipelineUrl) {
342
482
  throw new Error("参数 pipelineUrl 不能为空");
343
483
  }
344
-
345
- const accessToken = getConfig("access_token");
346
484
  if (!accessToken) {
347
- throw new Error("配置项 access_token 未设置");
485
+ throw new Error("参数 access_token 未指定且配置文件中未设置");
348
486
  }
349
487
 
350
488
  logger.info("获取流水线信息", { url: pipelineUrl });
@@ -393,17 +531,27 @@ async function kePipelineInfo(pipelineUrl) {
393
531
 
394
532
  /**
395
533
  * ke_pipeline_create - 执行流水线
534
+ * @param {Object} options - 配置选项
535
+ * @param {string} options.access_token - 访问令牌,未指定时从配置文件获取
536
+ * @param {string} options.pipelineUrl - 流水线地址(必填)
537
+ * @param {Object} options.globalArguments - 全局参数字典(必填)
538
+ * @param {number} options.deadline - 超时时间(秒),默认 86400
539
+ * @param {string} options.review - 审核信息,默认空
396
540
  */
397
- async function kePipelineCreate(pipelineUrl, globalArguments, deadline = 86400, review = "") {
541
+ async function kePipelineCreate(options = {}) {
398
542
  reloadConfig();
399
543
 
544
+ const accessToken = options.access_token || getConfig("access_token");
545
+ const pipelineUrl = options.pipelineUrl;
546
+ const globalArguments = options.globalArguments;
547
+ const deadline = options.deadline || 86400;
548
+ const review = options.review || "";
549
+
400
550
  if (!pipelineUrl) {
401
551
  throw new Error("参数 pipelineUrl 不能为空");
402
552
  }
403
-
404
- const accessToken = getConfig("access_token");
405
553
  if (!accessToken) {
406
- throw new Error("配置项 access_token 未设置");
554
+ throw new Error("参数 access_token 未指定且配置文件中未设置");
407
555
  }
408
556
  if (!globalArguments || Object.keys(globalArguments).length === 0) {
409
557
  throw new Error("参数 globalArguments 不能为空");
@@ -454,12 +602,18 @@ async function kePipelineCreate(pipelineUrl, globalArguments, deadline = 86400,
454
602
 
455
603
  /**
456
604
  * ke_tenants_list - 列出所有租户
605
+ * @param {Object} options - 配置选项
606
+ * @param {string} options.domain - KE 平台域名,未指定时从配置文件获取
607
+ * @param {string} options.access_token - 访问令牌,未指定时从配置文件获取
457
608
  */
458
- async function keTenantsList() {
609
+ async function keTenantsList(options = {}) {
459
610
  reloadConfig();
460
611
 
612
+ const domain = options.domain || getConfig("domain");
613
+ const accessToken = options.access_token || getConfig("access_token");
614
+
461
615
  const url = "user-center/v4/tenants/list?page=1&pageSize=100&type=all&single=true";
462
- const data = await keRequest("GET", url);
616
+ const data = await keRequest("GET", url, { domain, access_token: accessToken });
463
617
 
464
618
  const tenantsData = data.rtnData?.data || [];
465
619
 
@@ -480,17 +634,24 @@ async function keTenantsList() {
480
634
 
481
635
  /**
482
636
  * ke_projects_list - 列出所有项目
637
+ * @param {Object} options - 配置选项
638
+ * @param {string} options.domain - KE 平台域名,未指定时从配置文件获取
639
+ * @param {string} options.access_token - 访问令牌,未指定时从配置文件获取
640
+ * @param {string} options.tenant - 租户名称,未指定时从配置文件获取
483
641
  */
484
- async function keProjectsList() {
642
+ async function keProjectsList(options = {}) {
485
643
  reloadConfig();
486
644
 
487
- const tenant = getConfig("tenant");
645
+ const domain = options.domain || getConfig("domain");
646
+ const accessToken = options.access_token || getConfig("access_token");
647
+ const tenant = options.tenant || getConfig("tenant");
648
+
488
649
  if (!tenant) {
489
- throw new Error("配置项 tenant 未设置");
650
+ throw new Error("参数 tenant 未指定且配置文件中未设置");
490
651
  }
491
652
 
492
653
  const url = `user-center/v4/tenants/${tenant}/projects/list`;
493
- const data = await keRequest("GET", url);
654
+ const data = await keRequest("GET", url, { domain, access_token: accessToken });
494
655
 
495
656
  const projectsData = data.rtnData?.data || [];
496
657
 
@@ -513,13 +674,30 @@ async function keProjectsList() {
513
674
 
514
675
  /**
515
676
  * ke_app_list - 列出所有应用
677
+ * @param {Object} options - 配置选项
678
+ * @param {string} options.domain - KE 平台域名,未指定时从配置文件获取
679
+ * @param {string} options.access_token - 访问令牌,未指定时从配置文件获取
680
+ * @param {string} options.tenant - 租户名称,未指定时从配置文件获取
681
+ * @param {string} options.project - 项目名称,未指定时从配置文件获取
516
682
  */
517
- async function keAppList() {
683
+ async function keAppList(options = {}) {
518
684
  reloadConfig();
519
685
 
520
- const namespace = getTenantNamespace();
686
+ const domain = options.domain || getConfig("domain");
687
+ const accessToken = options.access_token || getConfig("access_token");
688
+ const tenant = options.tenant || getConfig("tenant");
689
+ const project = options.project || getConfig("project");
690
+
691
+ if (!tenant) {
692
+ throw new Error("参数 tenant 未指定且配置文件中未设置");
693
+ }
694
+ if (!project) {
695
+ throw new Error("参数 project 未指定且配置文件中未设置");
696
+ }
697
+
698
+ const namespace = `${tenant}-${project}`;
521
699
  const url = `amp/v4/namespace/${namespace}/applications/list?page=1&pageSize=999`;
522
- const data = await keRequest("GET", url);
700
+ const data = await keRequest("GET", url, { domain, access_token: accessToken });
523
701
 
524
702
  const appsData = data.rtnData?.data || [];
525
703
 
@@ -540,17 +718,24 @@ async function keAppList() {
540
718
 
541
719
  /**
542
720
  * ke_env_list - 获取环境列表
721
+ * @param {Object} options - 配置选项
722
+ * @param {string} options.domain - KE 平台域名,未指定时从配置文件获取
723
+ * @param {string} options.access_token - 访问令牌,未指定时从配置文件获取
724
+ * @param {string} options.tenant - 租户名称,未指定时从配置文件获取
543
725
  */
544
- async function keEnvList() {
726
+ async function keEnvList(options = {}) {
545
727
  reloadConfig();
546
728
 
547
- const tenant = getConfig("tenant");
729
+ const domain = options.domain || getConfig("domain");
730
+ const accessToken = options.access_token || getConfig("access_token");
731
+ const tenant = options.tenant || getConfig("tenant");
732
+
548
733
  if (!tenant) {
549
- throw new Error("配置项 tenant 未设置");
734
+ throw new Error("参数 tenant 未指定且配置文件中未设置");
550
735
  }
551
736
 
552
737
  const url = `user-center/v4/tenants/${tenant}/clusters/all/list`;
553
- const data = await keRequest("GET", url);
738
+ const data = await keRequest("GET", url, { domain, access_token: accessToken });
554
739
 
555
740
  const clustersData = data.rtnData?.data || [];
556
741
  const envList = clustersData.map(c => c.name).filter(Boolean);
@@ -570,23 +755,40 @@ async function keEnvList() {
570
755
 
571
756
  /**
572
757
  * ke_pods_list - 获取 Pod 列表
758
+ * @param {Object} options - 配置选项
759
+ * @param {string} options.domain - KE 平台域名,未指定时从配置文件获取
760
+ * @param {string} options.access_token - 访问令牌,未指定时从配置文件获取
761
+ * @param {string} options.tenant - 租户名称,未指定时从配置文件获取
762
+ * @param {string} options.project - 项目名称,未指定时从配置文件获取
763
+ * @param {string} options.appName - 应用名称(必填)
764
+ * @param {string} options.env - 环境名称(必填)
573
765
  */
574
- async function kePodsList(appName) {
766
+ async function kePodsList(options = {}) {
575
767
  reloadConfig();
576
768
 
769
+ const domain = options.domain || getConfig("domain");
770
+ const accessToken = options.access_token || getConfig("access_token");
771
+ const tenant = options.tenant || getConfig("tenant");
772
+ const project = options.project || getConfig("project");
773
+ const appName = options.appName;
774
+ const env = options.env;
775
+
776
+ if (!tenant) {
777
+ throw new Error("参数 tenant 未指定且配置文件中未设置");
778
+ }
779
+ if (!project) {
780
+ throw new Error("参数 project 未指定且配置文件中未设置");
781
+ }
577
782
  if (!appName) {
578
783
  throw new Error("参数 appName 不能为空");
579
784
  }
580
-
581
- const namespace = getTenantNamespace();
582
- const env = getConfig("env");
583
-
584
785
  if (!env) {
585
- throw new Error("配置项 env 未设置");
786
+ throw new Error("参数 env 不能为空");
586
787
  }
587
788
 
789
+ const namespace = `${tenant}-${project}`;
588
790
  const url = `amp/v4/namespace/${namespace}/env/${env}/applications/${appName}/appstatus/view?canary=false`;
589
- const data = await keRequest("GET", url);
791
+ const data = await keRequest("GET", url, { domain, access_token: accessToken });
590
792
 
591
793
  // 提取 Pod 列表
592
794
  const podsList = [];
@@ -634,20 +836,49 @@ async function kePodsList(appName) {
634
836
 
635
837
  /**
636
838
  * ke_pod_log_list - 获取 Pod 日志列表
839
+ * @param {Object} options - 配置选项
840
+ * @param {string} options.domain - KE 平台域名,未指定时从配置文件获取
841
+ * @param {string} options.access_token - 访问令牌,未指定时从配置文件获取
842
+ * @param {string} options.tenant - 租户名称,未指定时从配置文件获取
843
+ * @param {string} options.project - 项目名称,未指定时从配置文件获取(用于构建默认 namespace)
844
+ * @param {string} options.namespace - 命名空间,未指定时从配置文件的 tenant-project 构建
845
+ * @param {string} options.application - 应用名称,未指定时从配置文件获取
846
+ * @param {string} options.env - 环境名称,未指定时从配置文件获取
847
+ * @param {string} options.startTime - 开始时间(纳秒时间戳字符串,必填)
848
+ * @param {string} options.endTime - 结束时间(纳秒时间戳字符串,必填)
849
+ * @param {number} options.size - 返回记录数量(必填)
850
+ * @param {number} options.offset - 偏移量(必填)
851
+ * @param {string} options.sort - 排序方式(必填)
637
852
  */
638
- async function kePodLogList(namespace, service, env, startTime, endTime, size = 100, offset = 0, sort = "desc") {
853
+ async function kePodLogList(options = {}) {
639
854
  reloadConfig();
640
855
 
641
- if (!namespace) throw new Error("参数 namespace 不能为空");
642
- if (!service) throw new Error("参数 service 不能为空");
643
- if (!env) throw new Error("参数 env 不能为空");
644
- if (!startTime) throw new Error("参数 start_time 不能为空");
645
- if (!endTime) throw new Error("参数 end_time 不能为空");
646
-
647
- const tenant = getConfig("tenant");
856
+ const domain = options.domain || getConfig("domain");
857
+ const accessToken = options.access_token || getConfig("access_token");
858
+ const tenant = options.tenant || getConfig("tenant");
859
+ const project = options.project || getConfig("project");
860
+ const service = options.application || getConfig("application");
861
+ const env = options.env || getConfig("env");
862
+ const startTime = options.startTime;
863
+ const endTime = options.endTime;
864
+ const size = options.size;
865
+ const offset = options.offset;
866
+ const sort = options.sort;
867
+
868
+ // namespace 优先从参数获取,否则从 tenant-project 构建
869
+ const namespace = options.namespace || (tenant && project ? `${tenant}-${project}` : null);
870
+
648
871
  if (!tenant) {
649
- throw new Error("配置项 tenant 未设置");
872
+ throw new Error("参数 tenant 未指定且配置文件中未设置");
650
873
  }
874
+ if (!namespace) throw new Error("参数 namespace 未指定且无法从配置文件的 tenant-project 构建");
875
+ if (!service) throw new Error("参数 application 未指定且配置文件中未设置");
876
+ if (!env) throw new Error("参数 env 未指定且配置文件中未设置");
877
+ if (!startTime) throw new Error("参数 startTime 不能为空");
878
+ if (!endTime) throw new Error("参数 endTime 不能为空");
879
+ if (size === undefined || size === null) throw new Error("参数 size 不能为空");
880
+ if (offset === undefined || offset === null) throw new Error("参数 offset 不能为空");
881
+ if (!sort) throw new Error("参数 sort 不能为空");
651
882
 
652
883
  const url = `armilla/v1/group/${tenant}/env/${env}/log/list`;
653
884
 
@@ -679,7 +910,7 @@ async function kePodLogList(namespace, service, env, startTime, endTime, size =
679
910
  log_version: "v3"
680
911
  };
681
912
 
682
- const data = await keRequest("POST", url, { body: requestBody });
913
+ const data = await keRequest("POST", url, { domain, access_token: accessToken, body: requestBody });
683
914
  const records = data.rtnData?.records || [];
684
915
 
685
916
  if (records.length === 0) {
@@ -718,106 +949,6 @@ async function kePodLogList(namespace, service, env, startTime, endTime, size =
718
949
  return result;
719
950
  }
720
951
 
721
- /**
722
- * ke_pod_exec - 在 Pod 容器中执行命令
723
- */
724
- async function kePodExec(tenant, project, podName, cluster, command, container = "", nodeName = "") {
725
- reloadConfig();
726
-
727
- if (!tenant) throw new Error("参数 tenant 不能为空");
728
- if (!project) throw new Error("参数 project 不能为空");
729
- if (!podName) throw new Error("参数 podName 不能为空");
730
- if (!cluster) throw new Error("参数 cluster 不能为空");
731
- if (!command) throw new Error("参数 command 不能为空");
732
-
733
- const namespace = `${tenant}-${project}`;
734
-
735
- // 构建 exec API URL
736
- // 根据 KE 平台的 API 结构,exec 接口可能在 amp/v4 下
737
- const url = `amp/v4/namespace/${namespace}/env/${cluster}/pods/${podName}/exec`;
738
-
739
- logger.info("执行 Pod 命令", { namespace, podName, cluster, command, container, nodeName });
740
-
741
- const requestBody = {
742
- command: command.split(/\s+/), // 将命令字符串拆分为数组
743
- container: container || undefined,
744
- nodeName: nodeName || undefined
745
- };
746
-
747
- // 移除 undefined 字段
748
- Object.keys(requestBody).forEach(key => {
749
- if (requestBody[key] === undefined) {
750
- delete requestBody[key];
751
- }
752
- });
753
-
754
- try {
755
- const data = await keRequest("POST", url, { body: requestBody });
756
-
757
- const execResult = data.rtnData || {};
758
- const stdout = execResult.stdout || "";
759
- const stderr = execResult.stderr || "";
760
- const exitCode = execResult.exitCode !== undefined ? execResult.exitCode : (data.rtnCode === "000000" ? 0 : 1);
761
-
762
- let result = `命令执行完成\n`;
763
- result += `Pod: ${podName}\n`;
764
- result += `命名空间: ${namespace}\n`;
765
- result += `环境: ${cluster}\n`;
766
- result += `命令: ${command}\n`;
767
- result += `退出码: ${exitCode}\n\n`;
768
-
769
- if (stdout) {
770
- result += `标准输出:\n${stdout}\n`;
771
- }
772
-
773
- if (stderr) {
774
- result += `错误输出:\n${stderr}\n`;
775
- }
776
-
777
- if (!stdout && !stderr) {
778
- result += `(无输出)`;
779
- }
780
-
781
- return result;
782
- } catch (error) {
783
- // 如果 POST 失败,尝试 GET 方式(某些平台可能使用 GET)
784
- logger.debug("POST 方式失败,尝试 GET 方式", { error: error.message });
785
-
786
- const getUrl = `${url}?command=${encodeURIComponent(command)}${container ? `&container=${encodeURIComponent(container)}` : ''}${nodeName ? `&nodeName=${encodeURIComponent(nodeName)}` : ''}`;
787
-
788
- try {
789
- const data = await keRequest("GET", getUrl);
790
- const execResult = data.rtnData || {};
791
- const stdout = execResult.stdout || "";
792
- const stderr = execResult.stderr || "";
793
- const exitCode = execResult.exitCode !== undefined ? execResult.exitCode : 0;
794
-
795
- let result = `命令执行完成\n`;
796
- result += `Pod: ${podName}\n`;
797
- result += `命名空间: ${namespace}\n`;
798
- result += `环境: ${cluster}\n`;
799
- result += `命令: ${command}\n`;
800
- result += `退出码: ${exitCode}\n\n`;
801
-
802
- if (stdout) {
803
- result += `标准输出:\n${stdout}\n`;
804
- }
805
-
806
- if (stderr) {
807
- result += `错误输出:\n${stderr}\n`;
808
- }
809
-
810
- if (!stdout && !stderr) {
811
- result += `(无输出)`;
812
- }
813
-
814
- return result;
815
- } catch (getError) {
816
- throw new Error(`执行命令失败: ${error.message}。如果 KE 平台不支持 exec API,请使用 webshell 手动操作。`);
817
- }
818
- }
819
- }
820
-
821
952
  // ==================== MCP 服务器 ====================
822
953
 
823
954
  const server = new McpServer({
@@ -825,16 +956,48 @@ const server = new McpServer({
825
956
  version: VERSION
826
957
  });
827
958
 
959
+ // 注册工具:ke_config_reset
960
+ server.registerTool(
961
+ "ke_config_reset",
962
+ {
963
+ description: "重置/更新 KE MCP 配置参数,配置后其他工具可自动读取这些默认值。",
964
+ inputSchema: {
965
+ domain: z.string().optional().describe("KE 平台域名(如:https://ke.example.com)。【必须】由用户手动输入,这是访问 KE 平台的基础地址,不可自动猜测"),
966
+ access_token: z.string().optional().describe("访问令牌(leo-user-token)。【必须】由用户手动输入,可从 KE 平台的用户设置中获取,不可自动猜测"),
967
+ tenant: z.string().optional().describe("租户名称。可通过 ke_tenants_list 工具获取可用租户列表,如果存在多个租户【必须】展示列表并让用户明确选择,不可自动选择"),
968
+ project: z.string().optional().describe("项目名称。可通过 ke_projects_list 工具获取指定租户下的项目列表,如果存在多个项目【必须】展示列表并让用户明确选择,不可自动选择"),
969
+ application: z.string().optional().describe("应用名称。可通过 ke_app_list 工具获取指定租户和项目下的应用列表,如果存在多个应用【必须】展示列表并让用户明确选择,不可自动选择"),
970
+ env: z.string().optional().describe("环境名称(如:test、prod)。可通过 ke_env_list 工具获取指定租户下的环境列表,如果存在多个环境【必须】展示列表并让用户明确选择,不可自动选择")
971
+ }
972
+ },
973
+ async ({ domain, access_token, tenant, project, application, env }) => {
974
+ try {
975
+ const result = await keConfigReset({ domain, access_token, tenant, project, application, env });
976
+ return { content: [{ type: "text", text: result }] };
977
+ } catch (error) {
978
+ logger.error("ke_config_reset 失败", { error: error.message });
979
+ return { content: [{ type: "text", text: `错误: ${error.message}` }], isError: true };
980
+ }
981
+ }
982
+ );
983
+
828
984
  // 注册工具:ke_app_restart
829
985
  server.registerTool(
830
986
  "ke_app_restart",
831
987
  {
832
- description: "重启 KE 应用(通过删除 Pod 触发自动重建)",
833
- inputSchema: {}
988
+ description: "重启 KE 应用(通过删除 Pod 触发自动重建)。所有配置项如果未指定,则默认从项目目录下的 .mcp/bd-ke-mcp.json 配置文件中获取。",
989
+ inputSchema: {
990
+ domain: z.string().optional().describe("KE 平台域名(如:https://ke.example.com),用于 API 请求。未指定时从 .mcp/bd-ke-mcp.json 配置文件获取"),
991
+ access_token: z.string().optional().describe("访问令牌(leo-user-token),用于 API 认证。未指定时从 .mcp/bd-ke-mcp.json 配置文件获取"),
992
+ tenant: z.string().optional().describe("租户名称,用于构建命名空间。未指定时从 .mcp/bd-ke-mcp.json 配置文件获取"),
993
+ project: z.string().optional().describe("项目名称,用于构建命名空间。未指定时从 .mcp/bd-ke-mcp.json 配置文件获取"),
994
+ application: z.string().optional().describe("要重启的应用名称。未指定时从 .mcp/bd-ke-mcp.json 配置文件获取"),
995
+ env: z.string().optional().describe("环境名称(如:production、development),指定要重启的环境。未指定时从 .mcp/bd-ke-mcp.json 配置文件获取")
996
+ }
834
997
  },
835
- async () => {
998
+ async ({ domain, access_token, tenant, project, application, env }) => {
836
999
  try {
837
- const result = await keAppRestart();
1000
+ const result = await keAppRestart({ domain, access_token, tenant, project, application, env });
838
1001
  return { content: [{ type: "text", text: result }] };
839
1002
  } catch (error) {
840
1003
  logger.error("ke_app_restart 失败", { error: error.message });
@@ -847,15 +1010,20 @@ server.registerTool(
847
1010
  server.registerTool(
848
1011
  "ke_pipeline_list",
849
1012
  {
850
- description: "获取 KE 流水线列表,根据配置文件中的 tenant、project、application 筛选",
1013
+ description: "获取 KE 流水线列表,根据 tenant、project、application 筛选。所有配置项如果未指定,则默认从项目目录下的 .mcp/bd-ke-mcp.json 配置文件中获取。",
851
1014
  inputSchema: {
852
- page: z.number().optional().default(1).describe("页码,默认 1"),
853
- pageSize: z.number().optional().default(20).describe("每页数量,默认 20")
1015
+ domain: z.string().optional().describe("KE 平台域名(如:https://ke.example.com),用于 API 请求和构建流水线访问地址。未指定时从 .mcp/bd-ke-mcp.json 配置文件获取"),
1016
+ access_token: z.string().optional().describe("访问令牌(leo-user-token),用于 API 认证。未指定时从 .mcp/bd-ke-mcp.json 配置文件获取"),
1017
+ tenant: z.string().optional().describe("租户名称,用于筛选流水线。未指定时从 .mcp/bd-ke-mcp.json 配置文件获取"),
1018
+ project: z.string().optional().describe("项目名称,用于筛选流水线。未指定时从 .mcp/bd-ke-mcp.json 配置文件获取"),
1019
+ application: z.string().optional().describe("应用名称,用于进一步筛选特定应用的流水线。未指定时从 .mcp/bd-ke-mcp.json 配置文件获取,可为空表示不按应用筛选"),
1020
+ page: z.number().optional().default(1).describe("分页页码,从 1 开始,默认为 1"),
1021
+ pageSize: z.number().optional().default(20).describe("每页返回的流水线数量,默认为 20")
854
1022
  }
855
1023
  },
856
- async ({ page, pageSize }) => {
1024
+ async ({ domain, access_token, tenant, project, application, page, pageSize }) => {
857
1025
  try {
858
- const result = await kePipelineList(page, pageSize);
1026
+ const result = await kePipelineList({ domain, access_token, tenant, project, application, page, pageSize });
859
1027
  return { content: [{ type: "text", text: result }] };
860
1028
  } catch (error) {
861
1029
  logger.error("ke_pipeline_list 失败", { error: error.message });
@@ -868,14 +1036,15 @@ server.registerTool(
868
1036
  server.registerTool(
869
1037
  "ke_pipeline_info",
870
1038
  {
871
- description: "获取 KE 流水线信息,包括流水线名称和执行参数",
1039
+ description: "获取 KE 流水线信息,包括流水线名称和执行参数。access_token 如果未指定,则默认从项目目录下的 .mcp/bd-ke-mcp.json 配置文件中获取。",
872
1040
  inputSchema: {
873
- pipelineUrl: z.string().describe("流水线地址(如:http://pro.kubeease.cn/pipeline/v1/group/tenant-project/pipelines/app-xxx/view)")
1041
+ access_token: z.string().optional().describe("访问令牌(leo-user-token),用于 API 认证。未指定时从 .mcp/bd-ke-mcp.json 配置文件获取"),
1042
+ pipelineUrl: z.string().describe("流水线地址,完整的 URL 路径(如:https://ke.example.com/pipeline/v1/group/tenant-project/pipelines/app-xxx/view),可从 ke_pipeline_list 获取")
874
1043
  }
875
1044
  },
876
- async ({ pipelineUrl }) => {
1045
+ async ({ access_token, pipelineUrl }) => {
877
1046
  try {
878
- const result = await kePipelineInfo(pipelineUrl);
1047
+ const result = await kePipelineInfo({ access_token, pipelineUrl });
879
1048
  return { content: [{ type: "text", text: result }] };
880
1049
  } catch (error) {
881
1050
  logger.error("ke_pipeline_info 失败", { error: error.message });
@@ -888,17 +1057,18 @@ server.registerTool(
888
1057
  server.registerTool(
889
1058
  "ke_pipeline_create",
890
1059
  {
891
- description: "执行 KE 流水线(创建流水线运行时)",
1060
+ description: "执行 KE 流水线(创建流水线运行时)。access_token 如果未指定,则默认从项目目录下的 .mcp/bd-ke-mcp.json 配置文件中获取。",
892
1061
  inputSchema: {
893
- pipelineUrl: z.string().describe("流水线地址(如:http://pro.kubeease.cn/pipeline/v1/group/tenant-project/pipelines/app-xxx/view)"),
894
- globalArguments: z.record(z.string()).describe("全局参数字典,键为参数名,值为参数值"),
895
- deadline: z.number().optional().default(86400).describe("超时时间(秒),默认 86400"),
896
- review: z.string().optional().default("").describe("审核信息")
1062
+ access_token: z.string().optional().describe("访问令牌(leo-user-token),用于 API 认证。未指定时从 .mcp/bd-ke-mcp.json 配置文件获取"),
1063
+ pipelineUrl: z.string().describe("流水线地址,完整的 URL 路径(如:https://ke.example.com/pipeline/v1/group/tenant-project/pipelines/app-xxx/view),可从 ke_pipeline_list 获取"),
1064
+ globalArguments: z.record(z.string()).describe("全局参数字典,键为参数名,值为参数值。参数列表可通过 ke_pipeline_info 获取"),
1065
+ deadline: z.number().optional().default(86400).describe("流水线执行超时时间(秒),超过此时间流水线将被终止,默认 86400(24小时)"),
1066
+ review: z.string().optional().default("").describe("审核信息,可选的审核备注或说明")
897
1067
  }
898
1068
  },
899
- async ({ pipelineUrl, globalArguments, deadline, review }) => {
1069
+ async ({ access_token, pipelineUrl, globalArguments, deadline, review }) => {
900
1070
  try {
901
- const result = await kePipelineCreate(pipelineUrl, globalArguments, deadline, review);
1071
+ const result = await kePipelineCreate({ access_token, pipelineUrl, globalArguments, deadline, review });
902
1072
  return { content: [{ type: "text", text: result }] };
903
1073
  } catch (error) {
904
1074
  logger.error("ke_pipeline_create 失败", { error: error.message });
@@ -911,12 +1081,15 @@ server.registerTool(
911
1081
  server.registerTool(
912
1082
  "ke_tenants_list",
913
1083
  {
914
- description: "列出所有的租户",
915
- inputSchema: {}
1084
+ description: "列出当前用户有权限访问的所有租户。所有配置项如果未指定,则默认从项目目录下的 .mcp/bd-ke-mcp.json 配置文件中获取。",
1085
+ inputSchema: {
1086
+ domain: z.string().optional().describe("KE 平台域名(如:https://ke.example.com),用于 API 请求。未指定时从 .mcp/bd-ke-mcp.json 配置文件获取"),
1087
+ access_token: z.string().optional().describe("访问令牌(leo-user-token),用于 API 认证。未指定时从 .mcp/bd-ke-mcp.json 配置文件获取")
1088
+ }
916
1089
  },
917
- async () => {
1090
+ async ({ domain, access_token }) => {
918
1091
  try {
919
- const result = await keTenantsList();
1092
+ const result = await keTenantsList({ domain, access_token });
920
1093
  return { content: [{ type: "text", text: result }] };
921
1094
  } catch (error) {
922
1095
  logger.error("ke_tenants_list 失败", { error: error.message });
@@ -929,12 +1102,16 @@ server.registerTool(
929
1102
  server.registerTool(
930
1103
  "ke_projects_list",
931
1104
  {
932
- description: "列出所有的项目",
933
- inputSchema: {}
1105
+ description: "列出指定租户下的所有项目。所有配置项如果未指定,则默认从项目目录下的 .mcp/bd-ke-mcp.json 配置文件中获取。",
1106
+ inputSchema: {
1107
+ domain: z.string().optional().describe("KE 平台域名(如:https://ke.example.com),用于 API 请求。未指定时从 .mcp/bd-ke-mcp.json 配置文件获取"),
1108
+ access_token: z.string().optional().describe("访问令牌(leo-user-token),用于 API 认证。未指定时从 .mcp/bd-ke-mcp.json 配置文件获取"),
1109
+ tenant: z.string().optional().describe("租户名称,指定要查询项目的租户。未指定时从 .mcp/bd-ke-mcp.json 配置文件获取")
1110
+ }
934
1111
  },
935
- async () => {
1112
+ async ({ domain, access_token, tenant }) => {
936
1113
  try {
937
- const result = await keProjectsList();
1114
+ const result = await keProjectsList({ domain, access_token, tenant });
938
1115
  return { content: [{ type: "text", text: result }] };
939
1116
  } catch (error) {
940
1117
  logger.error("ke_projects_list 失败", { error: error.message });
@@ -947,12 +1124,17 @@ server.registerTool(
947
1124
  server.registerTool(
948
1125
  "ke_app_list",
949
1126
  {
950
- description: "列出所有的应用",
951
- inputSchema: {}
1127
+ description: "列出指定租户和项目下的所有应用。所有配置项如果未指定,则默认从项目目录下的 .mcp/bd-ke-mcp.json 配置文件中获取。",
1128
+ inputSchema: {
1129
+ domain: z.string().optional().describe("KE 平台域名(如:https://ke.example.com),用于 API 请求。未指定时从 .mcp/bd-ke-mcp.json 配置文件获取"),
1130
+ access_token: z.string().optional().describe("访问令牌(leo-user-token),用于 API 认证。未指定时从 .mcp/bd-ke-mcp.json 配置文件获取"),
1131
+ tenant: z.string().optional().describe("租户名称,用于构建命名空间。未指定时从 .mcp/bd-ke-mcp.json 配置文件获取"),
1132
+ project: z.string().optional().describe("项目名称,用于构建命名空间。未指定时从 .mcp/bd-ke-mcp.json 配置文件获取")
1133
+ }
952
1134
  },
953
- async () => {
1135
+ async ({ domain, access_token, tenant, project }) => {
954
1136
  try {
955
- const result = await keAppList();
1137
+ const result = await keAppList({ domain, access_token, tenant, project });
956
1138
  return { content: [{ type: "text", text: result }] };
957
1139
  } catch (error) {
958
1140
  logger.error("ke_app_list 失败", { error: error.message });
@@ -965,14 +1147,16 @@ server.registerTool(
965
1147
  server.registerTool(
966
1148
  "ke_env_list",
967
1149
  {
968
- description: "获取当前租户下的所有环境列表",
1150
+ description: "获取指定租户下的所有可用环境(集群)列表。所有配置项如果未指定,则默认从项目目录下的 .mcp/bd-ke-mcp.json 配置文件中获取。",
969
1151
  inputSchema: {
970
- projectName: z.string().optional().describe("项目名称(已废弃,保留以保持向后兼容)")
1152
+ domain: z.string().optional().describe("KE 平台域名(如:https://ke.example.com),用于 API 请求。未指定时从 .mcp/bd-ke-mcp.json 配置文件获取"),
1153
+ access_token: z.string().optional().describe("访问令牌(leo-user-token),用于 API 认证。未指定时从 .mcp/bd-ke-mcp.json 配置文件获取"),
1154
+ tenant: z.string().optional().describe("租户名称,指定要查询环境的租户。未指定时从 .mcp/bd-ke-mcp.json 配置文件获取")
971
1155
  }
972
1156
  },
973
- async () => {
1157
+ async ({ domain, access_token, tenant }) => {
974
1158
  try {
975
- const result = await keEnvList();
1159
+ const result = await keEnvList({ domain, access_token, tenant });
976
1160
  return { content: [{ type: "text", text: result }] };
977
1161
  } catch (error) {
978
1162
  logger.error("ke_env_list 失败", { error: error.message });
@@ -985,14 +1169,19 @@ server.registerTool(
985
1169
  server.registerTool(
986
1170
  "ke_pods_list",
987
1171
  {
988
- description: "获取指定应用的 Pod 实例列表,包含实例名称、状态、创建时间、容器IP、运行节点、重启次数等信息",
1172
+ description: "获取指定应用的 Pod 实例列表,包含实例名称、状态、创建时间、容器IP、运行节点、重启次数等信息。所有配置项如果未指定,则默认从项目目录下的 .mcp/bd-ke-mcp.json 配置文件中获取。",
989
1173
  inputSchema: {
990
- appName: z.string().describe("应用名称,可通过 ke_app_list 获取")
1174
+ domain: z.string().optional().describe("KE 平台域名(如:https://ke.example.com),用于 API 请求。未指定时从 .mcp/bd-ke-mcp.json 配置文件获取"),
1175
+ access_token: z.string().optional().describe("访问令牌(leo-user-token),用于 API 认证。未指定时从 .mcp/bd-ke-mcp.json 配置文件获取"),
1176
+ tenant: z.string().optional().describe("租户名称,用于构建命名空间。未指定时从 .mcp/bd-ke-mcp.json 配置文件获取"),
1177
+ project: z.string().optional().describe("项目名称,用于构建命名空间。未指定时从 .mcp/bd-ke-mcp.json 配置文件获取"),
1178
+ appName: z.string().describe("应用名称,指定要查询 Pod 的应用,可通过 ke_app_list 获取"),
1179
+ env: z.string().describe("环境名称,指定要查询的环境(集群),可通过 ke_env_list 获取")
991
1180
  }
992
1181
  },
993
- async ({ appName }) => {
1182
+ async ({ domain, access_token, tenant, project, appName, env }) => {
994
1183
  try {
995
- const result = await kePodsList(appName);
1184
+ const result = await kePodsList({ domain, access_token, tenant, project, appName, env });
996
1185
  return { content: [{ type: "text", text: result }] };
997
1186
  } catch (error) {
998
1187
  logger.error("ke_pods_list 失败", { error: error.message });
@@ -1005,21 +1194,24 @@ server.registerTool(
1005
1194
  server.registerTool(
1006
1195
  "ke_pod_log_list",
1007
1196
  {
1008
- description: "获取指定应用的 Pod 日志列表",
1197
+ description: "获取指定应用的 Pod 日志列表,支持按时间范围查询和分页。所有配置项如果未指定,则默认从项目目录下的 .mcp/bd-ke-mcp.json 配置文件中获取。",
1009
1198
  inputSchema: {
1010
- namespace: z.string().describe("命名空间,格式为 tenant-project(如:app-sheyang)"),
1011
- service: z.string().describe("服务名称(应用名称),可通过 ke_app_list 获取"),
1012
- env: z.string().describe("环境名称,可通过 ke_env_list 获取"),
1013
- start_time: z.number().describe("开始时间(纳秒时间戳)"),
1014
- end_time: z.number().describe("结束时间(纳秒时间戳)"),
1015
- size: z.number().optional().default(100).describe("返回记录数量,默认 100"),
1016
- offset: z.number().optional().default(0).describe("偏移量,默认 0"),
1017
- sort: z.string().optional().default("desc").describe("排序方式,默认 desc(降序),可选 asc(升序)")
1199
+ domain: z.string().optional().describe("KE 平台域名(如:https://ke.example.com),用于 API 请求。未指定时从 .mcp/bd-ke-mcp.json 配置文件获取"),
1200
+ access_token: z.string().optional().describe("访问令牌(leo-user-token),用于 API 认证。未指定时从 .mcp/bd-ke-mcp.json 配置文件获取"),
1201
+ tenant: z.string().optional().describe("租户名称,用于日志查询 API 路径。未指定时从 .mcp/bd-ke-mcp.json 配置文件获取"),
1202
+ namespace: z.string().optional().describe("命名空间,格式为 tenant-project(如:myapp-production),用于筛选日志来源。未指定时从配置文件的 tenant-project 自动构建"),
1203
+ application: z.string().optional().describe("应用名称,指定要查询日志的应用,可通过 ke_app_list 获取。未指定时从 .mcp/bd-ke-mcp.json 配置文件获取"),
1204
+ env: z.string().optional().describe("环境名称,指定要查询日志的环境(集群),可通过 ke_env_list 获取。未指定时从 .mcp/bd-ke-mcp.json 配置文件获取"),
1205
+ startTime: z.string().describe("查询开始时间,纳秒级时间戳字符串(如:\"1704067200000000000\" 表示 2024-01-01 00:00:00)"),
1206
+ endTime: z.string().describe("查询结束时间,纳秒级时间戳字符串(如:\"1704153600000000000\" 表示 2024-01-02 00:00:00)"),
1207
+ size: z.number().describe("返回的日志记录数量,建议不超过 1000"),
1208
+ offset: z.number().describe("分页偏移量,用于翻页查询,从 0 开始"),
1209
+ sort: z.string().describe("日志排序方式,desc 表示按时间降序(最新在前),asc 表示按时间升序(最早在前)")
1018
1210
  }
1019
1211
  },
1020
- async ({ namespace, service, env, start_time, end_time, size, offset, sort }) => {
1212
+ async ({ domain, access_token, tenant, namespace, application, env, startTime, endTime, size, offset, sort }) => {
1021
1213
  try {
1022
- const result = await kePodLogList(namespace, service, env, start_time, end_time, size, offset, sort);
1214
+ const result = await kePodLogList({ domain, access_token, tenant, namespace, application, env, startTime, endTime, size, offset, sort });
1023
1215
  return { content: [{ type: "text", text: result }] };
1024
1216
  } catch (error) {
1025
1217
  logger.error("ke_pod_log_list 失败", { error: error.message });
@@ -1028,32 +1220,6 @@ server.registerTool(
1028
1220
  }
1029
1221
  );
1030
1222
 
1031
- // 注册工具:ke_pod_exec
1032
- server.registerTool(
1033
- "ke_pod_exec",
1034
- {
1035
- description: "在 Pod 容器中执行命令(如:ls, pwd, cat 等)",
1036
- inputSchema: {
1037
- tenant: z.string().describe("租户名称"),
1038
- project: z.string().describe("项目名称"),
1039
- podName: z.string().describe("Pod 名称"),
1040
- cluster: z.string().describe("集群/环境名称(如:funeng-test)"),
1041
- command: z.string().describe("要执行的命令(如:ls, pwd, cat /etc/hosts)"),
1042
- container: z.string().optional().describe("容器名称(可选,如果 Pod 有多个容器)"),
1043
- nodeName: z.string().optional().describe("节点名称(可选)")
1044
- }
1045
- },
1046
- async ({ tenant, project, podName, cluster, command, container, nodeName }) => {
1047
- try {
1048
- const result = await kePodExec(tenant, project, podName, cluster, command, container, nodeName);
1049
- return { content: [{ type: "text", text: result }] };
1050
- } catch (error) {
1051
- logger.error("ke_pod_exec 失败", { error: error.message });
1052
- return { content: [{ type: "text", text: `错误: ${error.message}` }], isError: true };
1053
- }
1054
- }
1055
- );
1056
-
1057
1223
  // ==================== 启动服务 ====================
1058
1224
 
1059
1225
  async function main() {
@@ -1067,6 +1233,7 @@ async function main() {
1067
1233
  pid: process.pid,
1068
1234
  projectRoot: getProjectRoot(),
1069
1235
  tools: [
1236
+ "ke_config_reset",
1070
1237
  "ke_app_restart",
1071
1238
  "ke_pipeline_list",
1072
1239
  "ke_pipeline_info",
@@ -1076,8 +1243,7 @@ async function main() {
1076
1243
  "ke_app_list",
1077
1244
  "ke_env_list",
1078
1245
  "ke_pods_list",
1079
- "ke_pod_log_list",
1080
- "ke_pod_exec"
1246
+ "ke_pod_log_list"
1081
1247
  ]
1082
1248
  });
1083
1249
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@junjun-org/bd-ke-mcp",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "type": "module",
5
5
  "description": "MCP (Model Context Protocol) tools for BD-KE - Knowledge Engine application management",
6
6
  "main": "index.js",