Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit c9a174e

Browse files
committed
feat: add Gitee repository operation tool, including create and fork functions
Signed-off-by: 诺墨 <[email protected]>
1 parent 8ec4d7e commit c9a174e

File tree

3 files changed

+204
-0
lines changed

3 files changed

+204
-0
lines changed

common/types.ts

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,89 @@ export const GiteeUserSchema = z.object({
3434
email: z.string().email().nullable().optional(),
3535
});
3636

37+
// Declare a type and then define it to avoid circular references.
38+
export type GiteeRepositorySchemaType = z.ZodObject<any>;
39+
export let GiteeRepositorySchema: GiteeRepositorySchemaType;
40+
41+
GiteeRepositorySchema = z.object({
42+
id: z.number(),
43+
full_name: z.string(),
44+
human_name: z.string(),
45+
url: z.string().url(),
46+
namespace: z.object({
47+
id: z.number(),
48+
name: z.string(),
49+
path: z.string(),
50+
type: z.string(),
51+
}),
52+
path: z.string(),
53+
name: z.string(),
54+
owner: GiteeUserSchema,
55+
assigner: GiteeUserSchema.nullable(),
56+
description: z.string().nullable(),
57+
private: z.boolean(),
58+
public: z.boolean(),
59+
internal: z.boolean(),
60+
fork: z.boolean(),
61+
html_url: z.string().url(),
62+
ssh_url: z.string(),
63+
forks_url: z.string().url().optional(),
64+
keys_url: z.string().url().optional(),
65+
collaborators_url: z.string().url().optional(),
66+
hooks_url: z.string().url().optional(),
67+
branches_url: z.string().url().optional(),
68+
tags_url: z.string().url().optional(),
69+
blobs_url: z.string().url().optional(),
70+
stargazers_url: z.string().url().optional(),
71+
contributors_url: z.string().url().optional(),
72+
commits_url: z.string().url().optional(),
73+
comments_url: z.string().url().optional(),
74+
issue_comment_url: z.string().url().optional(),
75+
issues_url: z.string().url().optional(),
76+
pulls_url: z.string().url().optional(),
77+
milestones_url: z.string().url().optional(),
78+
notifications_url: z.string().url().optional(),
79+
labels_url: z.string().url().optional(),
80+
releases_url: z.string().url().optional(),
81+
recommend: z.boolean().optional(),
82+
gvp: z.boolean().optional(),
83+
homepage: z.string().nullable().optional(),
84+
language: z.string().nullable().optional(),
85+
forks_count: z.number().optional(),
86+
stargazers_count: z.number().optional(),
87+
watchers_count: z.number().optional(),
88+
default_branch: z.string().nullable().optional(),
89+
open_issues_count: z.number().optional(),
90+
has_issues: z.boolean().optional(),
91+
has_wiki: z.boolean().optional(),
92+
issue_comment: z.boolean().nullable().optional(),
93+
can_comment: z.boolean().optional(),
94+
pull_requests_enabled: z.boolean().optional(),
95+
has_page: z.boolean().optional(),
96+
license: z.string().nullable().optional(),
97+
outsourced: z.boolean().optional(),
98+
project_creator: z.string().optional(),
99+
members: z.array(z.string()).optional(),
100+
pushed_at: z.string().nullable().optional(),
101+
created_at: z.string().optional(),
102+
updated_at: z.string().optional(),
103+
parent: z.lazy(() => GiteeRepositorySchema).nullable().optional(),
104+
paas: z.string().nullable().optional(),
105+
assignees_number: z.number().optional(),
106+
testers_number: z.number().optional(),
107+
assignee: z.union([GiteeUserSchema, z.array(z.any()), z.null()]).optional(),
108+
enterprise: z.object({
109+
id: z.number(),
110+
name: z.string(),
111+
url: z.string().url(),
112+
}).nullable().optional(),
113+
permission: z.object({
114+
pull: z.boolean(),
115+
push: z.boolean(),
116+
admin: z.boolean(),
117+
}).optional(),
118+
});
119+
37120
// Type Exports
38121
export type GiteeUser = z.infer<typeof GiteeUserSchema>;
122+
export type GiteeRepository = z.infer<typeof GiteeRepositorySchema>;

index.ts

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { MCPServer } from "./common/server.js";
33
import { VERSION } from "./common/version.js";
44

55
// 导入操作模块
6+
import * as repoOperations from "./operations/repos.js";
67
import * as userOperations from "./operations/users.js";
78
import { z } from 'zod';
89

@@ -13,6 +14,56 @@ export function createGiteeMCPServer() {
1314
version: VERSION,
1415
});
1516

