@zereight/mcp-gitlab 2.1.7 → 2.1.9
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.ko.md +25 -0
- package/README.md +150 -98
- package/README.zh-CN.md +25 -0
- package/build/index.js +183 -9
- package/build/schemas.js +160 -0
- package/build/test/schema-tests.js +228 -3
- package/build/test/streamable-http-static-token-auth.test.js +154 -0
- package/build/test/test-ci-lint.js +191 -0
- package/build/test/test-todos.js +195 -0
- package/build/test/test-toolset-filtering.js +13 -6
- package/build/tools/registry.js +52 -1
- package/package.json +2 -2
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import { describe, test, before, after } from "node:test";
|
|
2
|
+
import assert from "node:assert";
|
|
3
|
+
import { spawn } from "child_process";
|
|
4
|
+
import { MockGitLabServer, findMockServerPort } from "./utils/mock-gitlab-server.js";
|
|
5
|
+
const MOCK_TOKEN = "glpat-todos-test-token";
|
|
6
|
+
async function callTool(toolName, args, env) {
|
|
7
|
+
return new Promise((resolve, reject) => {
|
|
8
|
+
const proc = spawn("node", ["build/index.js"], {
|
|
9
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
10
|
+
env: {
|
|
11
|
+
...process.env,
|
|
12
|
+
...env,
|
|
13
|
+
},
|
|
14
|
+
});
|
|
15
|
+
let output = "";
|
|
16
|
+
let errorOutput = "";
|
|
17
|
+
proc.stdout?.on("data", (d) => (output += d));
|
|
18
|
+
proc.stderr?.on("data", (d) => (errorOutput += d));
|
|
19
|
+
proc.on("close", code => {
|
|
20
|
+
if (code !== 0) {
|
|
21
|
+
return reject(new Error(`Process exited with code ${code}: ${errorOutput}`));
|
|
22
|
+
}
|
|
23
|
+
const line = output.split("\n").find(l => l.startsWith("{"));
|
|
24
|
+
if (!line)
|
|
25
|
+
return reject(new Error("No JSON output found"));
|
|
26
|
+
try {
|
|
27
|
+
const response = JSON.parse(line);
|
|
28
|
+
if (response.error) {
|
|
29
|
+
reject(response.error);
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
const content = response.result?.content?.[0]?.text;
|
|
33
|
+
resolve(content ? JSON.parse(content) : response.result);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
catch (e) {
|
|
37
|
+
reject(e);
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
proc.stdin?.end(JSON.stringify({
|
|
41
|
+
jsonrpc: "2.0",
|
|
42
|
+
id: 1,
|
|
43
|
+
method: "tools/call",
|
|
44
|
+
params: args === undefined ? { name: toolName } : { name: toolName, arguments: args },
|
|
45
|
+
}) + "\n");
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
async function listToolNames(env) {
|
|
49
|
+
return new Promise((resolve, reject) => {
|
|
50
|
+
const proc = spawn("node", ["build/index.js"], {
|
|
51
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
52
|
+
env: {
|
|
53
|
+
...process.env,
|
|
54
|
+
...env,
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
let output = "";
|
|
58
|
+
let errorOutput = "";
|
|
59
|
+
proc.stdout?.on("data", (d) => (output += d));
|
|
60
|
+
proc.stderr?.on("data", (d) => (errorOutput += d));
|
|
61
|
+
proc.on("close", code => {
|
|
62
|
+
if (code !== 0) {
|
|
63
|
+
return reject(new Error(`Process exited with code ${code}: ${errorOutput}`));
|
|
64
|
+
}
|
|
65
|
+
const line = output.split("\n").find(l => l.startsWith("{"));
|
|
66
|
+
if (!line)
|
|
67
|
+
return reject(new Error("No JSON output found"));
|
|
68
|
+
try {
|
|
69
|
+
const response = JSON.parse(line);
|
|
70
|
+
if (response.error) {
|
|
71
|
+
reject(response.error);
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
resolve(response.result.tools.map((tool) => tool.name));
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
catch (e) {
|
|
78
|
+
reject(e);
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
proc.stdin?.end(JSON.stringify({
|
|
82
|
+
jsonrpc: "2.0",
|
|
83
|
+
id: 1,
|
|
84
|
+
method: "tools/list",
|
|
85
|
+
params: {},
|
|
86
|
+
}) + "\n");
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
function todoFixture(id, state = "pending") {
|
|
90
|
+
return {
|
|
91
|
+
id,
|
|
92
|
+
project: { id: 123, path_with_namespace: "group/project" },
|
|
93
|
+
author: { id: 1, username: "root" },
|
|
94
|
+
action_name: "marked",
|
|
95
|
+
target_type: "MergeRequest",
|
|
96
|
+
target: { id: 34, iid: 7, project_id: 123, title: "Review this MR" },
|
|
97
|
+
target_url: "https://gitlab.example.com/group/project/-/merge_requests/7",
|
|
98
|
+
body: "Review this MR",
|
|
99
|
+
state,
|
|
100
|
+
created_at: "2026-01-01T00:00:00.000Z",
|
|
101
|
+
updated_at: "2026-01-01T00:00:00.000Z",
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
describe("GitLab todos tools", () => {
|
|
105
|
+
let mockGitLab;
|
|
106
|
+
let mockGitLabUrl;
|
|
107
|
+
before(async () => {
|
|
108
|
+
const mockPort = await findMockServerPort(9250);
|
|
109
|
+
mockGitLab = new MockGitLabServer({
|
|
110
|
+
port: mockPort,
|
|
111
|
+
validTokens: [MOCK_TOKEN],
|
|
112
|
+
});
|
|
113
|
+
mockGitLab.addMockHandler("get", "/todos", (req, res) => {
|
|
114
|
+
assert.strictEqual(req.query.state, "pending");
|
|
115
|
+
assert.strictEqual(req.query.action, "assigned");
|
|
116
|
+
assert.strictEqual(req.query.project_id, "123");
|
|
117
|
+
assert.strictEqual(req.query.page, "2");
|
|
118
|
+
assert.strictEqual(req.query.per_page, "5");
|
|
119
|
+
res.json([todoFixture(102)]);
|
|
120
|
+
});
|
|
121
|
+
mockGitLab.addMockHandler("post", "/todos/102/mark_as_done", (req, res) => {
|
|
122
|
+
res.json(todoFixture(102, "done"));
|
|
123
|
+
});
|
|
124
|
+
mockGitLab.addMockHandler("post", "/todos/mark_as_done", (req, res) => {
|
|
125
|
+
res.status(204).send();
|
|
126
|
+
});
|
|
127
|
+
await mockGitLab.start();
|
|
128
|
+
mockGitLabUrl = mockGitLab.getUrl();
|
|
129
|
+
});
|
|
130
|
+
after(async () => {
|
|
131
|
+
await mockGitLab.stop();
|
|
132
|
+
});
|
|
133
|
+
test("list_todos sends filters and returns todos", async () => {
|
|
134
|
+
const result = await callTool("list_todos", {
|
|
135
|
+
state: "pending",
|
|
136
|
+
action: "assigned",
|
|
137
|
+
project_id: 123,
|
|
138
|
+
page: 2,
|
|
139
|
+
per_page: 5,
|
|
140
|
+
}, {
|
|
141
|
+
GITLAB_API_URL: `${mockGitLabUrl}/api/v4`,
|
|
142
|
+
GITLAB_PERSONAL_ACCESS_TOKEN: MOCK_TOKEN,
|
|
143
|
+
});
|
|
144
|
+
assert.ok(Array.isArray(result));
|
|
145
|
+
assert.strictEqual(result[0].id, 102);
|
|
146
|
+
assert.strictEqual(result[0].state, "pending");
|
|
147
|
+
});
|
|
148
|
+
test("mark_todo_done marks one todo done", async () => {
|
|
149
|
+
const result = await callTool("mark_todo_done", { id: 102 }, {
|
|
150
|
+
GITLAB_API_URL: `${mockGitLabUrl}/api/v4`,
|
|
151
|
+
GITLAB_PERSONAL_ACCESS_TOKEN: MOCK_TOKEN,
|
|
152
|
+
});
|
|
153
|
+
assert.strictEqual(result.id, 102);
|
|
154
|
+
assert.strictEqual(result.state, "done");
|
|
155
|
+
});
|
|
156
|
+
test("mark_all_todos_done reports success", async () => {
|
|
157
|
+
const result = await callTool("mark_all_todos_done", {}, {
|
|
158
|
+
GITLAB_API_URL: `${mockGitLabUrl}/api/v4`,
|
|
159
|
+
GITLAB_PERSONAL_ACCESS_TOKEN: MOCK_TOKEN,
|
|
160
|
+
});
|
|
161
|
+
assert.deepStrictEqual(result, {
|
|
162
|
+
status: "success",
|
|
163
|
+
message: "All pending to-do items marked as done",
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
test("mark_all_todos_done accepts omitted arguments", async () => {
|
|
167
|
+
const result = await callTool("mark_all_todos_done", undefined, {
|
|
168
|
+
GITLAB_API_URL: `${mockGitLabUrl}/api/v4`,
|
|
169
|
+
GITLAB_PERSONAL_ACCESS_TOKEN: MOCK_TOKEN,
|
|
170
|
+
});
|
|
171
|
+
assert.deepStrictEqual(result, {
|
|
172
|
+
status: "success",
|
|
173
|
+
message: "All pending to-do items marked as done",
|
|
174
|
+
});
|
|
175
|
+
});
|
|
176
|
+
test("todo tools are visible in the default issues toolset", async () => {
|
|
177
|
+
const tools = await listToolNames({
|
|
178
|
+
GITLAB_API_URL: `${mockGitLabUrl}/api/v4`,
|
|
179
|
+
GITLAB_PERSONAL_ACCESS_TOKEN: MOCK_TOKEN,
|
|
180
|
+
});
|
|
181
|
+
assert.ok(tools.includes("list_todos"));
|
|
182
|
+
assert.ok(tools.includes("mark_todo_done"));
|
|
183
|
+
assert.ok(tools.includes("mark_all_todos_done"));
|
|
184
|
+
});
|
|
185
|
+
test("read-only mode keeps list_todos and hides todo mutations", async () => {
|
|
186
|
+
const tools = await listToolNames({
|
|
187
|
+
GITLAB_API_URL: `${mockGitLabUrl}/api/v4`,
|
|
188
|
+
GITLAB_PERSONAL_ACCESS_TOKEN: MOCK_TOKEN,
|
|
189
|
+
GITLAB_READ_ONLY_MODE: "true",
|
|
190
|
+
});
|
|
191
|
+
assert.ok(tools.includes("list_todos"));
|
|
192
|
+
assert.ok(!tools.includes("mark_todo_done"));
|
|
193
|
+
assert.ok(!tools.includes("mark_all_todos_done"));
|
|
194
|
+
});
|
|
195
|
+
});
|
|
@@ -17,11 +17,12 @@ const MCP_PORT_BASE = 3200;
|
|
|
17
17
|
// Known tool counts per toolset (from TOOLSET_DEFINITIONS)
|
|
18
18
|
const TOOLSET_TOOL_COUNTS = {
|
|
19
19
|
merge_requests: 40,
|
|
20
|
-
issues:
|
|
20
|
+
issues: 23,
|
|
21
21
|
repositories: 7,
|
|
22
|
-
branches:
|
|
22
|
+
branches: 6,
|
|
23
23
|
projects: 8,
|
|
24
24
|
labels: 5,
|
|
25
|
+
ci: 2,
|
|
25
26
|
pipelines: 19,
|
|
26
27
|
milestones: 9,
|
|
27
28
|
wiki: 10,
|
|
@@ -32,6 +33,7 @@ const TOOLSET_TOOL_COUNTS = {
|
|
|
32
33
|
workitems: 18,
|
|
33
34
|
webhooks: 3,
|
|
34
35
|
};
|
|
36
|
+
const LEGACY_PIPELINE_TOOL_COUNT = TOOLSET_TOOL_COUNTS.pipelines + TOOLSET_TOOL_COUNTS.ci;
|
|
35
37
|
const DEFAULT_TOOLSETS = [
|
|
36
38
|
"merge_requests",
|
|
37
39
|
"issues",
|
|
@@ -39,6 +41,7 @@ const DEFAULT_TOOLSETS = [
|
|
|
39
41
|
"branches",
|
|
40
42
|
"projects",
|
|
41
43
|
"labels",
|
|
44
|
+
"ci",
|
|
42
45
|
"users",
|
|
43
46
|
];
|
|
44
47
|
const NON_DEFAULT_TOOLSETS = [
|
|
@@ -58,11 +61,12 @@ const ALL_TOOLSET_TOOL_COUNT = Object.values(TOOLSET_TOOL_COUNTS).reduce((sum, c
|
|
|
58
61
|
// Representative tools per toolset for spot-checking
|
|
59
62
|
const TOOLSET_SAMPLE_TOOLS = {
|
|
60
63
|
merge_requests: ["merge_merge_request", "create_merge_request_thread", "list_draft_notes"],
|
|
61
|
-
issues: ["create_issue", "list_issues", "create_note"],
|
|
64
|
+
issues: ["create_issue", "list_issues", "create_note", "list_todos"],
|
|
62
65
|
repositories: ["search_repositories", "get_file_contents", "push_files"],
|
|
63
|
-
branches: ["create_branch", "list_commits"],
|
|
66
|
+
branches: ["create_branch", "list_commits", "list_commit_statuses", "create_commit_status"],
|
|
64
67
|
projects: ["get_project", "list_namespaces", "list_group_iterations"],
|
|
65
68
|
labels: ["list_labels", "create_label"],
|
|
69
|
+
ci: ["validate_ci_lint", "validate_project_ci_lint"],
|
|
66
70
|
pipelines: ["list_pipelines", "create_pipeline", "cancel_pipeline_job", "list_deployments", "list_job_artifacts"],
|
|
67
71
|
milestones: ["list_milestones", "create_milestone", "get_milestone_burndown_events"],
|
|
68
72
|
wiki: ["list_wiki_pages", "create_wiki_page", "list_group_wiki_pages", "create_group_wiki_page"],
|
|
@@ -260,7 +264,7 @@ describe("Toolset Filtering", { concurrency: 1 }, () => {
|
|
|
260
264
|
});
|
|
261
265
|
after(() => cleanupServers([server]));
|
|
262
266
|
test("returns issue tools + all pipeline tools + discover_tools", () => {
|
|
263
|
-
assert.strictEqual(tools.length, TOOLSET_TOOL_COUNTS.issues +
|
|
267
|
+
assert.strictEqual(tools.length, TOOLSET_TOOL_COUNTS.issues + LEGACY_PIPELINE_TOOL_COUNT + DISCOVER_TOOLS_COUNT);
|
|
264
268
|
});
|
|
265
269
|
test("includes all pipeline tools via legacy flag", () => {
|
|
266
270
|
assertContainsAll(tools, TOOLSET_SAMPLE_TOOLS.pipelines, "pipelines");
|
|
@@ -297,6 +301,7 @@ describe("Toolset Filtering", { concurrency: 1 }, () => {
|
|
|
297
301
|
"list_issue_links",
|
|
298
302
|
"list_issue_discussions",
|
|
299
303
|
"get_issue_link",
|
|
304
|
+
"list_todos",
|
|
300
305
|
"list_issue_emoji_reactions",
|
|
301
306
|
"list_issue_note_emoji_reactions",
|
|
302
307
|
];
|
|
@@ -304,6 +309,8 @@ describe("Toolset Filtering", { concurrency: 1 }, () => {
|
|
|
304
309
|
"create_issue",
|
|
305
310
|
"update_issue",
|
|
306
311
|
"delete_issue",
|
|
312
|
+
"mark_todo_done",
|
|
313
|
+
"mark_all_todos_done",
|
|
307
314
|
"create_issue_note",
|
|
308
315
|
"update_issue_note",
|
|
309
316
|
"create_issue_link",
|
|
@@ -396,7 +403,7 @@ describe("Toolset Filtering", { concurrency: 1 }, () => {
|
|
|
396
403
|
});
|
|
397
404
|
after(() => cleanupServers([server]));
|
|
398
405
|
test("returns exactly pipeline tool count + discover_tools (no duplicates)", () => {
|
|
399
|
-
assert.strictEqual(tools.length,
|
|
406
|
+
assert.strictEqual(tools.length, LEGACY_PIPELINE_TOOL_COUNT + DISCOVER_TOOLS_COUNT);
|
|
400
407
|
});
|
|
401
408
|
});
|
|
402
409
|
// ---- 12. GITLAB_TOOLS with tool already in enabled toolset (no dupes) ----
|
package/build/tools/registry.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { zodToJsonSchema } from "zod-to-json-schema";
|
|
2
2
|
import { toJSONSchema } from "../utils/schema.js";
|
|
3
3
|
import { USE_GITLAB_WIKI, USE_MILESTONE, USE_PIPELINE, } from "../config.js";
|
|
4
|
-
import { ApproveMergeRequestSchema, BulkPublishDraftNotesSchema, CancelPipelineJobSchema, CancelPipelineSchema, ConvertWorkItemTypeSchema, CreateBranchSchema, CreateDraftNoteSchema, CreateGroupWikiPageSchema, CreateIssueLinkSchema, CreateIssueNoteSchema, CreateIssueSchema, CreateIssueEmojiReactionSchema, CreateIssueNoteEmojiReactionSchema, ListIssueEmojiReactionsSchema, ListIssueNoteEmojiReactionsSchema, CreateLabelSchema, CreateMergeRequestDiscussionNoteSchema, CreateMergeRequestEmojiReactionSchema, ListMergeRequestEmojiReactionsSchema, ListMergeRequestNoteEmojiReactionsSchema, CreateMergeRequestNoteSchema, CreateMergeRequestNoteEmojiReactionSchema, CreateMergeRequestSchema, CreateMergeRequestThreadSchema, CreateNoteSchema, CreateOrUpdateFileSchema, CreatePipelineSchema, CreateProjectMilestoneSchema, CreateReleaseEvidenceSchema, CreateReleaseSchema, CreateRepositorySchema, CreateTagSchema, CreateTimelineEventSchema, CreateWikiPageSchema, CreateWorkItemNoteSchema, CreateWorkItemEmojiReactionSchema, CreateWorkItemNoteEmojiReactionSchema, ListWorkItemEmojiReactionsSchema, ListWorkItemNoteEmojiReactionsSchema, CreateWorkItemSchema, DeleteDraftNoteSchema, DeleteGroupWikiPageSchema, DeleteIssueLinkSchema, DeleteIssueSchema, DeleteIssueEmojiReactionSchema, DeleteIssueNoteEmojiReactionSchema, DeleteLabelSchema, DeleteMergeRequestDiscussionNoteSchema, DeleteMergeRequestNoteSchema, DeleteMergeRequestEmojiReactionSchema, DeleteMergeRequestNoteEmojiReactionSchema, DeleteProjectMilestoneSchema, DeleteReleaseSchema, DeleteTagSchema, DeleteWikiPageSchema, DeleteWorkItemEmojiReactionSchema, DeleteWorkItemNoteEmojiReactionSchema, DownloadAttachmentSchema, DownloadJobArtifactsSchema, DownloadReleaseAssetSchema, EditProjectMilestoneSchema, ExecuteGraphQLSchema, ForkRepositorySchema, GetBranchDiffsSchema, GetCommitDiffSchema, GetCommitSchema, GetDeploymentSchema, GetDraftNoteSchema, GetEnvironmentSchema, GetFileContentsSchema, GetGroupWikiPageSchema, GetIssueLinkSchema, GetIssueSchema, GetJobArtifactFileSchema, GetLabelSchema, GetMergeRequestApprovalStateSchema, GetMergeRequestConflictsSchema, GetMergeRequestDiffsSchema, GetMergeRequestFileDiffSchema, GetMergeRequestNoteSchema, GetMergeRequestNotesSchema, GetMergeRequestSchema, GetMergeRequestVersionSchema, GetMilestoneBurndownEventsSchema, GetMilestoneIssuesSchema, GetMilestoneMergeRequestsSchema, GetNamespaceSchema, GetPipelineJobOutputSchema, GetPipelineSchema, GetProjectEventsSchema, GetProjectMilestoneSchema, GetProjectSchema, GetReleaseSchema, GetRepositoryTreeSchema, GetTagSchema, GetTagSignatureSchema, GetTimelineEventsSchema, GetUsersSchema, GetWebhookEventSchema, GetWikiPageSchema, GetWorkItemSchema, ListCommitsSchema, ListCustomFieldDefinitionsSchema, ListDeploymentsSchema, ListDraftNotesSchema, ListEnvironmentsSchema, ListEventsSchema, ListGroupIterationsSchema, ListGroupProjectsSchema, ListGroupWikiPagesSchema, ListIssueDiscussionsSchema, ListIssueLinksSchema, ListIssuesSchema, ListJobArtifactsSchema, ListLabelsSchema, ListMergeRequestChangedFilesSchema, ListMergeRequestDiffsSchema, ListMergeRequestDiscussionsSchema, ListMergeRequestVersionsSchema, ListMergeRequestsSchema, ListNamespacesSchema, ListPipelineJobsSchema, ListPipelineTriggerJobsSchema, ListPipelinesSchema, ListProjectMembersSchema, ListProjectMilestonesSchema, ListProjectsSchema, ListReleasesSchema, ListTagsSchema, ListWebhookEventsSchema, ListWebhooksSchema, ListWikiPagesSchema, ListWorkItemNotesSchema, ListWorkItemStatusesSchema, ListWorkItemsSchema, MarkdownUploadSchema, MergeMergeRequestSchema, MoveWorkItemSchema, MyIssuesSchema, PlayPipelineJobSchema, PromoteProjectMilestoneSchema, PublishDraftNoteSchema, PushFilesSchema, ResolveMergeRequestThreadSchema, RetryPipelineJobSchema, RetryPipelineSchema, SearchCodeSchema, SearchGroupCodeSchema, SearchProjectCodeSchema, SearchRepositoriesSchema, UnapproveMergeRequestSchema, UpdateDraftNoteSchema, UpdateGroupWikiPageSchema, UpdateIssueNoteSchema, UpdateIssueSchema, UpdateLabelSchema, UpdateMergeRequestDiscussionNoteSchema, UpdateMergeRequestNoteSchema, UpdateMergeRequestSchema, UpdateReleaseSchema, UpdateWikiPageSchema, UpdateWorkItemSchema, VerifyNamespaceSchema, } from "../schemas.js";
|
|
4
|
+
import { ApproveMergeRequestSchema, BulkPublishDraftNotesSchema, CancelPipelineJobSchema, CancelPipelineSchema, ConvertWorkItemTypeSchema, CreateBranchSchema, CreateDraftNoteSchema, CreateGroupWikiPageSchema, CreateIssueLinkSchema, CreateIssueNoteSchema, CreateIssueSchema, CreateIssueEmojiReactionSchema, CreateIssueNoteEmojiReactionSchema, ListIssueEmojiReactionsSchema, ListIssueNoteEmojiReactionsSchema, CreateLabelSchema, MarkAllTodosDoneSchema, ListTodosSchema, MarkTodoDoneSchema, CreateMergeRequestDiscussionNoteSchema, CreateMergeRequestEmojiReactionSchema, ListMergeRequestEmojiReactionsSchema, ListMergeRequestNoteEmojiReactionsSchema, CreateMergeRequestNoteSchema, CreateMergeRequestNoteEmojiReactionSchema, CreateMergeRequestSchema, CreateMergeRequestThreadSchema, CreateNoteSchema, CreateCommitStatusSchema, CreateOrUpdateFileSchema, CreatePipelineSchema, CreateProjectMilestoneSchema, CreateReleaseEvidenceSchema, CreateReleaseSchema, CreateRepositorySchema, CreateTagSchema, CreateTimelineEventSchema, CreateWikiPageSchema, CreateWorkItemNoteSchema, CreateWorkItemEmojiReactionSchema, CreateWorkItemNoteEmojiReactionSchema, ListWorkItemEmojiReactionsSchema, ListWorkItemNoteEmojiReactionsSchema, CreateWorkItemSchema, DeleteDraftNoteSchema, DeleteGroupWikiPageSchema, DeleteIssueLinkSchema, DeleteIssueSchema, DeleteIssueEmojiReactionSchema, DeleteIssueNoteEmojiReactionSchema, DeleteLabelSchema, DeleteMergeRequestDiscussionNoteSchema, DeleteMergeRequestNoteSchema, DeleteMergeRequestEmojiReactionSchema, DeleteMergeRequestNoteEmojiReactionSchema, DeleteProjectMilestoneSchema, DeleteReleaseSchema, DeleteTagSchema, DeleteWikiPageSchema, DeleteWorkItemEmojiReactionSchema, DeleteWorkItemNoteEmojiReactionSchema, DownloadAttachmentSchema, DownloadJobArtifactsSchema, DownloadReleaseAssetSchema, EditProjectMilestoneSchema, ExecuteGraphQLSchema, ForkRepositorySchema, GetBranchDiffsSchema, GetCommitDiffSchema, GetCommitSchema, GetDeploymentSchema, GetDraftNoteSchema, GetEnvironmentSchema, GetFileContentsSchema, GetGroupWikiPageSchema, GetIssueLinkSchema, GetIssueSchema, GetJobArtifactFileSchema, GetLabelSchema, GetMergeRequestApprovalStateSchema, GetMergeRequestConflictsSchema, GetMergeRequestDiffsSchema, GetMergeRequestFileDiffSchema, GetMergeRequestNoteSchema, GetMergeRequestNotesSchema, GetMergeRequestSchema, GetMergeRequestVersionSchema, GetMilestoneBurndownEventsSchema, GetMilestoneIssuesSchema, GetMilestoneMergeRequestsSchema, GetNamespaceSchema, GetPipelineJobOutputSchema, GetPipelineSchema, GetProjectEventsSchema, GetProjectMilestoneSchema, GetProjectSchema, GetReleaseSchema, GetRepositoryTreeSchema, GetTagSchema, GetTagSignatureSchema, GetTimelineEventsSchema, GetUsersSchema, GetWebhookEventSchema, GetWikiPageSchema, GetWorkItemSchema, ListCommitsSchema, ListCommitStatusesSchema, ListCustomFieldDefinitionsSchema, ListDeploymentsSchema, ListDraftNotesSchema, ListEnvironmentsSchema, ListEventsSchema, ListGroupIterationsSchema, ListGroupProjectsSchema, ListGroupWikiPagesSchema, ListIssueDiscussionsSchema, ListIssueLinksSchema, ListIssuesSchema, ListJobArtifactsSchema, ListLabelsSchema, ListMergeRequestChangedFilesSchema, ListMergeRequestDiffsSchema, ListMergeRequestDiscussionsSchema, ListMergeRequestVersionsSchema, ListMergeRequestsSchema, ListNamespacesSchema, ListPipelineJobsSchema, ListPipelineTriggerJobsSchema, ValidateCiLintSchema, ValidateProjectCiLintSchema, ListPipelinesSchema, ListProjectMembersSchema, ListProjectMilestonesSchema, ListProjectsSchema, ListReleasesSchema, ListTagsSchema, ListWebhookEventsSchema, ListWebhooksSchema, ListWikiPagesSchema, ListWorkItemNotesSchema, ListWorkItemStatusesSchema, ListWorkItemsSchema, MarkdownUploadSchema, MergeMergeRequestSchema, MoveWorkItemSchema, MyIssuesSchema, PlayPipelineJobSchema, PromoteProjectMilestoneSchema, PublishDraftNoteSchema, PushFilesSchema, ResolveMergeRequestThreadSchema, RetryPipelineJobSchema, RetryPipelineSchema, SearchCodeSchema, SearchGroupCodeSchema, SearchProjectCodeSchema, SearchRepositoriesSchema, UnapproveMergeRequestSchema, UpdateDraftNoteSchema, UpdateGroupWikiPageSchema, UpdateIssueNoteSchema, UpdateIssueSchema, UpdateLabelSchema, UpdateMergeRequestDiscussionNoteSchema, UpdateMergeRequestNoteSchema, UpdateMergeRequestSchema, UpdateReleaseSchema, UpdateWikiPageSchema, UpdateWorkItemSchema, VerifyNamespaceSchema, } from "../schemas.js";
|
|
5
5
|
// Define all available tools
|
|
6
6
|
export const allTools = [
|
|
7
7
|
{
|
|
@@ -316,6 +316,21 @@ export const allTools = [
|
|
|
316
316
|
description: "Delete an issue",
|
|
317
317
|
inputSchema: toJSONSchema(DeleteIssueSchema),
|
|
318
318
|
},
|
|
319
|
+
{
|
|
320
|
+
name: "list_todos",
|
|
321
|
+
description: "List GitLab to-do items for the current user",
|
|
322
|
+
inputSchema: toJSONSchema(ListTodosSchema),
|
|
323
|
+
},
|
|
324
|
+
{
|
|
325
|
+
name: "mark_todo_done",
|
|
326
|
+
description: "Mark a GitLab to-do item as done",
|
|
327
|
+
inputSchema: toJSONSchema(MarkTodoDoneSchema),
|
|
328
|
+
},
|
|
329
|
+
{
|
|
330
|
+
name: "mark_all_todos_done",
|
|
331
|
+
description: "Mark all pending GitLab to-do items as done for the current user",
|
|
332
|
+
inputSchema: toJSONSchema(MarkAllTodosDoneSchema),
|
|
333
|
+
},
|
|
319
334
|
{
|
|
320
335
|
name: "list_issue_links",
|
|
321
336
|
description: "List all issue links for a specific issue",
|
|
@@ -506,6 +521,16 @@ export const allTools = [
|
|
|
506
521
|
description: "Get the output/trace of a pipeline job with optional pagination",
|
|
507
522
|
inputSchema: toJSONSchema(GetPipelineJobOutputSchema),
|
|
508
523
|
},
|
|
524
|
+
{
|
|
525
|
+
name: "validate_ci_lint",
|
|
526
|
+
description: "Validate provided GitLab CI/CD YAML content for a project",
|
|
527
|
+
inputSchema: toJSONSchema(ValidateCiLintSchema),
|
|
528
|
+
},
|
|
529
|
+
{
|
|
530
|
+
name: "validate_project_ci_lint",
|
|
531
|
+
description: "Validate an existing .gitlab-ci.yml configuration for a project",
|
|
532
|
+
inputSchema: toJSONSchema(ValidateProjectCiLintSchema),
|
|
533
|
+
},
|
|
509
534
|
{
|
|
510
535
|
name: "create_pipeline",
|
|
511
536
|
description: "Create a new pipeline for a branch or tag",
|
|
@@ -621,6 +646,16 @@ export const allTools = [
|
|
|
621
646
|
description: "Get changes/diffs of a specific commit",
|
|
622
647
|
inputSchema: toJSONSchema(GetCommitDiffSchema),
|
|
623
648
|
},
|
|
649
|
+
{
|
|
650
|
+
name: "list_commit_statuses",
|
|
651
|
+
description: "List statuses for a commit",
|
|
652
|
+
inputSchema: toJSONSchema(ListCommitStatusesSchema),
|
|
653
|
+
},
|
|
654
|
+
{
|
|
655
|
+
name: "create_commit_status",
|
|
656
|
+
description: "Create or update the status of a commit",
|
|
657
|
+
inputSchema: toJSONSchema(CreateCommitStatusSchema),
|
|
658
|
+
},
|
|
624
659
|
{
|
|
625
660
|
name: "list_group_iterations",
|
|
626
661
|
description: "List group iterations with filtering options",
|
|
@@ -867,6 +902,7 @@ export const readOnlyTools = new Set([
|
|
|
867
902
|
"list_draft_notes",
|
|
868
903
|
"mr_discussions",
|
|
869
904
|
"list_issues",
|
|
905
|
+
"list_todos",
|
|
870
906
|
"my_issues",
|
|
871
907
|
"list_merge_requests",
|
|
872
908
|
"get_issue",
|
|
@@ -889,6 +925,8 @@ export const readOnlyTools = new Set([
|
|
|
889
925
|
"list_pipeline_trigger_jobs",
|
|
890
926
|
"get_pipeline_job",
|
|
891
927
|
"get_pipeline_job_output",
|
|
928
|
+
"validate_ci_lint",
|
|
929
|
+
"validate_project_ci_lint",
|
|
892
930
|
"list_job_artifacts",
|
|
893
931
|
"download_job_artifacts",
|
|
894
932
|
"get_job_artifact_file",
|
|
@@ -909,6 +947,7 @@ export const readOnlyTools = new Set([
|
|
|
909
947
|
"list_commits",
|
|
910
948
|
"get_commit",
|
|
911
949
|
"get_commit_diff",
|
|
950
|
+
"list_commit_statuses",
|
|
912
951
|
"list_group_iterations",
|
|
913
952
|
"get_group_iteration",
|
|
914
953
|
"download_attachment",
|
|
@@ -998,6 +1037,8 @@ export const pipelineToolNames = new Set([
|
|
|
998
1037
|
"list_pipeline_trigger_jobs",
|
|
999
1038
|
"get_pipeline_job",
|
|
1000
1039
|
"get_pipeline_job_output",
|
|
1040
|
+
"validate_ci_lint",
|
|
1041
|
+
"validate_project_ci_lint",
|
|
1001
1042
|
"create_pipeline",
|
|
1002
1043
|
"retry_pipeline",
|
|
1003
1044
|
"cancel_pipeline",
|
|
@@ -1065,6 +1106,9 @@ export const TOOLSET_DEFINITIONS = [
|
|
|
1065
1106
|
"get_issue",
|
|
1066
1107
|
"update_issue",
|
|
1067
1108
|
"delete_issue",
|
|
1109
|
+
"list_todos",
|
|
1110
|
+
"mark_todo_done",
|
|
1111
|
+
"mark_all_todos_done",
|
|
1068
1112
|
"create_issue_note",
|
|
1069
1113
|
"update_issue_note",
|
|
1070
1114
|
"list_issue_links",
|
|
@@ -1102,6 +1146,8 @@ export const TOOLSET_DEFINITIONS = [
|
|
|
1102
1146
|
"list_commits",
|
|
1103
1147
|
"get_commit",
|
|
1104
1148
|
"get_commit_diff",
|
|
1149
|
+
"list_commit_statuses",
|
|
1150
|
+
"create_commit_status",
|
|
1105
1151
|
]),
|
|
1106
1152
|
},
|
|
1107
1153
|
{
|
|
@@ -1129,6 +1175,11 @@ export const TOOLSET_DEFINITIONS = [
|
|
|
1129
1175
|
"delete_label",
|
|
1130
1176
|
]),
|
|
1131
1177
|
},
|
|
1178
|
+
{
|
|
1179
|
+
id: "ci",
|
|
1180
|
+
isDefault: true,
|
|
1181
|
+
tools: new Set(["validate_ci_lint", "validate_project_ci_lint"]),
|
|
1182
|
+
},
|
|
1132
1183
|
{
|
|
1133
1184
|
id: "pipelines",
|
|
1134
1185
|
isDefault: false,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zereight/mcp-gitlab",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.9",
|
|
4
4
|
"mcpName": "io.github.zereight/gitlab-mcp",
|
|
5
5
|
"description": "GitLab MCP server for projects, merge requests, issues, pipelines, wiki, releases, and more",
|
|
6
6
|
"keywords": [
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"changelog": "auto-changelog -p",
|
|
52
52
|
"test": "npm run test:all",
|
|
53
53
|
"test:all": "npm run build && npm run test:mock && npm run test:live",
|
|
54
|
-
"test:mock": "node --import tsx/esm --test test/remote-auth-simple-test.ts && node --import tsx/esm --test test/mcp-oauth-tests.ts && tsx test/oauth-tests.ts && tsx test/test-list-merge-requests.ts && tsx test/test-list-project-members.ts && tsx test/test-download-attachment.ts && node --import tsx/esm --test test/test-job-artifacts.ts && node --import tsx/esm --test test/test-deployment-tools.ts && node --import tsx/esm --test test/test-merge-request-approval-state-tools.ts && node --import tsx/esm --test test/test-search-code.ts && node --import tsx/esm --test test/test-tags.ts && node --import tsx/esm --test test/test-toolset-filtering.ts && node --import tsx/esm --test test/test-auth-retry.ts && node --import tsx/esm --test test/stateless/codec.test.ts test/stateless/client-id.test.ts test/stateless/callback-proxy.test.ts test/stateless/session-id.test.ts test/stateless/session-id-integration.test.ts test/stateless/config-ttl.test.ts",
|
|
54
|
+
"test:mock": "node --import tsx/esm --test test/remote-auth-simple-test.ts && node --import tsx/esm --test test/mcp-oauth-tests.ts && node --import tsx/esm --test test/streamable-http-static-token-auth.test.ts && tsx test/oauth-tests.ts && tsx test/test-list-merge-requests.ts && tsx test/test-list-project-members.ts && tsx test/test-download-attachment.ts && node --import tsx/esm --test test/test-job-artifacts.ts && node --import tsx/esm --test test/test-deployment-tools.ts && node --import tsx/esm --test test/test-merge-request-approval-state-tools.ts && node --import tsx/esm --test test/test-search-code.ts && node --import tsx/esm --test test/test-tags.ts && node --import tsx/esm --test test/test-toolset-filtering.ts && node --import tsx/esm --test test/test-ci-lint.ts && node --import tsx/esm --test test/test-todos.ts && node --import tsx/esm --test test/test-auth-retry.ts && node --import tsx/esm --test test/stateless/codec.test.ts test/stateless/client-id.test.ts test/stateless/callback-proxy.test.ts test/stateless/session-id.test.ts test/stateless/session-id-integration.test.ts test/stateless/config-ttl.test.ts",
|
|
55
55
|
"test:stateless": "npm run build && node --import tsx/esm --test test/stateless/codec.test.ts test/stateless/client-id.test.ts test/stateless/callback-proxy.test.ts test/stateless/session-id.test.ts test/stateless/session-id-integration.test.ts test/stateless/config-ttl.test.ts",
|
|
56
56
|
"test:mcp-oauth": "npm run build && node --import tsx/esm --test test/mcp-oauth-tests.ts",
|
|
57
57
|
"test:live": "node test/validate-api.js",
|