@cnbcool/mcp-server
Version:
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
132 lines (131 loc) • 7.5 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = registerRepoTools;
const zod_1 = require("zod");
const repository_js_1 = require("../api/repository.js");
const user_js_1 = require("../api/user.js");
const formatToolResult_js_1 = require("../helpers/formatToolResult.js");
function registerRepoTools(server) {
server.tool('list-repositories', '获取当前用户拥有指定权限及其以上权限的仓库', {
page: zod_1.z.number().default(1).describe('第几页,从1开始,默认值是1'),
page_size: zod_1.z.number().default(10).describe('每页多少条数据,默认值为10'),
search: zod_1.z.preprocess((val) => (val === null ? undefined : val), zod_1.z.string().optional()).describe('查询关键字'),
filter_type: zod_1.z
.preprocess((val) => (val === null ? undefined : val), zod_1.z.enum(['private', 'public', 'encrypted']).optional())
.describe('仓库类型,为空表示所有仓库类型,默认值为空'),
role: zod_1.z
.preprocess((val) => (val === null ? undefined : val), zod_1.z.enum(['Reporter', 'Developer', 'Master', 'Owner']).optional())
.describe('最小仓库权限,当用户未指定角色时,需要主动传入Reporter'),
order_by: zod_1.z
.preprocess((val) => (val === null ? undefined : val), zod_1.z.enum(['created_at', 'last_updated_at', 'stars']).optional())
.describe('排序类型,默认值是last_updated_at'),
desc: zod_1.z
.preprocess((val) => (val === null ? undefined : val), zod_1.z.boolean().optional())
.describe('是否开启倒叙排序,默认值是false')
}, async ({ page, page_size, search, filter_type, role, order_by, desc }) => {
try {
const repos = await (0, repository_js_1.listRepositories)({ page, page_size, search, filter_type, role, order_by, desc });
return (0, formatToolResult_js_1.formatTextToolResult)(JSON.stringify(repos, null, 2), 'list-repositories');
}
catch (error) {
return (0, formatToolResult_js_1.formatToolError)(error, 'list-repositories');
}
});
server.tool('list-group-repositories', '获取分组里当前用户有权限的仓库', {
group: zod_1.z.string().describe('组织名称'),
page: zod_1.z.number().default(1).describe('第几页,从1开始,默认值是1'),
page_size: zod_1.z.number().default(10).describe('每页多少条数据,默认值为10'),
search: zod_1.z.preprocess((val) => (val === null ? undefined : val), zod_1.z.string().optional()).describe('仓库关键字'),
filter_type: zod_1.z
.preprocess((val) => (val === null ? undefined : val), zod_1.z.enum(['private', 'public', 'encrypted']).optional())
.describe('仓库类型'),
descendant: zod_1.z
.preprocess((val) => (val === null ? undefined : val), zod_1.z.enum(['all', 'sub', 'grand']).optional())
.describe('查全部、直接属于当前组织的仓库、子组织的仓库'),
order_by: zod_1.z
.preprocess((val) => (val === null ? undefined : val), zod_1.z.enum(['created_at', 'last_updated_at', 'stars', 'slug_path']).optional())
.describe('排序类型'),
desc: zod_1.z
.preprocess((val) => (val === null ? undefined : val), zod_1.z.boolean().optional())
.describe('是否开启倒叙排序,默认值是false')
}, async ({ group, page, page_size, search, filter_type, descendant, order_by, desc }) => {
try {
const repos = await (0, repository_js_1.listGroupRepositories)(group, {
page,
page_size,
search,
filter_type,
descendant,
order_by,
desc
});
return (0, formatToolResult_js_1.formatTextToolResult)(JSON.stringify(repos, null, 2), 'list-group-repositories');
}
catch (error) {
return (0, formatToolResult_js_1.formatToolError)(error, 'list-group-repositories');
}
});
server.tool('get-repository', '获取指定仓库信息', {
repo: zod_1.z.string().describe('仓库路径')
}, async ({ repo }) => {
try {
const repoInfo = await (0, repository_js_1.getRepository)(repo);
return (0, formatToolResult_js_1.formatTextToolResult)(JSON.stringify(repoInfo, null, 2), 'get-repository');
}
catch (error) {
return (0, formatToolResult_js_1.formatToolError)(error, 'get-repository');
}
});
server.tool('create-repository', '创建仓库', {
group: zod_1.z.preprocess((val) => (val === null ? undefined : val), zod_1.z.string().optional()).describe('仓库所属分组'),
name: zod_1.z.string().describe('仓库名称'),
description: zod_1.z.preprocess((val) => (val === null ? undefined : val), zod_1.z.string().optional()).describe('仓库描述'),
license: zod_1.z.preprocess((val) => (val === null ? undefined : val), zod_1.z.string().optional()).describe('仓库许可'),
visibility: zod_1.z
.preprocess((val) => (val === null ? undefined : val), zod_1.z.enum(['public', 'private', 'secret']).default('public'))
.describe('仓库可见性')
}, async ({ group, name, description, license, visibility }) => {
let repoGroup = group;
if (!repoGroup) {
const { username = '' } = await (0, user_js_1.getUser)();
repoGroup = username;
}
try {
const data = await (0, repository_js_1.createRepository)(repoGroup, { name, description, license, visibility });
return (0, formatToolResult_js_1.formatTextToolResult)(JSON.stringify(data, null, 2), 'create-repository');
}
catch (error) {
return (0, formatToolResult_js_1.formatToolError)(error, 'create-repository');
}
});
server.tool('get-current-repo', '获取当前仓库对应的CNB仓库信息', {
remote_url: zod_1.z.string().describe('远程仓库URL, 需要先执行`git remote get-url origin`命令获取')
}, async ({ remote_url }) => {
try {
let repoPath = '';
if (remote_url.startsWith('git@')) {
// SSH 格式: git@example.com:group/repo.git
const match = remote_url.match(/git@[^:]+:(.+?)(?:\.git)?$/);
if (match) {
repoPath = match[1];
}
}
else if (remote_url.startsWith('http')) {
// HTTPS 格式: https://example.com/group/repo.git
const match = remote_url.match(/https?:\/\/[^/]+\/(.+?)(?:\.git)?$/);
if (match) {
repoPath = match[1];
}
}
if (!repoPath) {
return (0, formatToolResult_js_1.formatToolError)(`无法从远程仓库URL解析出仓库路径: ${remote_url}`, 'get-current-repo');
}
// 获取仓库信息
const data = await (0, repository_js_1.getRepository)(repoPath);
return (0, formatToolResult_js_1.formatTextToolResult)(JSON.stringify(data, null, 2), 'get-current-repo');
}
catch (error) {
return (0, formatToolResult_js_1.formatToolError)(error, 'get-current-repo');
}
});
}