17+
// 注册仓库操作工具
18+
server.registerTool({
19+
name: "create_repository",
20+
description: "创建 Gitee 仓库",
21+
schema: repoOperations.CreateRepositorySchema,
22+
handler: async (params: any) => {
23+
try {
24+
// 确保 private 参数是布尔值
25+
if (params.private !== undefined) {
26+
if (typeof params.private === 'string') {
27+
// 将字符串转换为布尔值
28+
params.private = params.private.toLowerCase() === 'true';
29+
}
30+
}
31+
32+
// 处理其他可能的布尔值字段
33+
['has_issues', 'has_wiki', 'auto_init'].forEach(field => {
34+
if (params[field] !== undefined && typeof params[field] === 'string') {
35+
params[field] = params[field].toLowerCase() === 'true';
36+
}
37+
});
38+
39+
return await repoOperations.createRepository(params);
40+
} catch (error) {
41+
console.error('创建仓库失败:', error);
42+
throw error;
43+
}
44+
},
45+
});
46+
47+
server.registerTool({
48+
name: "fork_repository",
49+
description: "Fork Gitee 仓库",
50+
schema: repoOperations.ForkRepositorySchema,
51+
handler: async (params: any) => {
52+
const { owner, repo, organization } = params;
53+
return await repoOperations.forkRepository(owner, repo, organization);
54+
},
55+
});
56+
57+
server.registerTool({
58+
name: "search_repositories",
59+
description: "搜索 Gitee 仓库",
60+
schema: repoOperations.SearchRepositoriesSchema,
61+
handler: async (params: any) => {
62+
const { query, page, perPage } = params;
63+
return await repoOperations.searchRepositories(query, page, perPage);
64+
},
65+
});
66+
1667
// 注册用户操作工具
1768
server.registerTool({
1869
name: "get_user",

operations/repos.ts

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import { z } from "zod";
2+
import { giteeRequest, validateOwnerName, validateRepositoryName } from "../common/utils.js";
3+
import { GiteeRepositorySchema } from "../common/types.js";
4+
5+
// Schema 定义
6+
export const CreateRepositorySchema = z.object({
7+
name: z.string().describe("仓库名称"),
8+
description: z.string().optional().describe("仓库描述"),
9+
homepage: z.string().optional().describe("主页地址"),
10+
private: z.boolean().default(false).optional().describe("是否私有"),
11+
has_issues: z.boolean().default(true).optional().describe("是否开启 Issue 功能"),
12+
has_wiki: z.boolean().default(true).optional().describe("是否开启 Wiki 功能"),
13+
auto_init: z.boolean().default(false).optional().describe("是否自动初始化仓库"),
14+
gitignore_template: z.string().optional().describe("Git Ignore 模板"),
15+
license_template: z.string().optional().describe("License 模板"),
16+
path: z.string().optional().describe("仓库路径"),
17+
});
18+
19+
export const ForkRepositorySchema = z.object({
20+
owner: z.string().describe("仓库所属空间地址 (企业、组织或个人的地址 path)"),
21+
repo: z.string().describe("仓库路径 (path)"),
22+
organization: z.string().optional().describe("组织空间地址,不传默认为个人"),
23+
});
24+
25+
// 类型导出
26+
export type CreateRepositoryOptions = z.infer<typeof CreateRepositorySchema>;
27+
export type ForkRepositoryOptions = z.infer<typeof ForkRepositorySchema>;
28+
29+
// 函数实现
30+
export async function createRepository(options: CreateRepositoryOptions) {
31+
try {
32+
console.log('创建仓库参数:', JSON.stringify(options));
33+
const url = "https://gitee.com/api/v5/user/repos";
34+
const response = await giteeRequest(url, "POST", options);
35+
console.log('创建仓库响应:', JSON.stringify(response));
36+
37+
// 尝试解析响应
38+
try {
39+
return GiteeRepositorySchema.parse(response);
40+
} catch (parseError) {
41+
console.error('解析仓库响应失败:', parseError);
42+
// 返回原始响应,避免解析错误
43+
return response;
44+
}
45+
} catch (error) {
46+
console.error('创建仓库请求失败:', error);
47+
throw error;
48+
}
49+
}
50+
51+
export async function forkRepository(
52+
owner: string,
53+
repo: string,
54+
organization?: string
55+
) {
56+
owner = validateOwnerName(owner);
57+
repo = validateRepositoryName(repo);
58+
59+
const url = `https://gitee.com/api/v5/repos/${owner}/${repo}/forks`;
60+
const body: Record<string, string> = {};
61+
62+
if (organization) {
63+
body.organization = validateOwnerName(organization);
64+
}
65+
66+
const response = await giteeRequest(url, "POST", body);
67+
68+
return GiteeRepositorySchema.parse(response);
69+
}

0 commit comments

Comments
 (0)