@cnbcool/mcp-server 0.4.3 → 0.4.5

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 CHANGED
@@ -2,6 +2,41 @@
2
2
 
3
3
  CNB(https://cnb.cool) toolkits for LLMs supporting the MCP protocol
4
4
 
5
+ ## Tool List
6
+
7
+ | Tool Name | Tool Description |
8
+ | :----- | :------- |
9
+ | cnb_list_groups | Gets a list of top-level organizations for which the current user has permissions on the CNB platform. |
10
+ | cnb_list_sub_groups | Gets a list of sub-organizations for which the current user has permissions on the CNB platform under a specified organization. |
11
+ | cnb_get_group | Gets information about a specified organization on the CNB platform. |
12
+ | cnb_create_group | Creates a new organization on the CNB platform. |
13
+ | cnb_list_repositories | Gets a list of repositories for which the current user has permissions on the CNB platform. |
14
+ | cnb_list_group_repositories | Gets a list of repositories for which the current user has permissions on the CNB platform under a specified organization. |
15
+ | cnb_get_current_repository | Gets information about the CNB platform repository corresponding to the current workspace. |
16
+ | cnb_get_repository | Gets information about a specified repository on the CNB platform. |
17
+ | cnb_create_repository | Create a new repository on the CNB platform. |
18
+ | cnb_list_issues | Get a list of issues in a specified repository on the CNB platform. |
19
+ | cnb_get_issue | Get information about a specified issue on the CNB platform. |
20
+ | cnb_create_issue | Create a new issue in a specified repository on the CNB platform. To add labels, use the cnb_add_issue_labels tool. |
21
+ | cnb_update_issue | Update information about a specified issue on the CNB platform. To update labels, call the cnb_set_issue_labels tool separately. |
22
+ | cnb_list_issue_comments | Get a list of comments for a specified issue on the CNB platform. |
23
+ | cnb_create_issue_comment | Create a new comment on a specified issue on the CNB platform. |
24
+ | cnb_update_issue_comment | Update the content of a comment on a specified issue on the CNB platform. |
25
+ | cnb_list_issue_labels | Get a list of labels for a specified issue on the CNB platform. |
26
+ | cnb_add_issue_labels | Add one or more labels to a specified issue on the CNB platform. |
27
+ | cnb_set_issue_labels | Change the labels for a specified issue on the CNB platform. |
28
+ | cnb_clear_issue_labels | Clear the labels for a specified issue on the CNB platform. |
29
+ | cnb_remove_issue_label | Remove a specified label from a specified issue on the CNB platform. |
30
+ | cnb_list_pulls | Get a list of merge requests for a specified repository on the CNB platform. |
31
+ | cnb_get_pull | Get information about a merge request specified on the CNB platform |
32
+ | cnb_create_pull | Create a new merge request in a repository specified on the CNB platform |
33
+ | cnb_update_pull | Update information about a merge request specified on the CNB platform |
34
+ | cnb_merge_pull | Merge a merge request specified on the CNB platform |
35
+ | cnb_list_pull_comments | Get a list of comments for a merge request specified on the CNB platform |
36
+ | cnb_create_pull_comment | Create a new comment on a merge request specified on the CNB platform |
37
+ | cnb_list_workspaces | Get a list of the current user's cloud-native development environments on the CNB platform |
38
+ | cnb_delete_workspace | Delete a specified cloud-native development environment on the CNB platform |
39
+
5
40
  ## How to use
6
41
 
7
42
  ### STDIO
@@ -57,5 +92,3 @@ CNB(https://cnb.cool) toolkits for LLMs supporting the MCP protocol
57
92
  }
58
93
  }
