@zereight/mcp-gitlab 1.0.15 → 1.0.17
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/build/index.js +194 -6
- package/build/schemas.js +110 -2
- package/package.json +1 -1
package/build/index.js
CHANGED
|
@@ -9,7 +9,7 @@ import { fileURLToPath } from "url";
|
|
|
9
9
|
import { dirname } from "path";
|
|
10
10
|
import fs from "fs";
|
|
11
11
|
import path from "path";
|
|
12
|
-
import { GitLabForkSchema, GitLabReferenceSchema, GitLabRepositorySchema, GitLabIssueSchema, GitLabMergeRequestSchema, GitLabContentSchema, GitLabCreateUpdateFileResponseSchema, GitLabSearchResponseSchema, GitLabTreeSchema, GitLabCommitSchema, CreateOrUpdateFileSchema, SearchRepositoriesSchema, CreateRepositorySchema, GetFileContentsSchema, PushFilesSchema, CreateIssueSchema, CreateMergeRequestSchema, ForkRepositorySchema, CreateBranchSchema, GitLabMergeRequestDiffSchema, GetMergeRequestSchema, GetMergeRequestDiffsSchema, UpdateMergeRequestSchema, CreateNoteSchema, } from "./schemas.js";
|
|
12
|
+
import { GitLabForkSchema, GitLabReferenceSchema, GitLabRepositorySchema, GitLabIssueSchema, GitLabMergeRequestSchema, GitLabContentSchema, GitLabCreateUpdateFileResponseSchema, GitLabSearchResponseSchema, GitLabTreeSchema, GitLabCommitSchema, GitLabNamespaceSchema, GitLabNamespaceExistsResponseSchema, CreateOrUpdateFileSchema, SearchRepositoriesSchema, CreateRepositorySchema, GetFileContentsSchema, PushFilesSchema, CreateIssueSchema, CreateMergeRequestSchema, ForkRepositorySchema, CreateBranchSchema, GitLabMergeRequestDiffSchema, GetMergeRequestSchema, GetMergeRequestDiffsSchema, UpdateMergeRequestSchema, ListNamespacesSchema, GetNamespaceSchema, VerifyNamespaceSchema, GetProjectSchema, ListProjectsSchema, CreateNoteSchema, } from "./schemas.js";
|
|
13
13
|
/**
|
|
14
14
|
* Read version from package.json
|
|
15
15
|
*/
|
|
@@ -560,6 +560,121 @@ noteableIid, body) {
|
|
|
560
560
|
}
|
|
561
561
|
return await response.json();
|
|
562
562
|
}
|
|
563
|
+
/**
|
|
564
|
+
* List all namespaces
|
|
565
|
+
* 사용 가능한 모든 네임스페이스 목록 조회
|
|
566
|
+
*
|
|
567
|
+
* @param {Object} options - Options for listing namespaces
|
|
568
|
+
* @param {string} [options.search] - Search query to filter namespaces
|
|
569
|
+
* @param {boolean} [options.owned_only] - Only return namespaces owned by the authenticated user
|
|
570
|
+
* @param {boolean} [options.top_level_only] - Only return top-level namespaces
|
|
571
|
+
* @returns {Promise<GitLabNamespace[]>} List of namespaces
|
|
572
|
+
*/
|
|
573
|
+
async function listNamespaces(options) {
|
|
574
|
+
const url = new URL(`${GITLAB_API_URL}/namespaces`);
|
|
575
|
+
if (options.search) {
|
|
576
|
+
url.searchParams.append("search", options.search);
|
|
577
|
+
}
|
|
578
|
+
if (options.owned_only) {
|
|
579
|
+
url.searchParams.append("owned_only", "true");
|
|
580
|
+
}
|
|
581
|
+
if (options.top_level_only) {
|
|
582
|
+
url.searchParams.append("top_level_only", "true");
|
|
583
|
+
}
|
|
584
|
+
const response = await fetch(url.toString(), {
|
|
585
|
+
headers: DEFAULT_HEADERS,
|
|
586
|
+
});
|
|
587
|
+
await handleGitLabError(response);
|
|
588
|
+
const data = await response.json();
|
|
589
|
+
return z.array(GitLabNamespaceSchema).parse(data);
|
|
590
|
+
}
|
|
591
|
+
/**
|
|
592
|
+
* Get details on a namespace
|
|
593
|
+
* 네임스페이스 상세 정보 조회
|
|
594
|
+
*
|
|
595
|
+
* @param {string} id - The ID or URL-encoded path of the namespace
|
|
596
|
+
* @returns {Promise<GitLabNamespace>} The namespace details
|
|
597
|
+
*/
|
|
598
|
+
async function getNamespace(id) {
|
|
599
|
+
const url = new URL(`${GITLAB_API_URL}/namespaces/${encodeURIComponent(id)}`);
|
|
600
|
+
const response = await fetch(url.toString(), {
|
|
601
|
+
headers: DEFAULT_HEADERS,
|
|
602
|
+
});
|
|
603
|
+
await handleGitLabError(response);
|
|
604
|
+
const data = await response.json();
|
|
605
|
+
return GitLabNamespaceSchema.parse(data);
|
|
606
|
+
}
|
|
607
|
+
/**
|
|
608
|
+
* Verify if a namespace exists
|
|
609
|
+
* 네임스페이스 존재 여부 확인
|
|
610
|
+
*
|
|
611
|
+
* @param {string} namespacePath - The path of the namespace to check
|
|
612
|
+
* @param {number} [parentId] - The ID of the parent namespace
|
|
613
|
+
* @returns {Promise<GitLabNamespaceExistsResponse>} The verification result
|
|
614
|
+
*/
|
|
615
|
+
async function verifyNamespaceExistence(namespacePath, parentId) {
|
|
616
|
+
const url = new URL(`${GITLAB_API_URL}/namespaces/${encodeURIComponent(namespacePath)}/exists`);
|
|
617
|
+
if (parentId) {
|
|
618
|
+
url.searchParams.append("parent_id", parentId.toString());
|
|
619
|
+
}
|
|
620
|
+
const response = await fetch(url.toString(), {
|
|
621
|
+
headers: DEFAULT_HEADERS,
|
|
622
|
+
});
|
|
623
|
+
await handleGitLabError(response);
|
|
624
|
+
const data = await response.json();
|
|
625
|
+
return GitLabNamespaceExistsResponseSchema.parse(data);
|
|
626
|
+
}
|
|
627
|
+
/**
|
|
628
|
+
* Get a single project
|
|
629
|
+
* 단일 프로젝트 조회
|
|
630
|
+
*
|
|
631
|
+
* @param {string} projectId - The ID or URL-encoded path of the project
|
|
632
|
+
* @param {Object} options - Options for getting project details
|
|
633
|
+
* @param {boolean} [options.license] - Include project license data
|
|
634
|
+
* @param {boolean} [options.statistics] - Include project statistics
|
|
635
|
+
* @param {boolean} [options.with_custom_attributes] - Include custom attributes in response
|
|
636
|
+
* @returns {Promise<GitLabProject>} Project details
|
|
637
|
+
*/
|
|
638
|
+
async function getProject(projectId, options = {}) {
|
|
639
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}`);
|
|
640
|
+
if (options.license) {
|
|
641
|
+
url.searchParams.append("license", "true");
|
|
642
|
+
}
|
|
643
|
+
if (options.statistics) {
|
|
644
|
+
url.searchParams.append("statistics", "true");
|
|
645
|
+
}
|
|
646
|
+
if (options.with_custom_attributes) {
|
|
647
|
+
url.searchParams.append("with_custom_attributes", "true");
|
|
648
|
+
}
|
|
649
|
+
const response = await fetch(url.toString(), {
|
|
650
|
+
headers: DEFAULT_HEADERS,
|
|
651
|
+
});
|
|
652
|
+
await handleGitLabError(response);
|
|
653
|
+
const data = await response.json();
|
|
654
|
+
return GitLabRepositorySchema.parse(data);
|
|
655
|
+
}
|
|
656
|
+
/**
|
|
657
|
+
* List projects
|
|
658
|
+
* 프로젝트 목록 조회
|
|
659
|
+
*
|
|
660
|
+
* @param {Object} options - Options for listing projects
|
|
661
|
+
* @returns {Promise<GitLabProject[]>} List of projects
|
|
662
|
+
*/
|
|
663
|
+
async function listProjects(options = {}) {
|
|
664
|
+
const url = new URL(`${GITLAB_API_URL}/projects`);
|
|
665
|
+
// Add all the query parameters from options
|
|
666
|
+
Object.entries(options).forEach(([key, value]) => {
|
|
667
|
+
if (value !== undefined) {
|
|
668
|
+
url.searchParams.append(key, value.toString());
|
|
669
|
+
}
|
|
670
|
+
});
|
|
671
|
+
const response = await fetch(url.toString(), {
|
|
672
|
+
headers: DEFAULT_HEADERS,
|
|
673
|
+
});
|
|
674
|
+
await handleGitLabError(response);
|
|
675
|
+
const data = await response.json();
|
|
676
|
+
return z.array(GitLabRepositorySchema).parse(data);
|
|
677
|
+
}
|
|
563
678
|
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
564
679
|
return {
|
|
565
680
|
tools: [
|
|
@@ -628,6 +743,31 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
628
743
|
description: "Create a new note (comment) to an issue or merge request",
|
|
629
744
|
inputSchema: zodToJsonSchema(CreateNoteSchema),
|
|
630
745
|
},
|
|
746
|
+
{
|
|
747
|
+
name: "list_namespaces",
|
|
748
|
+
description: "List all namespaces available to the current user",
|
|
749
|
+
inputSchema: zodToJsonSchema(ListNamespacesSchema),
|
|
750
|
+
},
|
|
751
|
+
{
|
|
752
|
+
name: "get_namespace",
|
|
753
|
+
description: "Get details on a specified namespace",
|
|
754
|
+
inputSchema: zodToJsonSchema(GetNamespaceSchema),
|
|
755
|
+
},
|
|
756
|
+
{
|
|
757
|
+
name: "verify_namespace",
|
|
758
|
+
description: "Verify if a specified namespace already exists",
|
|
759
|
+
inputSchema: zodToJsonSchema(VerifyNamespaceSchema),
|
|
760
|
+
},
|
|
761
|
+
{
|
|
762
|
+
name: "get_project",
|
|
763
|
+
description: "Get details on a specified project",
|
|
764
|
+
inputSchema: zodToJsonSchema(GetProjectSchema),
|
|
765
|
+
},
|
|
766
|
+
{
|
|
767
|
+
name: "list_projects",
|
|
768
|
+
description: "List projects accessible by the current user",
|
|
769
|
+
inputSchema: zodToJsonSchema(ListProjectsSchema),
|
|
770
|
+
},
|
|
631
771
|
],
|
|
632
772
|
};
|
|
633
773
|
});
|
|
@@ -638,11 +778,23 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
638
778
|
}
|
|
639
779
|
switch (request.params.name) {
|
|
640
780
|
case "fork_repository": {
|
|
641
|
-
const
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
781
|
+
const forkArgs = ForkRepositorySchema.parse(request.params.arguments);
|
|
782
|
+
try {
|
|
783
|
+
const forkedProject = await forkProject(forkArgs.project_id, forkArgs.namespace);
|
|
784
|
+
return {
|
|
785
|
+
content: [{ type: "text", text: JSON.stringify(forkedProject, null, 2) }],
|
|
786
|
+
};
|
|
787
|
+
}
|
|
788
|
+
catch (forkError) {
|
|
789
|
+
console.error("Error forking repository:", forkError);
|
|
790
|
+
let forkErrorMessage = "Failed to fork repository";
|
|
791
|
+
if (forkError instanceof Error) {
|
|
792
|
+
forkErrorMessage = `${forkErrorMessage}: ${forkError.message}`;
|
|
793
|
+
}
|
|
794
|
+
return {
|
|
795
|
+
content: [{ type: "text", text: JSON.stringify({ error: forkErrorMessage }, null, 2) }],
|
|
796
|
+
};
|
|
797
|
+
}
|
|
646
798
|
}
|
|
647
799
|
case "create_branch": {
|
|
648
800
|
const args = CreateBranchSchema.parse(request.params.arguments);
|
|
@@ -739,6 +891,42 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
739
891
|
],
|
|
740
892
|
};
|
|
741
893
|
}
|
|
894
|
+
case "list_namespaces": {
|
|
895
|
+
const args = ListNamespacesSchema.parse(request.params.arguments);
|
|
896
|
+
const namespaces = await listNamespaces(args);
|
|
897
|
+
return {
|
|
898
|
+
content: [{ type: "text", text: JSON.stringify(namespaces, null, 2) }],
|
|
899
|
+
};
|
|
900
|
+
}
|
|
901
|
+
case "get_namespace": {
|
|
902
|
+
const args = GetNamespaceSchema.parse(request.params.arguments);
|
|
903
|
+
const namespace = await getNamespace(args.id);
|
|
904
|
+
return {
|
|
905
|
+
content: [{ type: "text", text: JSON.stringify(namespace, null, 2) }],
|
|
906
|
+
};
|
|
907
|
+
}
|
|
908
|
+
case "verify_namespace": {
|
|
909
|
+
const args = VerifyNamespaceSchema.parse(request.params.arguments);
|
|
910
|
+
const result = await verifyNamespaceExistence(args.namespace, args.parent_id);
|
|
911
|
+
return {
|
|
912
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
913
|
+
};
|
|
914
|
+
}
|
|
915
|
+
case "get_project": {
|
|
916
|
+
const args = GetProjectSchema.parse(request.params.arguments);
|
|
917
|
+
const { id, ...options } = args;
|
|
918
|
+
const project = await getProject(id, options);
|
|
919
|
+
return {
|
|
920
|
+
content: [{ type: "text", text: JSON.stringify(project, null, 2) }],
|
|
921
|
+
};
|
|
922
|
+
}
|
|
923
|
+
case "list_projects": {
|
|
924
|
+
const args = ListProjectsSchema.parse(request.params.arguments);
|
|
925
|
+
const projects = await listProjects(args);
|
|
926
|
+
return {
|
|
927
|
+
content: [{ type: "text", text: JSON.stringify(projects, null, 2) }],
|
|
928
|
+
};
|
|
929
|
+
}
|
|
742
930
|
case "create_note": {
|
|
743
931
|
const args = CreateNoteSchema.parse(request.params.arguments);
|
|
744
932
|
const { project_id, noteable_type, noteable_iid, body } = args;
|
package/build/schemas.js
CHANGED
|
@@ -5,6 +5,31 @@ export const GitLabAuthorSchema = z.object({
|
|
|
5
5
|
email: z.string(),
|
|
6
6
|
date: z.string(),
|
|
7
7
|
});
|
|
8
|
+
// Namespace related schemas
|
|
9
|
+
export const GitLabNamespaceSchema = z.object({
|
|
10
|
+
id: z.number(),
|
|
11
|
+
name: z.string(),
|
|
12
|
+
path: z.string(),
|
|
13
|
+
kind: z.enum(["user", "group"]),
|
|
14
|
+
full_path: z.string(),
|
|
15
|
+
parent_id: z.number().nullable(),
|
|
16
|
+
avatar_url: z.string().nullable(),
|
|
17
|
+
web_url: z.string(),
|
|
18
|
+
members_count_with_descendants: z.number().optional(),
|
|
19
|
+
billable_members_count: z.number().optional(),
|
|
20
|
+
max_seats_used: z.number().optional(),
|
|
21
|
+
seats_in_use: z.number().optional(),
|
|
22
|
+
plan: z.string().optional(),
|
|
23
|
+
end_date: z.string().nullable().optional(),
|
|
24
|
+
trial_ends_on: z.string().nullable().optional(),
|
|
25
|
+
trial: z.boolean().optional(),
|
|
26
|
+
root_repository_size: z.number().optional(),
|
|
27
|
+
projects_count: z.number().optional(),
|
|
28
|
+
});
|
|
29
|
+
export const GitLabNamespaceExistsResponseSchema = z.object({
|
|
30
|
+
exists: z.boolean(),
|
|
31
|
+
suggests: z.array(z.string()).optional(),
|
|
32
|
+
});
|
|
8
33
|
// Repository related schemas
|
|
9
34
|
export const GitLabOwnerSchema = z.object({
|
|
10
35
|
username: z.string(), // Changed from login to match GitLab API
|
|
@@ -28,6 +53,48 @@ export const GitLabRepositorySchema = z.object({
|
|
|
28
53
|
created_at: z.string().optional(),
|
|
29
54
|
last_activity_at: z.string().optional(),
|
|
30
55
|
default_branch: z.string().optional(),
|
|
56
|
+
namespace: z.object({
|
|
57
|
+
id: z.number(),
|
|
58
|
+
name: z.string(),
|
|
59
|
+
path: z.string(),
|
|
60
|
+
kind: z.string(),
|
|
61
|
+
full_path: z.string(),
|
|
62
|
+
avatar_url: z.string().nullable().optional(),
|
|
63
|
+
web_url: z.string().optional(),
|
|
64
|
+
}).optional(),
|
|
65
|
+
readme_url: z.string().optional().nullable(),
|
|
66
|
+
topics: z.array(z.string()).optional(),
|
|
67
|
+
tag_list: z.array(z.string()).optional(), // deprecated but still present
|
|
68
|
+
open_issues_count: z.number().optional(),
|
|
69
|
+
archived: z.boolean().optional(),
|
|
70
|
+
forks_count: z.number().optional(),
|
|
71
|
+
star_count: z.number().optional(),
|
|
72
|
+
permissions: z.object({
|
|
73
|
+
project_access: z.object({
|
|
74
|
+
access_level: z.number(),
|
|
75
|
+
notification_level: z.number().optional(),
|
|
76
|
+
}).optional().nullable(),
|
|
77
|
+
group_access: z.object({
|
|
78
|
+
access_level: z.number(),
|
|
79
|
+
notification_level: z.number().optional(),
|
|
80
|
+
}).optional().nullable(),
|
|
81
|
+
}).optional(),
|
|
82
|
+
container_registry_enabled: z.boolean().optional(),
|
|
83
|
+
container_registry_access_level: z.string().optional(),
|
|
84
|
+
issues_enabled: z.boolean().optional(),
|
|
85
|
+
merge_requests_enabled: z.boolean().optional(),
|
|
86
|
+
wiki_enabled: z.boolean().optional(),
|
|
87
|
+
jobs_enabled: z.boolean().optional(),
|
|
88
|
+
snippets_enabled: z.boolean().optional(),
|
|
89
|
+
can_create_merge_request_in: z.boolean().optional(),
|
|
90
|
+
resolve_outdated_diff_discussions: z.boolean().optional(),
|
|
91
|
+
shared_runners_enabled: z.boolean().optional(),
|
|
92
|
+
shared_with_groups: z.array(z.object({
|
|
93
|
+
group_id: z.number(),
|
|
94
|
+
group_name: z.string(),
|
|
95
|
+
group_full_path: z.string(),
|
|
96
|
+
group_access_level: z.number(),
|
|
97
|
+
})).optional(),
|
|
31
98
|
});
|
|
32
99
|
// File content schemas
|
|
33
100
|
export const GitLabFileContentSchema = z.object({
|
|
@@ -141,11 +208,11 @@ export const GitLabForkParentSchema = z.object({
|
|
|
141
208
|
username: z.string(), // Changed from login to match GitLab API
|
|
142
209
|
id: z.number(),
|
|
143
210
|
avatar_url: z.string(),
|
|
144
|
-
}),
|
|
211
|
+
}).optional(), // Made optional to handle cases where GitLab API doesn't include it
|
|
145
212
|
web_url: z.string(), // Changed from html_url to match GitLab API
|
|
146
213
|
});
|
|
147
214
|
export const GitLabForkSchema = GitLabRepositorySchema.extend({
|
|
148
|
-
forked_from_project: GitLabForkParentSchema, //
|
|
215
|
+
forked_from_project: GitLabForkParentSchema.optional(), // Made optional to handle cases where GitLab API doesn't include it
|
|
149
216
|
});
|
|
150
217
|
// Issue related schemas
|
|
151
218
|
export const GitLabLabelSchema = z.object({
|
|
@@ -364,3 +431,44 @@ export const CreateNoteSchema = z.object({
|
|
|
364
431
|
noteable_iid: z.number().describe("IID of the issue or merge request"),
|
|
365
432
|
body: z.string().describe("Note content"),
|
|
366
433
|
});
|
|
434
|
+
// Add namespace-related operation schemas
|
|
435
|
+
export const ListNamespacesSchema = z.object({
|
|
436
|
+
search: z.string().optional().describe("Only returns namespaces accessible by the current user"),
|
|
437
|
+
owned_only: z.boolean().optional().describe("If true, only returns namespaces by the current user"),
|
|
438
|
+
top_level_only: z.boolean().optional().describe("In GitLab 16.8 and later, if true, only returns top-level namespaces"),
|
|
439
|
+
});
|
|
440
|
+
export const GetNamespaceSchema = z.object({
|
|
441
|
+
id: z.string().describe("ID or URL-encoded path of the namespace"),
|
|
442
|
+
});
|
|
443
|
+
export const VerifyNamespaceSchema = z.object({
|
|
444
|
+
namespace: z.string().describe("Path of the namespace"),
|
|
445
|
+
parent_id: z.number().optional().describe("ID of the parent namespace. If unspecified, only returns top-level namespaces"),
|
|
446
|
+
});
|
|
447
|
+
// Project API operation schemas
|
|
448
|
+
export const GetProjectSchema = z.object({
|
|
449
|
+
id: z.string().describe("ID or URL-encoded path of the project"),
|
|
450
|
+
license: z.boolean().optional().describe("Include project license data"),
|
|
451
|
+
statistics: z.boolean().optional().describe("Include project statistics"),
|
|
452
|
+
with_custom_attributes: z.boolean().optional().describe("Include custom attributes in response"),
|
|
453
|
+
});
|
|
454
|
+
export const ListProjectsSchema = z.object({
|
|
455
|
+
archived: z.boolean().optional().describe("Limit by archived status"),
|
|
456
|
+
id_after: z.number().optional().describe("Limit results to projects with IDs greater than the specified ID"),
|
|
457
|
+
id_before: z.number().optional().describe("Limit results to projects with IDs less than the specified ID"),
|
|
458
|
+
membership: z.boolean().optional().describe("Limit by projects that the current user is a member of"),
|
|
459
|
+
min_access_level: z.number().optional().describe("Limit by minimum access level"),
|
|
460
|
+
order_by: z.enum(['id', 'name', 'path', 'created_at', 'updated_at', 'last_activity_at']).optional().describe("Return projects ordered by field"),
|
|
461
|
+
owned: z.boolean().optional().describe("Limit by projects explicitly owned by the current user"),
|
|
462
|
+
search: z.string().optional().describe("Return list of projects matching the search criteria"),
|
|
463
|
+
simple: z.boolean().optional().describe("Return only limited fields for each project"),
|
|
464
|
+
sort: z.enum(['asc', 'desc']).optional().describe("Return projects sorted in ascending or descending order"),
|
|
465
|
+
starred: z.boolean().optional().describe("Limit by projects starred by the current user"),
|
|
466
|
+
visibility: z.enum(['public', 'internal', 'private']).optional().describe("Limit by visibility"),
|
|
467
|
+
with_custom_attributes: z.boolean().optional().describe("Include custom attributes in response"),
|
|
468
|
+
with_issues_enabled: z.boolean().optional().describe("Limit by enabled issues feature"),
|
|
469
|
+
with_merge_requests_enabled: z.boolean().optional().describe("Limit by enabled merge requests feature"),
|
|
470
|
+
with_programming_language: z.string().optional().describe("Limit by projects which use the given programming language"),
|
|
471
|
+
with_shared: z.boolean().optional().describe("Include projects shared to this group"),
|
|
472
|
+
page: z.number().optional().describe("Page number for pagination"),
|
|
473
|
+
per_page: z.number().optional().describe("Number of items per page"),
|
|
474
|
+
});
|