59
94
  ```
60
-
61
-
package/README_zh.md CHANGED
@@ -2,6 +2,41 @@
2
2
 
3
3
  CNB(https://cnb.cool) 支持 MCP 协议的 MCP Server
4
4
 
5
+ ## 工具列表
6
+
7
+ | 工具名 | 工具描述 |
8
+ | :----- | :------- |
9
+ | cnb_list_groups | 获取当前用户在CNB平台里拥有权限的顶层组织列表 |
10
+ | cnb_list_sub_groups | 获取当前用户在CNB平台里指定组织下拥有权限的子组织列表 |
11
+ | cnb_get_group | 获取CNB平台指定组织的信息 |
12
+ | cnb_create_group | 在CNB平台创建一个新组织 |
13
+ | cnb_list_repositories | 获取当前用户在CNB平台里拥有权限的仓库列表 |
14
+ | cnb_list_group_repositories | 获取当前用户在CNB平台里指定组织下拥有权限的仓库列表 |
15
+ | cnb_get_current_repository | 获取当前工作区对应的CNB平台仓库信息 |
16
+ | cnb_get_repository | 获取CNB平台指定仓库的信息 |
17
+ | cnb_create_repository | 在CNB平台创建一个新仓库 |
18
+ | cnb_list_issues | 获取CNB平台指定仓库的ISSUE列表 |
19
+ | cnb_get_issue | 获取CNB平台指定ISSUE的信息 |
20
+ | cnb_create_issue | 在CNB平台指定的仓库创建一条新ISSUE。如需添加标签,另外调用cnb_add_issue_labels工具 |
21
+ | cnb_update_issue | 更新CNB平台指定ISSUE的信息。如需更新标签,另外调用cnb_set_issue_labels工具 |
22
+ | cnb_list_issue_comments | 获取CNB平台指定ISSUE的评论列表 |
23
+ | cnb_create_issue_comment | 在CNB平台指定的ISSUE创建一条新评论 |
24
+ | cnb_update_issue_comment | 更新CNB平台指定ISSUE评论的内容 |
25
+ | cnb_list_issue_labels | 获取CNB平台指定ISSUE的标签列表 |
26
+ | cnb_add_issue_labels | 为CNB平台指定的ISSUE添加一个或多个标签 |
27
+ | cnb_set_issue_labels | 变更CNB平台指定ISSUE的标签 |
28
+ | cnb_clear_issue_labels | 清除CNB平台指定ISSUE的标签 |
29
+ | cnb_remove_issue_label | 移除CNB平台指定ISSUE的指定标签 |
30
+ | cnb_list_pulls | 获取CNB平台指定仓库的合并请求列表 |
31
+ | cnb_get_pull | 获取CNB平台指定合并请求的信息 |
32
+ | cnb_create_pull | 在CNB平台指定的仓库创建一个新合并请求 |
33
+ | cnb_update_pull | 更新CNB平台指定合并请求的信息 |
34
+ | cnb_merge_pull | 合并CNB平台指定的合并请求 |
35
+ | cnb_list_pull_comments | 获取CNB平台指定合并请求的评论列表 |
36
+ | cnb_create_pull_comment | 在CNB平台指定的合并请求创建一条新评论 |
37
+ | cnb_list_workspaces | 获取当前用户在CNB平台的云原生开发环境列表 |
38
+ | cnb_delete_workspace | 在CNB平台删除指定的云原生开发环境 |
39
+
5
40
  ## 使用方法
6
41
 
7
42
  ### STDIO
@@ -1,9 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  class CnbApiClient {
4
- static instance = null;
5
- _baseUrl;
6
- _token;
7
4
  constructor(options) {
8
5
  this._baseUrl = options.baseUrl;
9
6
  this._token = options.token;
@@ -28,7 +25,7 @@ class CnbApiClient {
28
25
  const headers = {
29
26
  Authorization: `Bearer ${this._token}`,
30
27
  Accept: 'application/vnd.cnb.api+json',
31
- ...(config?.header || {})
28
+ ...((config === null || config === void 0 ? void 0 : config.header) || {})
32
29
  };
33
30
  const options = {
34
31
  method,
@@ -49,4 +46,5 @@ class CnbApiClient {
49
46
  return response.json();
50
47
  }
51
48
  }
49
+ CnbApiClient.instance = null;
52
50
  exports.default = CnbApiClient;
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RepoVisibility = void 0;
4
+ var RepoVisibility;
5
+ (function (RepoVisibility) {
6
+ RepoVisibility["private"] = "Private";
7
+ RepoVisibility["public"] = "Public";
8
+ RepoVisibility["secret"] = "Secret";
9
+ })(RepoVisibility || (exports.RepoVisibility = RepoVisibility = {}));
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.toolDescriptions = void 0;
4
+ const toolNames_1 = require("./toolNames");
5
+ exports.toolDescriptions = {
6
+ // 组织工具
7
+ [toolNames_1.ToolNames.LIST_GROUPS]: '获取当前用户在CNB平台里拥有权限的顶层组织列表',
8
+ [toolNames_1.ToolNames.LIST_SUB_GROUPS]: '获取当前用户在CNB平台里指定组织下拥有权限的子组织列表',
9
+ [toolNames_1.ToolNames.GET_GROUP]: '获取CNB平台指定组织的信息',
10
+ [toolNames_1.ToolNames.CREATE_GROUP]: '在CNB平台创建一个新组织',
11
+ // 仓库工具
12
+ [toolNames_1.ToolNames.LIST_REPOSITORIES]: '获取当前用户在CNB平台里拥有权限的仓库列表',
13
+ [toolNames_1.ToolNames.LIST_GROUP_REPOSITORIES]: '获取当前用户在CNB平台里指定组织下拥有权限的仓库列表',
14
+ [toolNames_1.ToolNames.GET_CURRENT_REPOSITORY]: '获取当前工作区对应的CNB平台仓库信息',
15
+ [toolNames_1.ToolNames.GET_REPOSITORY]: '获取CNB平台指定仓库的信息',
16
+ [toolNames_1.ToolNames.CREATE_REPOSITORY]: '在CNB平台创建一个新仓库',
17
+ // ISSUE 工具
18
+ [toolNames_1.ToolNames.LIST_ISSUES]: '获取CNB平台指定仓库的ISSUE列表',
19
+ [toolNames_1.ToolNames.GET_ISSUE]: '获取CNB平台指定ISSUE的信息',
20
+ [toolNames_1.ToolNames.CREATE_ISSUE]: `在CNB平台指定的仓库创建一条新ISSUE。如需添加标签,另外调用${toolNames_1.ToolNames.ADD_ISSUE_LABELS}工具`,
21
+ [toolNames_1.ToolNames.UPDATE_ISSUE]: `更新CNB平台指定ISSUE的信息。如需更新标签,另外调用${toolNames_1.ToolNames.SET_ISSUE_LABELS}工具`,
22
+ [toolNames_1.ToolNames.LIST_ISSUE_COMMENTS]: '获取CNB平台指定ISSUE的评论列表',
23
+ [toolNames_1.ToolNames.CREATE_ISSUE_COMMENT]: '在CNB平台指定的ISSUE创建一条新评论',
24
+ [toolNames_1.ToolNames.UPDATE_ISSUE_COMMENT]: '更新CNB平台指定ISSUE评论的内容',
25
+ [toolNames_1.ToolNames.LIST_ISSUE_LABELS]: '获取CNB平台指定ISSUE的标签列表',
26
+ [toolNames_1.ToolNames.ADD_ISSUE_LABELS]: '为CNB平台指定的ISSUE添加一个或多个标签',
27
+ [toolNames_1.ToolNames.SET_ISSUE_LABELS]: '变更CNB平台指定ISSUE的标签',
28
+ [toolNames_1.ToolNames.CLEAR_ISSUE_LABELS]: '清除CNB平台指定ISSUE的标签',
29
+ [toolNames_1.ToolNames.REMOVE_ISSUE_LABEL]: '移除CNB平台指定ISSUE的指定标签',
30
+ // 合并请求工具
31
+ [toolNames_1.ToolNames.LIST_PULLS]: '获取CNB平台指定仓库的合并请求列表',
32
+ [toolNames_1.ToolNames.GET_PULL]: '获取CNB平台指定合并请求的信息',
33
+ [toolNames_1.ToolNames.CREATE_PULL]: '在CNB平台指定的仓库创建一个新合并请求',
34
+ [toolNames_1.ToolNames.UPDATE_PULL]: '更新CNB平台指定合并请求的信息',
35
+ [toolNames_1.ToolNames.MERGE_PULL]: '合并CNB平台指定的合并请求',
36
+ [toolNames_1.ToolNames.LIST_PULL_COMMENTS]: '获取CNB平台指定合并请求的评论列表',
37
+ [toolNames_1.ToolNames.CREATE_PULL_COMMENT]: '在CNB平台指定的合并请求创建一条新评论',
38
+ // 云原生开发工具
39
+ [toolNames_1.ToolNames.LIST_WORKSPACES]: '获取当前用户在CNB平台的云原生开发环境列表',
40
+ [toolNames_1.ToolNames.DELETE_WORKSPACE]: '在CNB平台删除指定的云原生开发环境'
41
+ };
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ToolNames = void 0;
4
+ var ToolNames;
5
+ (function (ToolNames) {
6
+ // 组织工具
7
+ ToolNames["LIST_GROUPS"] = "cnb_list_groups";
8
+ ToolNames["LIST_SUB_GROUPS"] = "cnb_list_sub_groups";
9
+ ToolNames["GET_GROUP"] = "cnb_get_group";
10
+ ToolNames["CREATE_GROUP"] = "cnb_create_group";
11
+ // 仓库工具
12
+ ToolNames["LIST_REPOSITORIES"] = "cnb_list_repositories";
13
+ ToolNames["LIST_GROUP_REPOSITORIES"] = "cnb_list_group_repositories";
14
+ ToolNames["GET_CURRENT_REPOSITORY"] = "cnb_get_current_repository";
15
+ ToolNames["GET_REPOSITORY"] = "cnb_get_repository";
16
+ ToolNames["CREATE_REPOSITORY"] = "cnb_create_repository";
17
+ // ISSUE 工具
18
+ ToolNames["LIST_ISSUES"] = "cnb_list_issues";
19
+ ToolNames["GET_ISSUE"] = "cnb_get_issue";
20
+ ToolNames["CREATE_ISSUE"] = "cnb_create_issue";
21
+ ToolNames["UPDATE_ISSUE"] = "cnb_update_issue";
22
+ ToolNames["LIST_ISSUE_COMMENTS"] = "cnb_list_issue_comments";
23
+ ToolNames["CREATE_ISSUE_COMMENT"] = "cnb_create_issue_comment";
24
+ ToolNames["UPDATE_ISSUE_COMMENT"] = "cnb_update_issue_comment";
25
+ ToolNames["LIST_ISSUE_LABELS"] = "cnb_list_issue_labels";
26
+ ToolNames["ADD_ISSUE_LABELS"] = "cnb_add_issue_labels";
27
+ ToolNames["SET_ISSUE_LABELS"] = "cnb_set_issue_labels";
28
+ ToolNames["CLEAR_ISSUE_LABELS"] = "cnb_clear_issue_labels";
29
+ ToolNames["REMOVE_ISSUE_LABEL"] = "cnb_remove_issue_label";
30
+ // 合并请求工具
31
+ ToolNames["LIST_PULLS"] = "cnb_list_pulls";
32
+ ToolNames["GET_PULL"] = "cnb_get_pull";
33
+ ToolNames["CREATE_PULL"] = "cnb_create_pull";
34
+ ToolNames["UPDATE_PULL"] = "cnb_update_pull";
35
+ ToolNames["MERGE_PULL"] = "cnb_merge_pull";
36
+ ToolNames["LIST_PULL_COMMENTS"] = "cnb_list_pull_comments";
37
+ ToolNames["CREATE_PULL_COMMENT"] = "cnb_create_pull_comment";
38
+ // 云原生开发工具
39
+ ToolNames["LIST_WORKSPACES"] = "cnb_list_workspaces";
40
+ ToolNames["DELETE_WORKSPACE"] = "cnb_delete_workspace";
41
+ })(ToolNames || (exports.ToolNames = ToolNames = {}));
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isRepoPublic = isRepoPublic;
4
+ const index_js_1 = require("../constants/index.js");
5
+ const repository_js_1 = require("../api/repository.js");
6
+ const formatRepoUrl_js_1 = require("./formatRepoUrl.js");
7
+ async function isRepoPublic(url) {
8
+ const repoPath = (0, formatRepoUrl_js_1.getRepoPath)(url);
9
+ if (!repoPath)
10
+ return true;
11
+ try {
12
+ const { visibility_level } = await (0, repository_js_1.getRepository)(repoPath);
13
+ // @ts-expect-error 字段类型转换过,但 swagger 无法感知
14
+ return visibility_level === index_js_1.RepoVisibility.public;
15
+ }
16
+ catch (_a) {
17
+ return true;
18
+ }
19
+ }
@@ -5,11 +5,12 @@ const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
5
5
  const index_js_1 = require("../tools/index.js");
6
6
  const package_json_1 = require("../../package.json");
7
7
  function createMcpServer(req) {
8
+ var _a;
8
9
  const mcpServer = new mcp_js_1.McpServer({
9
10
  name: 'cnb-mcp-server',
10
11
  version: package_json_1.version
11
12
  });
12
- const token = req?.headers['authorization']?.split(' ')[1];
13
+ const token = (_a = req === null || req === void 0 ? void 0 : req.headers['authorization']) === null || _a === void 0 ? void 0 : _a.split(' ')[1];
13
14
  (0, index_js_1.registerTools)(mcpServer, token);
14
15
  return mcpServer;
15
16
  }
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.transports = void 0;
4
+ exports.createStreamableTransport = createStreamableTransport;
5
+ const node_crypto_1 = require("node:crypto");
6
+ const streamableHttp_js_1 = require("@modelcontextprotocol/sdk/server/streamableHttp.js");
7
+ const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
8
+ const createMcpServer_1 = require("./createMcpServer");
9
+ // Store transports for each session type
10
+ exports.transports = {
11
+ streamable: {},
12
+ sse: {}
13
+ };
14
+ async function createStreamableTransport(req) {
15
+ const sessionId = req.headers['mcp-session-id'];
16
+ // Reuse existing transport
17
+ if (sessionId && exports.transports.streamable[sessionId]) {
18
+ const transport = exports.transports.streamable[sessionId];
19
+ if (!(transport instanceof streamableHttp_js_1.StreamableHTTPServerTransport)) {
20
+ throw new Error('Bad Request: Session exists but uses a different transport protocol');
21
+ }
22
+ return transport;
23
+ }
24
+ // New initialization request
25
+ if (!sessionId && (0, types_js_1.isInitializeRequest)(req.body)) {
26
+ const transport = new streamableHttp_js_1.StreamableHTTPServerTransport({
27
+ sessionIdGenerator: () => (0, node_crypto_1.randomUUID)(),
28
+ onsessioninitialized: (sessionId) => {
29
+ exports.transports.streamable[sessionId] = transport;
30
+ }
31
+ });
32
+ // Clean up transport when closed
33
+ transport.onclose = () => {
34
+ console.log(`Transport closed for session ${transport.sessionId}`);
35
+ console.log(Object.keys(exports.transports.streamable));
36
+ if (transport.sessionId) {
37
+ delete exports.transports.streamable[transport.sessionId];
38
+ }
39
+ };
40
+ const mcpServer = (0, createMcpServer_1.createMcpServer)(req);
41
+ await mcpServer.connect(transport);
42
+ return transport;
43
+ }
44
+ throw new Error('Bad Request: No valid session ID provided');
45
+ }
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getRepoPath = getRepoPath;
4
+ function getRepoPath(url) {
5
+ var _a;
6
+ let repoPath = '';
7
+ if (!url)
8
+ return repoPath;
9
+ try {
10
+ const urlObj = new URL(url);
11
+ // Remove leading /
12
+ repoPath = urlObj.pathname.substring(1);
13
+ }
14
+ catch (_b) {
15
+ // ssh format address or malformed url
16
+ repoPath = (_a = url.split(':')[1]) !== null && _a !== void 0 ? _a : '';
17
+ }
18
+ // Remove tailing .git
19
+ repoPath = repoPath.replace(/\.git$/, '');
20
+ return repoPath;
21
+ }
@@ -1,12 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.stopWithWrongTransport = stopWithWrongTransport;
4
- function stopWithWrongTransport(res) {
3
+ exports.stopWithBadRequest = stopWithBadRequest;
4
+ function stopWithBadRequest(res, message) {
5
5
  res.status(400).json({
6
6
  jsonrpc: '2.0',
7
7
  error: {
8
8
  code: -32000,
9
- message: 'Bad Request: Session exists but uses a different transport protocol'
9
+ message
10
10
  },
11
11
  id: null
12
12
  });
@@ -3,100 +3,64 @@
3
3
  var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  return (mod && mod.__esModule) ? mod : { "default": mod };
5
5
  };
6
+ var _a;
6
7
  Object.defineProperty(exports, "__esModule", { value: true });
7
8
  const express_1 = __importDefault(require("express"));
8
- const node_crypto_1 = require("node:crypto");
9
- const streamableHttp_js_1 = require("@modelcontextprotocol/sdk/server/streamableHttp.js");
10
9
  const sse_js_1 = require("@modelcontextprotocol/sdk/server/sse.js");
11
- const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
12
10
  const dotenv_1 = __importDefault(require("dotenv"));
13
11
  const createMcpServer_js_1 = require("./helpers/createMcpServer.js");
14
12
  const sendResponse_js_1 = require("./helpers/sendResponse.js");
13
+ const createTransport_js_1 = require("./helpers/createTransport.js");
15
14
  dotenv_1.default.config();
16
15
  const DEFAULT_APP_PORT = 3000;
17
- // Store transports for each session type
18
- const transports = {
19
- streamable: {},
20
- sse: {}
21
- };
22
16
  const app = (0, express_1.default)();
23
17
  app.use(express_1.default.json());
24
18
  app.post('/mcp', async (req, res) => {
25
- const sessionId = req.headers['mcp-session-id'];
26
19
  let transport;
27
- // Reuse existing transport
28
- if (sessionId && transports.streamable[sessionId]) {
29
- transport = transports.streamable[sessionId];
30
- if (!(transport instanceof streamableHttp_js_1.StreamableHTTPServerTransport)) {
31
- (0, sendResponse_js_1.stopWithWrongTransport)(res);
32
- return;
33
- }
34
- await transport.handleRequest(req, res, req.body);
35
- return;
20
+ try {
21
+ transport = await (0, createTransport_js_1.createStreamableTransport)(req);
36
22
  }
37
- // New initialization request
38
- if (!sessionId && (0, types_js_1.isInitializeRequest)(req.body)) {
39
- transport = new streamableHttp_js_1.StreamableHTTPServerTransport({
40
- sessionIdGenerator: () => (0, node_crypto_1.randomUUID)(),
41
- onsessioninitialized: (sessionId) => {
42
- transports.streamable[sessionId] = transport;
43
- }
44
- });
45
- // Clean up transport when closed
46
- transport.onclose = () => {
47
- if (transport.sessionId) {
48
- delete transports.streamable[transport.sessionId];
49
- }
50
- };
51
- const mcpServer = (0, createMcpServer_js_1.createMcpServer)(req);
52
- await mcpServer.connect(transport);
53
- await transport.handleRequest(req, res, req.body);
23
+ catch (err) {
24
+ const message = err instanceof Error ? err.message : 'Unknown error';
25
+ (0, sendResponse_js_1.stopWithBadRequest)(res, message);
54
26
  return;
55
27
  }
56
- // Invalid request
57
- res.status(400).json({
58
- jsonrpc: '2.0',
59
- error: {
60
- code: -32000,
61
- message: 'Bad Request: No valid session ID provided'
62
- },
63
- id: null
64
- });
28
+ await transport.handleRequest(req, res, req.body);
65
29
  });
66
30
  const handleSessionRequest = async (req, res) => {
67
31
  const sessionId = req.headers['mcp-session-id'];
68
- if (!sessionId || !transports.streamable[sessionId]) {
32
+ if (!sessionId || !createTransport_js_1.transports.streamable[sessionId]) {
69
33
  res.status(400).send('Invalid or missing session ID');
70
34
  return;
71
35
  }
72
- const transport = transports.streamable[sessionId];
36
+ const transport = createTransport_js_1.transports.streamable[sessionId];
73
37
  await transport.handleRequest(req, res, req.body);
74
38
  };
75
39
  app.get('/mcp', handleSessionRequest);
76
40
  app.delete('/mcp', handleSessionRequest);
77
41
  app.get('/sse', async (req, res) => {
78
42
  const transport = new sse_js_1.SSEServerTransport('/messages', res);
79
- transports.sse[transport.sessionId] = transport;
43
+ createTransport_js_1.transports.sse[transport.sessionId] = transport;
80
44
  res.on('close', () => {
81
- delete transports.sse[transport.sessionId];
45
+ delete createTransport_js_1.transports.sse[transport.sessionId];
82
46
  });
83
47
  const mcpServer = (0, createMcpServer_js_1.createMcpServer)(req);
84
48
  await mcpServer.connect(transport);
85
49
  });
86
50
  app.post('/messages', async (req, res) => {
87
51
  const sessionId = req.query.sessionId;
88
- const transport = transports.sse[sessionId];
52
+ const transport = createTransport_js_1.transports.sse[sessionId];
89
53
  if (!transport) {
90
54
  res.status(400).send('No transport found for sessionId');
91
55
  return;
92
56
  }
93
57
  if (!(transport instanceof sse_js_1.SSEServerTransport)) {
94
- (0, sendResponse_js_1.stopWithWrongTransport)(res);
58
+ (0, sendResponse_js_1.stopWithBadRequest)(res, 'Bad Request: Session exists but uses a different transport protocol');
95
59
  return;
96
60
  }
97
61
  await transport.handlePostMessage(req, res, req.body);
98
62
  });
99
- let port = parseInt(process.env.APP_PORT ?? '', 10);
63
+ let port = parseInt((_a = process.env.APP_PORT) !== null && _a !== void 0 ? _a : '', 10);
100
64
  if (isNaN(port)) {
101
65
  port = DEFAULT_APP_PORT;
102
66
  }
@@ -2,10 +2,12 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.default = registerGroupTools;
4
4
  const zod_1 = require("zod");
5
+ const toolNames_js_1 = require("../constants/toolNames.js");
6
+ const toolDescriptions_js_1 = require("../constants/toolDescriptions.js");
5
7
  const group_js_1 = require("../api/group.js");
6
8
  const formatToolResult_js_1 = require("../helpers/formatToolResult.js");
7
9
  function registerGroupTools(server) {
8
- server.tool('list-groups', '获取当前用户拥有权限的顶层组织列表', {
10
+ server.tool(toolNames_js_1.ToolNames.LIST_GROUPS, toolDescriptions_js_1.toolDescriptions[toolNames_js_1.ToolNames.LIST_GROUPS], {
9
11
  page: zod_1.z.number().default(1).describe('第几页,从1开始'),
10
12
  page_size: zod_1.z.number().default(10).describe('每页多少条数据'),
11
13
  search: zod_1.z.preprocess((val) => (val === null ? undefined : val), zod_1.z.string().optional()).describe('仓库关键字'),
@@ -15,13 +17,13 @@ function registerGroupTools(server) {
15
17
  }, async ({ page, page_size, search, role }) => {
16
18
  try {
17
19
  const groups = await (0, group_js_1.listGroups)({ page, page_size, search, role });
18
- return (0, formatToolResult_js_1.formatTextToolResult)(JSON.stringify(groups, null, 2), 'list-groups');
20
+ return (0, formatToolResult_js_1.formatTextToolResult)(JSON.stringify(groups, null, 2), toolNames_js_1.ToolNames.LIST_GROUPS);
19
21
  }
20
22
  catch (error) {
21
- return (0, formatToolResult_js_1.formatToolError)(error, 'list-groups');
23
+ return (0, formatToolResult_js_1.formatToolError)(error, toolNames_js_1.ToolNames.LIST_GROUPS);
22
24
  }
23
25
  });
24
- server.tool('list-sub-groups', '查询当前用户在指定组织下拥有指定权限的子组织列表', {
26
+ server.tool(toolNames_js_1.ToolNames.LIST_SUB_GROUPS, toolDescriptions_js_1.toolDescriptions[toolNames_js_1.ToolNames.LIST_SUB_GROUPS], {
25
27
  group: zod_1.z.string().describe('组织名称'),
26
28
  page: zod_1.z.number().default(1).describe('第几页,从1开始'),
27
29
  page_size: zod_1.z.number().default(10).describe('每页多少条数据'),
@@ -29,24 +31,24 @@ function registerGroupTools(server) {
29
31
  }, async ({ group, page, page_size, access }) => {
30
32
  try {
31
33
  const subGroups = await (0, group_js_1.listSubGroups)(group, { page, page_size, access });
32
- return (0, formatToolResult_js_1.formatTextToolResult)(JSON.stringify(subGroups, null, 2), 'list-sub-groups');
34
+ return (0, formatToolResult_js_1.formatTextToolResult)(JSON.stringify(subGroups, null, 2), toolNames_js_1.ToolNames.LIST_SUB_GROUPS);
33
35
  }
34
36
  catch (error) {
35
- return (0, formatToolResult_js_1.formatToolError)(error, 'list-sub-groups');
37
+ return (0, formatToolResult_js_1.formatToolError)(error, toolNames_js_1.ToolNames.LIST_SUB_GROUPS);
36
38
  }
37
39
  });
38
- server.tool('get-group', '获取指定组织信息', {
40
+ server.tool(toolNames_js_1.ToolNames.GET_GROUP, toolDescriptions_js_1.toolDescriptions[toolNames_js_1.ToolNames.GET_GROUP], {
39
41
  group: zod_1.z.string().describe('组织路径')
40
42
  }, async ({ group }) => {
41
43
  try {
42
44
  const groupInfo = await (0, group_js_1.getGroup)(group);
43
- return (0, formatToolResult_js_1.formatTextToolResult)(JSON.stringify(groupInfo, null, 2), 'get-group');
45
+ return (0, formatToolResult_js_1.formatTextToolResult)(JSON.stringify(groupInfo, null, 2), toolNames_js_1.ToolNames.GET_GROUP);
44
46
  }
45
47
  catch (error) {
46
- return (0, formatToolResult_js_1.formatToolError)(error, 'get-group');
48
+ return (0, formatToolResult_js_1.formatToolError)(error, toolNames_js_1.ToolNames.GET_GROUP);
47
49
  }
48
50
  });
49
- server.tool('create-group', '创建新组织', {
51
+ server.tool(toolNames_js_1.ToolNames.CREATE_GROUP, toolDescriptions_js_1.toolDescriptions[toolNames_js_1.ToolNames.CREATE_GROUP], {
50
52
  path: zod_1.z.string().describe('组织路径'),
51
53
  description: zod_1.z.preprocess((val) => (val === null ? undefined : val), zod_1.z.string().optional()).describe('组织描述'),
52
54
  remark: zod_1.z.preprocess((val) => (val === null ? undefined : val), zod_1.z.string().optional()).describe('仓库备注'),
@@ -56,10 +58,10 @@ function registerGroupTools(server) {
56
58
  }, async ({ path, description, remark, bind_domain }) => {
57
59
  try {
58
60
  const data = await (0, group_js_1.createGroup)({ path, description, remark, bind_domain });
59
- return (0, formatToolResult_js_1.formatTextToolResult)(JSON.stringify(data, null, 2), 'create-group');
61
+ return (0, formatToolResult_js_1.formatTextToolResult)(JSON.stringify(data, null, 2), toolNames_js_1.ToolNames.CREATE_GROUP);
60
62
  }
61
63
  catch (error) {
62
- return (0, formatToolResult_js_1.formatToolError)(error, 'create-group');
64
+ return (0, formatToolResult_js_1.formatToolError)(error, toolNames_js_1.ToolNames.CREATE_GROUP);
63
65
  }
64
66
  });
65
67
  }
@@ -2,10 +2,12 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.default = registerIssueTools;
4
4
  const zod_1 = require("zod");
5
+ const toolNames_js_1 = require("../constants/toolNames.js");
6
+ const toolDescriptions_js_1 = require("../constants/toolDescriptions.js");
5
7
  const issue_js_1 = require("../api/issue.js");
6
8
  const formatToolResult_js_1 = require("../helpers/formatToolResult.js");
7
9
  function registerIssueTools(server) {
8
- server.tool('list-issues', '查询仓库的 Issues', {
10
+ server.tool(toolNames_js_1.ToolNames.LIST_ISSUES, toolDescriptions_js_1.toolDescriptions[toolNames_js_1.ToolNames.LIST_ISSUES], {
9
11
  repo: zod_1.z.string().describe('仓库路径'),
10
12
  page: zod_1.z.number().default(1).describe('第几页,从1开始'),
11
13
  page_size: zod_1.z.number().default(10).describe('每页多少条数据,默认是30'),
@@ -47,25 +49,25 @@ function registerIssueTools(server) {
47
49
  updated_time_end,
48
50
  order_by
49
51
  });
50
- return (0, formatToolResult_js_1.formatTextToolResult)(JSON.stringify(issues, null, 2), 'list-issues');
52
+ return (0, formatToolResult_js_1.formatTextToolResult)(JSON.stringify(issues, null, 2), toolNames_js_1.ToolNames.LIST_ISSUES);
51
53
  }
52
54
  catch (error) {
53
- return (0, formatToolResult_js_1.formatToolError)(error, 'list-issues');
55
+ return (0, formatToolResult_js_1.formatToolError)(error, toolNames_js_1.ToolNames.LIST_ISSUES);
54
56
  }
55
57
  });
56
- server.tool('get-issue', '获取指定 Issue 信息', {
58
+ server.tool(toolNames_js_1.ToolNames.GET_ISSUE, toolDescriptions_js_1.toolDescriptions[toolNames_js_1.ToolNames.GET_ISSUE], {
57
59
  repo: zod_1.z.string().describe('仓库路径'),
58
60
  issueId: zod_1.z.number().describe('Issue ID')
59
61
  }, async ({ repo, issueId }) => {
60
62
  try {
61
63
  const issues = await (0, issue_js_1.getIssue)(repo, issueId);
62
- return (0, formatToolResult_js_1.formatTextToolResult)(JSON.stringify(issues, null, 2), 'get-issue');
64
+ return (0, formatToolResult_js_1.formatTextToolResult)(JSON.stringify(issues, null, 2), toolNames_js_1.ToolNames.GET_ISSUE);
63
65
  }
64
66
  catch (error) {
65
- return (0, formatToolResult_js_1.formatToolError)(error, 'get-issue');
67
+ return (0, formatToolResult_js_1.formatToolError)(error, toolNames_js_1.ToolNames.GET_ISSUE);
66
68
  }
67
69
  });
68
- server.tool('create-issue', '创建一个 Issue. 如需添加 Issue 标签,需要另外调用 add-issue-labels', {
70
+ server.tool(toolNames_js_1.ToolNames.CREATE_ISSUE, toolDescriptions_js_1.toolDescriptions[toolNames_js_1.ToolNames.CREATE_ISSUE], {
69
71
  repo: zod_1.z.string().describe('仓库路径'),
70
72
  title: zod_1.z.string().describe('Issue 标题'),
71
73
  body: zod_1.z.preprocess((val) => (val === null ? undefined : val), zod_1.z.string().optional()).describe('Issue 描述'),
@@ -93,13 +95,13 @@ function registerIssueTools(server) {
93
95
  end_date,
94
96
  start_date
95
97
  });
96
- return (0, formatToolResult_js_1.formatTextToolResult)(JSON.stringify(issue, null, 2), 'create-issue');
98
+ return (0, formatToolResult_js_1.formatTextToolResult)(JSON.stringify(issue, null, 2), toolNames_js_1.ToolNames.CREATE_ISSUE);
97
99
  }
98
100
  catch (error) {
99
- return (0, formatToolResult_js_1.formatToolError)(error, 'create-issue');
101
+ return (0, formatToolResult_js_1.formatToolError)(error, toolNames_js_1.ToolNames.CREATE_ISSUE);
100
102
  }
101
103
  });
102
- server.tool('update-issue', '更新一个 Issue。 如需更新 Issue 标签,需要另外调用 set-issue-labels', {
104
+ server.tool(toolNames_js_1.ToolNames.UPDATE_ISSUE, toolDescriptions_js_1.toolDescriptions[toolNames_js_1.ToolNames.UPDATE_ISSUE], {
103
105
  repo: zod_1.z.string().describe('仓库路径'),
104
106
  issueId: zod_1.z.number().describe('Issue ID'),
105
107
  title: zod_1.z.preprocess((val) => (val === null ? undefined : val), zod_1.z.string().optional()).describe('Issue 标题'),
@@ -126,13 +128,13 @@ function registerIssueTools(server) {
126
128
  state,
127
129
  state_reason
128
130
  });
129
- return (0, formatToolResult_js_1.formatTextToolResult)(JSON.stringify(issue, null, 2), 'update-issue');
131
+ return (0, formatToolResult_js_1.formatTextToolResult)(JSON.stringify(issue, null, 2), toolNames_js_1.ToolNames.UPDATE_ISSUE);
130
132
  }
131
133
  catch (error) {
132
- return (0, formatToolResult_js_1.formatToolError)(error, 'update-issue');
134
+ return (0, formatToolResult_js_1.formatToolError)(error, toolNames_js_1.ToolNames.UPDATE_ISSUE);
133
135
  }
134
136
  });
135
- server.tool('list-issue-comments', '查询 Issue 评论列表', {
137
+ server.tool(toolNames_js_1.ToolNames.LIST_ISSUE_COMMENTS, toolDescriptions_js_1.toolDescriptions[toolNames_js_1.ToolNames.LIST_ISSUE_COMMENTS], {
136
138
  repo: zod_1.z.string().describe('仓库路径'),
137
139
  issueId: zod_1.z.number().describe('Issue ID'),
138
140
  page: zod_1.z.number().default(1).describe('第几页,从1开始'),
@@ -140,26 +142,26 @@ function registerIssueTools(server) {
140
142
  }, async ({ repo, issueId, page, page_size }) => {
141
143
  try {
142
144
  const comments = await (0, issue_js_1.listIssueComments)(repo, issueId, { page, page_size });
143
- return (0, formatToolResult_js_1.formatTextToolResult)(JSON.stringify(comments, null, 2), 'list-issue-comments');
145
+ return (0, formatToolResult_js_1.formatTextToolResult)(JSON.stringify(comments, null, 2), toolNames_js_1.ToolNames.LIST_ISSUE_COMMENTS);
144
146
  }
145
147
  catch (error) {
146
- return (0, formatToolResult_js_1.formatToolError)(error, 'list-issue-comments');
148
+ return (0, formatToolResult_js_1.formatToolError)(error, toolNames_js_1.ToolNames.LIST_ISSUE_COMMENTS);
147
149
  }
148
150
  });
149
- server.tool('create-issue-comment', '创建一个 Issue 评论', {
151
+ server.tool(toolNames_js_1.ToolNames.CREATE_ISSUE_COMMENT, toolDescriptions_js_1.toolDescriptions[toolNames_js_1.ToolNames.CREATE_ISSUE_COMMENT], {
150
152
  repo: zod_1.z.string().describe('仓库路径'),
151
153
  issueId: zod_1.z.number().describe('Issue ID'),
152
154
  body: zod_1.z.string().describe('评论内容')
153
155
  }, async ({ repo, issueId, body }) => {
154
156
  try {
155
157
  const comment = await (0, issue_js_1.createIssueComment)(repo, issueId, { body });
156
- return (0, formatToolResult_js_1.formatTextToolResult)(JSON.stringify(comment, null, 2), 'create-issue-comment');
158
+ return (0, formatToolResult_js_1.formatTextToolResult)(JSON.stringify(comment, null, 2), toolNames_js_1.ToolNames.CREATE_ISSUE_COMMENT);
157
159
  }
158
160
  catch (error) {
159
- return (0, formatToolResult_js_1.formatToolError)(error, 'create-issue-comment');
161
+ return (0, formatToolResult_js_1.formatToolError)(error, toolNames_js_1.ToolNames.CREATE_ISSUE_COMMENT);
160
162
  }
161
163
  });
162
- server.tool('update-issue-comment', '更新一个 Issue 评论', {
164
+ server.tool(toolNames_js_1.ToolNames.UPDATE_ISSUE_COMMENT, toolDescriptions_js_1.toolDescriptions[toolNames_js_1.ToolNames.UPDATE_ISSUE_COMMENT], {
163
165
  repo: zod_1.z.string().describe('仓库路径'),
164
166
  issueId: zod_1.z.number().describe('Issue ID'),
165
167
  commentId: zod_1.z.string().describe('评论 ID'),
@@ -167,73 +169,73 @@ function registerIssueTools(server) {
167
169
  }, async ({ repo, issueId, commentId, body }) => {
168
170
  try {
169
171
  const comment = await (0, issue_js_1.updateIssueComment)(repo, issueId, commentId, { body });
170
- return (0, formatToolResult_js_1.formatTextToolResult)(JSON.stringify(comment, null, 2), 'update-issue-comment');
172
+ return (0, formatToolResult_js_1.formatTextToolResult)(JSON.stringify(comment, null, 2), toolNames_js_1.ToolNames.UPDATE_ISSUE_COMMENT);
171
173
  }
172
174
  catch (error) {
173
- return (0, formatToolResult_js_1.formatToolError)(error, 'update-issue-comment');
175
+ return (0, formatToolResult_js_1.formatToolError)(error, toolNames_js_1.ToolNames.UPDATE_ISSUE_COMMENT);
174
176
  }
175
177
  });
176
- server.tool('list-issue-labels', '查询指定Issue的标签', {
178
+ server.tool(toolNames_js_1.ToolNames.LIST_ISSUE_LABELS, toolDescriptions_js_1.toolDescriptions[toolNames_js_1.ToolNames.LIST_ISSUE_LABELS], {
177
179
  repo: zod_1.z.string().describe('仓库路径'),
178
180
  issueId: zod_1.z.number().describe('Issue ID')
179
181
  }, async ({ repo, issueId }) => {
180
182
  try {
181
183
  const labels = await (0, issue_js_1.listIssueLabels)(repo, issueId);
182
- return (0, formatToolResult_js_1.formatTextToolResult)(JSON.stringify(labels, null, 2), 'list-issue-labels');
184
+ return (0, formatToolResult_js_1.formatTextToolResult)(JSON.stringify(labels, null, 2), toolNames_js_1.ToolNames.LIST_ISSUE_LABELS);
183
185
  }
184
186
  catch (error) {
185
- return (0, formatToolResult_js_1.formatToolError)(error, 'list-issue-labels');
187
+ return (0, formatToolResult_js_1.formatToolError)(error, toolNames_js_1.ToolNames.LIST_ISSUE_LABELS);
186
188
  }
187
189
  });
188
- server.tool('add-issue-labels', '为指定Issue添加标签', {
190
+ server.tool(toolNames_js_1.ToolNames.ADD_ISSUE_LABELS, toolDescriptions_js_1.toolDescriptions[toolNames_js_1.ToolNames.ADD_ISSUE_LABELS], {
189
191
  repo: zod_1.z.string().describe('仓库路径'),
190
192
  issueId: zod_1.z.number().describe('Issue ID'),
191
193
  labels: zod_1.z.array(zod_1.z.string()).describe('要添加的标签列表,每个标签需要从仓库标签列表中选择')
192
194
  }, async ({ repo, issueId, labels }) => {
193
195
  try {
194
196
  const result = await (0, issue_js_1.addIssueLabels)(repo, issueId, labels);
195
- return (0, formatToolResult_js_1.formatTextToolResult)(JSON.stringify(result, null, 2), 'add-issue-labels');
197
+ return (0, formatToolResult_js_1.formatTextToolResult)(JSON.stringify(result, null, 2), toolNames_js_1.ToolNames.ADD_ISSUE_LABELS);
196
198
  }
197
199
  catch (error) {
198
- return (0, formatToolResult_js_1.formatToolError)(error, 'add-issue-labels');
200
+ return (0, formatToolResult_js_1.formatToolError)(error, toolNames_js_1.ToolNames.ADD_ISSUE_LABELS);
199
201
  }
200
202
  });
201
- server.tool('set-issue-labels', '设置Issue的标签(替换所有现有标签)', {
203
+ server.tool(toolNames_js_1.ToolNames.SET_ISSUE_LABELS, toolDescriptions_js_1.toolDescriptions[toolNames_js_1.ToolNames.SET_ISSUE_LABELS], {
202
204
  repo: zod_1.z.string().describe('仓库路径'),
203
205
  issueId: zod_1.z.number().describe('Issue ID'),
204
206
  labels: zod_1.z.array(zod_1.z.string()).describe('新的标签列表(将替换所有现有标签),每个标签需要从仓库标签列表中选择')
205
207
  }, async ({ repo, issueId, labels }) => {
206
208
  try {
207
209
  const result = await (0, issue_js_1.setIssueLabels)(repo, issueId, labels);
208
- return (0, formatToolResult_js_1.formatTextToolResult)(JSON.stringify(result, null, 2), 'set-issue-labels');
210
+ return (0, formatToolResult_js_1.formatTextToolResult)(JSON.stringify(result, null, 2), toolNames_js_1.ToolNames.SET_ISSUE_LABELS);
209
211
  }
210
212
  catch (error) {
211
- return (0, formatToolResult_js_1.formatToolError)(error, 'set-issue-labels');
213
+ return (0, formatToolResult_js_1.formatToolError)(error, toolNames_js_1.ToolNames.SET_ISSUE_LABELS);
212
214
  }
213
215
  });
214
- server.tool('delete-issue-labels', '删除Issue的所有标签', {
216
+ server.tool(toolNames_js_1.ToolNames.CLEAR_ISSUE_LABELS, toolDescriptions_js_1.toolDescriptions[toolNames_js_1.ToolNames.CLEAR_ISSUE_LABELS], {
215
217
  repo: zod_1.z.string().describe('仓库路径'),
216
218
  issueId: zod_1.z.number().describe('Issue ID')
217
219
  }, async ({ repo, issueId }) => {
218
220
  try {
219
221
  await (0, issue_js_1.deleteIssueLabels)(repo, issueId);
220
- return (0, formatToolResult_js_1.formatTextToolResult)('All labels deleted', 'delete-issue-labels');
222
+ return (0, formatToolResult_js_1.formatTextToolResult)('All labels deleted', toolNames_js_1.ToolNames.CLEAR_ISSUE_LABELS);
221
223
  }
222
224
  catch (error) {
223
- return (0, formatToolResult_js_1.formatToolError)(error, 'delete-issue-labels');
225
+ return (0, formatToolResult_js_1.formatToolError)(error, toolNames_js_1.ToolNames.CLEAR_ISSUE_LABELS);
224
226
  }
225
227
  });
226
- server.tool('delete-issue-label', '删除Issue的指定标签', {
228
+ server.tool(toolNames_js_1.ToolNames.REMOVE_ISSUE_LABEL, toolDescriptions_js_1.toolDescriptions[toolNames_js_1.ToolNames.REMOVE_ISSUE_LABEL], {
227
229
  repo: zod_1.z.string().describe('仓库路径'),
228
230
  issueId: zod_1.z.number().describe('Issue ID'),
229
231
  labelName: zod_1.z.string().describe('要删除的标签名称')
230
232
  }, async ({ repo, issueId, labelName }) => {
231
233
  try {
232
234
  await (0, issue_js_1.deleteIssueLabel)(repo, issueId, labelName);
233
- return (0, formatToolResult_js_1.formatTextToolResult)(`${labelName} deleted`, 'delete-issue-label');
235
+ return (0, formatToolResult_js_1.formatTextToolResult)(`${labelName} deleted`, toolNames_js_1.ToolNames.REMOVE_ISSUE_LABEL);
234
236
  }
235
237
  catch (error) {
236
- return (0, formatToolResult_js_1.formatToolError)(error, 'delete-issue-label');
238
+ return (0, formatToolResult_js_1.formatToolError)(error, toolNames_js_1.ToolNames.REMOVE_ISSUE_LABEL);
237
239
  }
238
240
  });
239
241
  }
@@ -2,10 +2,12 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.default = registerPullTools;
4
4
  const zod_1 = require("zod");
5
+ const toolNames_js_1 = require("../constants/toolNames.js");
6
+ const toolDescriptions_js_1 = require("../constants/toolDescriptions.js");
5
7
  const pull_js_1 = require("../api/pull.js");
6
8
  const formatToolResult_js_1 = require("../helpers/formatToolResult.js");
7
9
  function registerPullTools(server) {
8
- server.tool('list-pulls', '查询仓库的Pull Requests', {
10
+ server.tool(toolNames_js_1.ToolNames.LIST_PULLS, toolDescriptions_js_1.toolDescriptions[toolNames_js_1.ToolNames.LIST_PULLS], {
9
11
  repo: zod_1.z.string().describe('仓库路径,格式为 {group}/{repo}'),
10
12
  state: zod_1.z
11
13
  .preprocess((val) => (val === null ? undefined : val), zod_1.z.enum(['open', 'closed', 'all']).optional())
@@ -21,25 +23,25 @@ function registerPullTools(server) {
21
23
  }, async ({ repo, ...params }) => {
22
24
  try {
23
25
  const pulls = await (0, pull_js_1.listPulls)(repo, params);
24
- return (0, formatToolResult_js_1.formatTextToolResult)(JSON.stringify(pulls, null, 2), 'list-pulls');
26
+ return (0, formatToolResult_js_1.formatTextToolResult)(JSON.stringify(pulls, null, 2), toolNames_js_1.ToolNames.LIST_PULLS);
25
27
  }
26
28
  catch (error) {
27
- return (0, formatToolResult_js_1.formatToolError)(error, 'list-pulls');
29
+ return (0, formatToolResult_js_1.formatToolError)(error, toolNames_js_1.ToolNames.LIST_PULLS);
28
30
  }
29
31
  });
30
- server.tool('get-pull', '获取单个Pull Request详情', {
32
+ server.tool(toolNames_js_1.ToolNames.GET_PULL, toolDescriptions_js_1.toolDescriptions[toolNames_js_1.ToolNames.GET_PULL], {
31
33
  repo: zod_1.z.string().describe('仓库路径,格式为 {group}/{repo}'),
32
34
  number: zod_1.z.number().describe('Pull Request编号')
33
35
  }, async ({ repo, number }) => {
34
36
  try {
35
37
  const pull = await (0, pull_js_1.getPull)(repo, number);
36
- return (0, formatToolResult_js_1.formatTextToolResult)(JSON.stringify(pull, null, 2), 'get-pull');
38
+ return (0, formatToolResult_js_1.formatTextToolResult)(JSON.stringify(pull, null, 2), toolNames_js_1.ToolNames.GET_PULL);
37
39
  }
38
40
  catch (error) {
39
- return (0, formatToolResult_js_1.formatToolError)(error, 'get-pull');
41
+ return (0, formatToolResult_js_1.formatToolError)(error, toolNames_js_1.ToolNames.GET_PULL);
40
42
  }
41
43
  });
42
- server.tool('create-pull', '创建Pull Request', {
44
+ server.tool(toolNames_js_1.ToolNames.CREATE_PULL, toolDescriptions_js_1.toolDescriptions[toolNames_js_1.ToolNames.CREATE_PULL], {
43
45
  repo: zod_1.z.string().describe('目标仓库路径,格式为 {group}/{repo}'),
44
46
  base: zod_1.z.string().describe('目标仓库目标分支'),
45
47
  head_repo: zod_1.z.string().optional().describe('来源仓库路径,格式为 {group}/{repo},不填则为目标仓库'),
@@ -49,13 +51,13 @@ function registerPullTools(server) {
49
51
  }, async ({ repo, ...params }) => {
50
52
  try {
51
53
  const pull = await (0, pull_js_1.createPull)(repo, params);
52
- return (0, formatToolResult_js_1.formatTextToolResult)(JSON.stringify(pull, null, 2), 'create-pull');
54
+ return (0, formatToolResult_js_1.formatTextToolResult)(JSON.stringify(pull, null, 2), toolNames_js_1.ToolNames.CREATE_PULL);
53
55
  }
54
56
  catch (error) {
55
- return (0, formatToolResult_js_1.formatToolError)(error, 'create-pull');
57
+ return (0, formatToolResult_js_1.formatToolError)(error, toolNames_js_1.ToolNames.CREATE_PULL);
56
58
  }
57
59
  });
58
- server.tool('update-pull', '更新Pull Request', {
60
+ server.tool(toolNames_js_1.ToolNames.UPDATE_PULL, toolDescriptions_js_1.toolDescriptions[toolNames_js_1.ToolNames.UPDATE_PULL], {
59
61
  repo: zod_1.z.string().describe('仓库路径,格式为 {group}/{repo}'),
60
62
  number: zod_1.z.number().describe('Pull Request编号'),
61
63
  title: zod_1.z.preprocess((val) => (val === null ? undefined : val), zod_1.z.string().optional()).describe('标题'),
@@ -66,13 +68,13 @@ function registerPullTools(server) {
66
68
  }, async ({ repo, number, ...params }) => {
67
69
  try {
68
70
  const pull = await (0, pull_js_1.updatePull)(repo, number, params);
69
- return (0, formatToolResult_js_1.formatTextToolResult)(JSON.stringify(pull, null, 2), 'update-pull');
71
+ return (0, formatToolResult_js_1.formatTextToolResult)(JSON.stringify(pull, null, 2), toolNames_js_1.ToolNames.UPDATE_PULL);
70
72
  }
71
73
  catch (error) {
72
- return (0, formatToolResult_js_1.formatToolError)(error, 'update-pull');
74
+ return (0, formatToolResult_js_1.formatToolError)(error, toolNames_js_1.ToolNames.UPDATE_PULL);
73
75
  }
74
76
  });
75
- server.tool('merge-pull', '合并Pull Request', {
77
+ server.tool(toolNames_js_1.ToolNames.MERGE_PULL, toolDescriptions_js_1.toolDescriptions[toolNames_js_1.ToolNames.MERGE_PULL], {
76
78
  repo: zod_1.z.string().describe('仓库路径,格式为 {group}/{repo}'),
77
79
  number: zod_1.z.number().describe('Pull Request编号'),
78
80
  merge_style: zod_1.z
@@ -85,13 +87,13 @@ function registerPullTools(server) {
85
87
  }, async ({ repo, number, ...params }) => {
86
88
  try {
87
89
  const result = await (0, pull_js_1.mergePull)(repo, number, params);
88
- return (0, formatToolResult_js_1.formatTextToolResult)(JSON.stringify(result, null, 2), 'merge-pull');
90
+ return (0, formatToolResult_js_1.formatTextToolResult)(JSON.stringify(result, null, 2), toolNames_js_1.ToolNames.MERGE_PULL);
89
91
  }
90
92
  catch (error) {
91
- return (0, formatToolResult_js_1.formatToolError)(error, 'merge-pull');
93
+ return (0, formatToolResult_js_1.formatToolError)(error, toolNames_js_1.ToolNames.MERGE_PULL);
92
94
  }
93
95
  });
94
- server.tool('list-pull-comments', '列出Pull Request的评论', {
96
+ server.tool(toolNames_js_1.ToolNames.LIST_PULL_COMMENTS, toolDescriptions_js_1.toolDescriptions[toolNames_js_1.ToolNames.LIST_PULL_COMMENTS], {
95
97
  repo: zod_1.z.string().describe('仓库路径,格式为 {group}/{repo}'),
96
98
  number: zod_1.z.number().describe('Pull Request编号'),
97
99
  page: zod_1.z.number().default(1).describe('页码'),
@@ -99,23 +101,23 @@ function registerPullTools(server) {
99
101
  }, async ({ repo, number, ...params }) => {
100
102
  try {
101
103
  const comments = await (0, pull_js_1.listPullComments)(repo, number, params);
102
- return (0, formatToolResult_js_1.formatTextToolResult)(JSON.stringify(comments, null, 2), 'list-pull-comments');
104
+ return (0, formatToolResult_js_1.formatTextToolResult)(JSON.stringify(comments, null, 2), toolNames_js_1.ToolNames.LIST_PULL_COMMENTS);
103
105
  }
104
106
  catch (error) {
105
- return (0, formatToolResult_js_1.formatToolError)(error, 'list-pull-comments');
107
+ return (0, formatToolResult_js_1.formatToolError)(error, toolNames_js_1.ToolNames.LIST_PULL_COMMENTS);
106
108
  }
107
109
  });
108
- server.tool('create-pull-comment', '创建Pull Request评论', {
110
+ server.tool(toolNames_js_1.ToolNames.CREATE_PULL_COMMENT, toolDescriptions_js_1.toolDescriptions[toolNames_js_1.ToolNames.CREATE_PULL_COMMENT], {
109
111
  repo: zod_1.z.string().describe('仓库路径,格式为 {group}/{repo}'),
110
112
  number: zod_1.z.number().describe('Pull Request编号'),
111
113
  body: zod_1.z.string().describe('评论内容')
112
114
  }, async ({ repo, number, body }) => {
113
115
  try {
114
116
  await (0, pull_js_1.createPullComment)(repo, number, { body });
115
- return (0, formatToolResult_js_1.formatTextToolResult)('Comment created', 'create-pull-comment');
117
+ return (0, formatToolResult_js_1.formatTextToolResult)('Comment created', toolNames_js_1.ToolNames.CREATE_PULL_COMMENT);
116
118
  }
117
119
  catch (error) {
118
- return (0, formatToolResult_js_1.formatToolError)(error, 'create-pull-comment');
120
+ return (0, formatToolResult_js_1.formatToolError)(error, toolNames_js_1.ToolNames.CREATE_PULL_COMMENT);
119
121
  }
120
122
  });
121
123
  }
@@ -2,11 +2,16 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.default = registerRepoTools;
4
4
  const zod_1 = require("zod");
5
+ const toolNames_js_1 = require("../constants/toolNames.js");
6
+ const toolDescriptions_js_1 = require("../constants/toolDescriptions.js");
5
7
  const repository_js_1 = require("../api/repository.js");
6
8
  const user_js_1 = require("../api/user.js");
7
9
  const formatToolResult_js_1 = require("../helpers/formatToolResult.js");
10
+ const formatRepoUrl_js_1 = require("../helpers/formatRepoUrl.js");
11
+ const checkRepoVisibility_js_1 = require("../helpers/checkRepoVisibility.js");
8
12
  function registerRepoTools(server) {
9
- server.tool('list-repositories', '获取当前用户拥有指定权限及其以上权限的仓库', {
13
+ server.tool(toolNames_js_1.ToolNames.LIST_REPOSITORIES, toolDescriptions_js_1.toolDescriptions[toolNames_js_1.ToolNames.LIST_REPOSITORIES], {
14
+ remote_url: zod_1.z.string().describe('远程仓库URL,需要先执行`git remote get-url origin`命令获取,获取不到传空字符串'),
10
15
  page: zod_1.z.number().default(1).describe('第几页,从1开始,默认值是1'),
11
16
  page_size: zod_1.z.number().default(10).describe('每页多少条数据,默认值为10'),
12
17
  search: zod_1.z.preprocess((val) => (val === null ? undefined : val), zod_1.z.string().optional()).describe('查询关键字'),
@@ -22,16 +27,20 @@ function registerRepoTools(server) {
22
27
  desc: zod_1.z
23
28
  .preprocess((val) => (val === null ? undefined : val), zod_1.z.boolean().optional())
24
29
  .describe('是否开启倒叙排序,默认值是false')
25
- }, async ({ page, page_size, search, filter_type, role, order_by, desc }) => {
30
+ }, async ({ remote_url, page, page_size, search, filter_type, role, order_by, desc }) => {
31
+ const isPublic = await (0, checkRepoVisibility_js_1.isRepoPublic)(remote_url);
32
+ if (isPublic) {
33
+ filter_type = 'public';
34
+ }
26
35
  try {
27
36
  const repos = await (0, repository_js_1.listRepositories)({ page, page_size, search, filter_type, role, order_by, desc });
28
- return (0, formatToolResult_js_1.formatTextToolResult)(JSON.stringify(repos, null, 2), 'list-repositories');
37
+ return (0, formatToolResult_js_1.formatTextToolResult)(JSON.stringify(repos, null, 2), toolNames_js_1.ToolNames.LIST_REPOSITORIES);
29
38
  }
30
39
  catch (error) {
31
- return (0, formatToolResult_js_1.formatToolError)(error, 'list-repositories');
40
+ return (0, formatToolResult_js_1.formatToolError)(error, toolNames_js_1.ToolNames.LIST_REPOSITORIES);
32
41
  }
33
42
  });
34
- server.tool('list-group-repositories', '获取分组里当前用户有权限的仓库', {
43
+ server.tool(toolNames_js_1.ToolNames.LIST_GROUP_REPOSITORIES, toolDescriptions_js_1.toolDescriptions[toolNames_js_1.ToolNames.LIST_GROUP_REPOSITORIES], {
35
44
  group: zod_1.z.string().describe('组织名称'),
36
45
  page: zod_1.z.number().default(1).describe('第几页,从1开始,默认值是1'),
37
46
  page_size: zod_1.z.number().default(10).describe('每页多少条数据,默认值为10'),
@@ -59,24 +68,24 @@ function registerRepoTools(server) {
59
68
  order_by,
60
69
  desc
61
70
  });
62
- return (0, formatToolResult_js_1.formatTextToolResult)(JSON.stringify(repos, null, 2), 'list-group-repositories');
71
+ return (0, formatToolResult_js_1.formatTextToolResult)(JSON.stringify(repos, null, 2), toolNames_js_1.ToolNames.LIST_GROUP_REPOSITORIES);
63
72
  }
64
73
  catch (error) {
65
- return (0, formatToolResult_js_1.formatToolError)(error, 'list-group-repositories');
74
+ return (0, formatToolResult_js_1.formatToolError)(error, toolNames_js_1.ToolNames.LIST_GROUP_REPOSITORIES);
66
75
  }
67
76
  });
68
- server.tool('get-repository', '获取指定仓库信息', {
77
+ server.tool(toolNames_js_1.ToolNames.GET_REPOSITORY, toolDescriptions_js_1.toolDescriptions[toolNames_js_1.ToolNames.GET_REPOSITORY], {
69
78
  repo: zod_1.z.string().describe('仓库路径')
70
79
  }, async ({ repo }) => {
71
80
  try {
72
81
  const repoInfo = await (0, repository_js_1.getRepository)(repo);
73
- return (0, formatToolResult_js_1.formatTextToolResult)(JSON.stringify(repoInfo, null, 2), 'get-repository');
82
+ return (0, formatToolResult_js_1.formatTextToolResult)(JSON.stringify(repoInfo, null, 2), toolNames_js_1.ToolNames.GET_REPOSITORY);
74
83
  }
75
84
  catch (error) {
76
- return (0, formatToolResult_js_1.formatToolError)(error, 'get-repository');
85
+ return (0, formatToolResult_js_1.formatToolError)(error, toolNames_js_1.ToolNames.GET_REPOSITORY);
77
86
  }
78
87
  });
79
- server.tool('create-repository', '创建仓库', {
88
+ server.tool(toolNames_js_1.ToolNames.CREATE_REPOSITORY, toolDescriptions_js_1.toolDescriptions[toolNames_js_1.ToolNames.CREATE_REPOSITORY], {
80
89
  group: zod_1.z.preprocess((val) => (val === null ? undefined : val), zod_1.z.string().optional()).describe('仓库所属分组'),
81
90
  name: zod_1.z.string().describe('仓库名称'),
82
91
  description: zod_1.z.preprocess((val) => (val === null ? undefined : val), zod_1.z.string().optional()).describe('仓库描述'),
@@ -92,40 +101,26 @@ function registerRepoTools(server) {
92
101
  }
93
102
  try {
94
103
  const data = await (0, repository_js_1.createRepository)(repoGroup, { name, description, license, visibility });
95
- return (0, formatToolResult_js_1.formatTextToolResult)(JSON.stringify(data, null, 2), 'create-repository');
104
+ return (0, formatToolResult_js_1.formatTextToolResult)(JSON.stringify(data, null, 2), toolNames_js_1.ToolNames.CREATE_REPOSITORY);
96
105
  }
97
106
  catch (error) {
98
- return (0, formatToolResult_js_1.formatToolError)(error, 'create-repository');
107
+ return (0, formatToolResult_js_1.formatToolError)(error, toolNames_js_1.ToolNames.CREATE_REPOSITORY);
99
108
  }
100
109
  });
101
- server.tool('get-current-repo', '获取当前仓库对应的CNB仓库信息', {
110
+ server.tool(toolNames_js_1.ToolNames.GET_CURRENT_REPOSITORY, toolDescriptions_js_1.toolDescriptions[toolNames_js_1.ToolNames.GET_CURRENT_REPOSITORY], {
102
111
  remote_url: zod_1.z.string().describe('远程仓库URL, 需要先执行`git remote get-url origin`命令获取')
103
112
  }, async ({ remote_url }) => {
104
113
  try {
105
- let repoPath = '';
106
- if (remote_url.startsWith('git@')) {
107
- // SSH 格式: git@example.com:group/repo.git
108
- const match = remote_url.match(/git@[^:]+:(.+?)(?:\.git)?$/);
109
- if (match) {
110
- repoPath = match[1];
111
- }
112
- }
113
- else if (remote_url.startsWith('http')) {
114
- // HTTPS 格式: https://example.com/group/repo.git
115
- const match = remote_url.match(/https?:\/\/[^/]+\/(.+?)(?:\.git)?$/);
116
- if (match) {
117
- repoPath = match[1];
118
- }
119
- }
114
+ const repoPath = (0, formatRepoUrl_js_1.getRepoPath)(remote_url);
120
115
  if (!repoPath) {
121
- return (0, formatToolResult_js_1.formatToolError)(`无法从远程仓库URL解析出仓库路径: ${remote_url}`, 'get-current-repo');
116
+ return (0, formatToolResult_js_1.formatToolError)(`无法从远程仓库URL解析出仓库路径: ${remote_url}`, toolNames_js_1.ToolNames.GET_CURRENT_REPOSITORY);
122
117
  }
123
118
  // 获取仓库信息
124
119
  const data = await (0, repository_js_1.getRepository)(repoPath);
125
- return (0, formatToolResult_js_1.formatTextToolResult)(JSON.stringify(data, null, 2), 'get-current-repo');
120
+ return (0, formatToolResult_js_1.formatTextToolResult)(JSON.stringify(data, null, 2), toolNames_js_1.ToolNames.GET_CURRENT_REPOSITORY);
126
121
  }
127
122
  catch (error) {
128
- return (0, formatToolResult_js_1.formatToolError)(error, 'get-current-repo');
123
+ return (0, formatToolResult_js_1.formatToolError)(error, toolNames_js_1.ToolNames.GET_CURRENT_REPOSITORY);
129
124
  }
130
125
  });
131
126
  }
@@ -2,10 +2,12 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.default = registerWorkspaceTools;
4
4
  const zod_1 = require("zod");
5
+ const toolNames_js_1 = require("../constants/toolNames.js");
6
+ const toolDescriptions_js_1 = require("../constants/toolDescriptions.js");
5
7
  const workspace_js_1 = require("../api/workspace.js");
6
8
  const formatToolResult_js_1 = require("../helpers/formatToolResult.js");
7
9
  function registerWorkspaceTools(server) {
8
- server.tool('list-workspace', '获取我的云原生开发环境列表', {
10
+ server.tool(toolNames_js_1.ToolNames.LIST_WORKSPACES, toolDescriptions_js_1.toolDescriptions[toolNames_js_1.ToolNames.LIST_WORKSPACES], {
9
11
  branch: zod_1.z
10
12
  .preprocess((val) => (val === null ? undefined : val), zod_1.z.string().optional())
11
13
  .describe('分支名,例如:main'),
@@ -38,23 +40,23 @@ function registerWorkspaceTools(server) {
38
40
  slug,
39
41
  status
40
42
  });
41
- return (0, formatToolResult_js_1.formatTextToolResult)(JSON.stringify(workspaces, null, 2), 'list-workspace');
43
+ return (0, formatToolResult_js_1.formatTextToolResult)(JSON.stringify(workspaces, null, 2), toolNames_js_1.ToolNames.LIST_WORKSPACES);
42
44
  }
43
45
  catch (error) {
44
- return (0, formatToolResult_js_1.formatToolError)(error, 'list-workspace');
46
+ return (0, formatToolResult_js_1.formatToolError)(error, toolNames_js_1.ToolNames.LIST_WORKSPACES);
45
47
  }
46
48
  });
47
- server.tool('delete-workspace', '删除我的云原生开发环境', {
49
+ server.tool(toolNames_js_1.ToolNames.DELETE_WORKSPACE, toolDescriptions_js_1.toolDescriptions[toolNames_js_1.ToolNames.DELETE_WORKSPACE], {
48
50
  pipelineId: zod_1.z.string().describe('开发环境 ID')
49
51
  }, async ({ pipelineId }) => {
50
52
  try {
51
53
  const result = await (0, workspace_js_1.deleteWorkspace)({
52
54
  pipelineId
53
55
  });
54
- return (0, formatToolResult_js_1.formatTextToolResult)(JSON.stringify(result, null, 2), 'delete-workspace');
56
+ return (0, formatToolResult_js_1.formatTextToolResult)(JSON.stringify(result, null, 2), toolNames_js_1.ToolNames.DELETE_WORKSPACE);
55
57
  }
56
58
  catch (error) {
57
- return (0, formatToolResult_js_1.formatToolError)(error, 'delete-workspace');
59
+ return (0, formatToolResult_js_1.formatToolError)(error, toolNames_js_1.ToolNames.DELETE_WORKSPACE);
58
60
  }
59
61
  });
60
62
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@cnbcool/mcp-server",
3
3
  "description": "CNB MCP Server. A comprehensive MCP server that provides seamless integration to the CNB's API(https://cnb.cool), offering a wide range of tools for repository management, pipelines operations and collaboration features",
4
- "version": "0.4.3",
4
+ "version": "0.4.5",
5
5
  "main": "./dist/stdio.js",
6
6
  "bin": {
7
7
  "cnb-mcp-stdio": "dist/stdio.js",
@@ -46,21 +46,21 @@
46
46
  "zod": "3.24.3"
47
47
  },
48
48
  "devDependencies": {
49
- "@commitlint/cli": "19.8.0",
50
- "@commitlint/config-conventional": "19.8.0",
51
- "@eslint/js": "9.24.0",
49
+ "@commitlint/cli": "19.8.1",
50
+ "@commitlint/config-conventional": "19.8.1",
51
+ "@eslint/js": "9.33.0",
52
52
  "@modelcontextprotocol/inspector": "^0.16.2",
53
53
  "@types/express": "5.0.1",
54
- "@types/node": "22.13.9",
55
- "eslint": "^9.32.0",
56
- "eslint-config-prettier": "10.1.2",
57
- "eslint-plugin-prettier": "5.2.6",
58
- "globals": "16.0.0",
54
+ "@types/node": "^18.19.123",
55
+ "eslint": "9.33.0",
56
+ "eslint-config-prettier": "10.1.8",
57
+ "eslint-plugin-prettier": "5.5.4",
58
+ "globals": "16.3.0",
59
59
  "husky": "9.1.7",
60
- "lint-staged": "15.5.1",
61
- "prettier": "3.5.3",
62
- "typescript": "5.8.2",
63
- "typescript-eslint": "8.30.1"
60
+ "lint-staged": "15.5.2",
61
+ "prettier": "3.6.2",
62
+ "typescript": "5.9.2",
63
+ "typescript-eslint": "8.40.0"
64
64
  },
65
65
  "lint-staged": {
66
66
  "**/*": [