@zereight/mcp-gitlab 2.1.30 → 2.1.38

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.
@@ -26,6 +26,9 @@ describe('getEffectiveProjectId', { concurrency: 1 }, () => {
26
26
  let mockGitLab;
27
27
  let servers = [];
28
28
  let client;
29
+ let group123Requested = false;
30
+ let group789Requested = false;
31
+ let labelLookupRoots = [];
29
32
  before(async () => {
30
33
  // Start mock GitLab server
31
34
  const mockPort = await findMockServerPort();
@@ -33,6 +36,124 @@ describe('getEffectiveProjectId', { concurrency: 1 }, () => {
33
36
  port: mockPort,
34
37
  validTokens: [MOCK_TOKEN]
35
38
  });
39
+ mockGitLab.addMockHandler('get', '/groups/123', (_req, res) => {
40
+ group123Requested = true;
41
+ res.json({
42
+ id: 123,
43
+ name: 'Test Group',
44
+ path: 'test-group',
45
+ full_path: 'test-group',
46
+ });
47
+ });
48
+ mockGitLab.addMockHandler('get', '/projects/789', (_req, res) => {
49
+ res.status(404).json({ message: '404 Project Not Found' });
50
+ });
51
+ mockGitLab.addMockHandler('get', '/groups/789', (_req, res) => {
52
+ group789Requested = true;
53
+ res.json({
54
+ id: 789,
55
+ name: 'Numeric Group',
56
+ path: 'numeric-group',
57
+ full_path: 'numeric-group',
58
+ });
59
+ });
60
+ mockGitLab.addRootHandler('post', '/api/graphql', (req, res) => {
61
+ const { query, variables } = req.body;
62
+ if (query.includes('workItemTypes')) {
63
+ res.json({
64
+ data: {
65
+ namespace: {
66
+ workItemTypes: {
67
+ nodes: [{ id: 'gid://gitlab/WorkItems::Type/1', name: 'Issue' }],
68
+ },
69
+ },
70
+ },
71
+ });
72
+ return;
73
+ }
74
+ if (query.includes('workItems(')) {
75
+ assert.ok(query.includes('group(fullPath: $path)'), 'Should query the group GraphQL root');
76
+ assert.strictEqual(variables.path, 'test-group', 'Should use resolved group full_path');
77
+ res.json({
78
+ data: {
79
+ group: {
80
+ workItems: {
81
+ nodes: [
82
+ {
83
+ id: 'gid://gitlab/WorkItem/1',
84
+ iid: '1',
85
+ title: 'Group work item',
86
+ state: 'OPEN',
87
+ webUrl: 'https://gitlab.mock/groups/test-group/-/work_items/1',
88
+ workItemType: { name: 'Issue' },
89
+ widgets: [],
90
+ },
91
+ ],
92
+ pageInfo: { hasNextPage: false, endCursor: null },
93
+ },
94
+ },
95
+ },
96
+ });
97
+ return;
98
+ }
99
+ if (query.includes('labels(title:')) {
100
+ assert.ok(query.includes('group(fullPath: $path)'), 'Should resolve labels from Group');
101
+ assert.ok(!query.includes('namespace(fullPath: $path)'), 'Should not query labels from Namespace');
102
+ labelLookupRoots.push('group');
103
+ res.json({
104
+ data: {
105
+ group: { l0: { nodes: [{ id: 'gid://gitlab/GroupLabel/1' }] } },
106
+ users: { nodes: [] },
107
+ },
108
+ });
109
+ return;
110
+ }
111
+ if (query.includes('workItem(iid: $iid)')) {
112
+ res.json({
113
+ data: { namespace: { workItem: { id: 'gid://gitlab/WorkItem/1' } } },
114
+ });
115
+ return;
116
+ }
117
+ if (query.includes('workItemCreate')) {
118
+ assert.deepStrictEqual(variables.labelIds, ['gid://gitlab/GroupLabel/1']);
119
+ res.json({
120
+ data: {
121
+ workItemCreate: {
122
+ workItem: {
123
+ id: 'gid://gitlab/WorkItem/2',
124
+ iid: '2',
125
+ title: variables.title,
126
+ webUrl: 'https://gitlab.mock/groups/test-group/-/work_items/2',
127
+ workItemType: { name: 'Issue' },
128
+ },
129
+ errors: [],
130
+ },
131
+ },
132
+ });
133
+ return;
134
+ }
135
+ if (query.includes('workItemUpdate')) {
136
+ assert.deepStrictEqual(variables.addLabelIds, ['gid://gitlab/GroupLabel/1']);
137
+ res.json({
138
+ data: {
139
+ workItemUpdate: {
140
+ workItem: {
141
+ id: variables.id,
142
+ iid: '1',
143
+ title: 'Updated group work item',
144
+ state: 'OPEN',
145
+ webUrl: 'https://gitlab.mock/groups/test-group/-/work_items/1',
146
+ workItemType: { name: 'Issue' },
147
+ widgets: [],
148
+ },
149
+ errors: [],
150
+ },
151
+ },
152
+ });
153
+ return;
154
+ }
155
+ res.status(500).json({ message: `Unexpected GraphQL query: ${query}` });
156
+ });
36
157
  await mockGitLab.start();
37
158
  const mockGitLabUrl = mockGitLab.getUrl();
38
159
  // Start MCP server WITHOUT GITLAB_ALLOWED_PROJECT_IDS
@@ -46,7 +167,7 @@ describe('getEffectiveProjectId', { concurrency: 1 }, () => {
46
167
  REMOTE_AUTHORIZATION: 'true',
47
168
  GITLAB_API_URL: `${mockGitLabUrl}/api/v4`,
48
169
  GITLAB_PROJECT_ID: DEFAULT_PROJECT_ID,
49
- GITLAB_READ_ONLY_MODE: 'true',
170
+ GITLAB_READ_ONLY_MODE: 'false',
50
171
  }
51
172
  });
52
173
  servers.push(server);
@@ -94,6 +215,82 @@ describe('getEffectiveProjectId', { concurrency: 1 }, () => {
94
215
  assert.strictEqual(project.id.toString(), OTHER_PROJECT_ID, 'Should use passed project_id');
95
216
  console.log(` ✓ Used passed project_id ${OTHER_PROJECT_ID} instead of default ${DEFAULT_PROJECT_ID}`);
96
217
  });
218
+ test('should resolve explicit numeric group IDs through the groups endpoint', async () => {
219
+ group123Requested = false;
220
+ const result = await client.callTool('list_work_items', {
221
+ project_id: 'group:123',
222
+ });
223
+ assert.ok(group123Requested, 'Should request /groups/123');
224
+ assert.ok(result.content, 'Should have content');
225
+ const content = result.content[0];
226
+ assert.ok('text' in content, 'Content should have text');
227
+ const parsed = JSON.parse(content.text);
228
+ assert.strictEqual(parsed.items.length, 1, 'Should return group work items');
229
+ assert.strictEqual(parsed.items[0].title, 'Group work item');
230
+ console.log(' ✓ Resolved group:123 via /groups/123 when no project allowlist is set');
231
+ });
232
+ test('should resolve labels from the group root when creating group work items', async () => {
233
+ labelLookupRoots = [];
234
+ const result = await client.callTool('create_work_item', {
235
+ project_id: 'group:123',
236
+ title: 'Created group work item',
237
+ labels: ['group-label'],
238
+ });
239
+ assert.deepStrictEqual(labelLookupRoots, ['group']);
240
+ assert.ok(result.content, 'Should have content');
241
+ const content = result.content[0];
242
+ assert.ok('text' in content, 'Content should have text');
243
+ assert.strictEqual(JSON.parse(content.text).title, 'Created group work item');
244
+ console.log(' ✓ Resolved create labels through group(fullPath:)');
245
+ });
246
+ test('should resolve labels from the group root when updating group work items', async () => {
247
+ labelLookupRoots = [];
248
+ const result = await client.callTool('update_work_item', {
249
+ project_id: 'group:123',
250
+ iid: 1,
251
+ add_labels: ['group-label'],
252
+ });
253
+ assert.deepStrictEqual(labelLookupRoots, ['group']);
254
+ assert.ok(result.content, 'Should have content');
255
+ const content = result.content[0];
256
+ assert.ok('text' in content, 'Content should have text');
257
+ assert.strictEqual(JSON.parse(content.text).title, 'Updated group work item');
258
+ console.log(' ✓ Resolved update labels through group(fullPath:)');
259
+ });
260
+ test('should not fall back from bare numeric project IDs to groups', async () => {
261
+ group789Requested = false;
262
+ let didThrow = false;
263
+ try {
264
+ await client.callTool('list_work_items', {
265
+ project_id: '789',
266
+ });
267
+ }
268
+ catch (error) {
269
+ didThrow = true;
270
+ assert.ok(error instanceof Error);
271
+ assert.ok(error.message.includes('404'), 'Should surface the project 404');
272
+ }
273
+ assert.ok(didThrow, 'Should have failed on the project 404');
274
+ assert.strictEqual(group789Requested, false, 'Should not request /groups/789');
275
+ console.log(' ✓ Bare numeric ID 789 did not fall back to /groups/789');
276
+ });
277
+ test('should not fall back from explicit numeric project IDs to groups', async () => {
278
+ group789Requested = false;
279
+ let didThrow = false;
280
+ try {
281
+ await client.callTool('list_work_items', {
282
+ project_id: 'project:789',
283
+ });
284
+ }
285
+ catch (error) {
286
+ didThrow = true;
287
+ assert.ok(error instanceof Error);
288
+ assert.ok(error.message.includes('404'), 'Should surface the project 404');
289
+ }
290
+ assert.ok(didThrow, 'Should have failed on the project 404');
291
+ assert.strictEqual(group789Requested, false, 'Should not request /groups/789');
292
+ console.log(' ✓ Explicit project:789 did not fall back to /groups/789');
293
+ });
97
294
  });
98
295
  describe('getEffectiveProjectId - With single GITLAB_ALLOWED_PROJECT_IDS', () => {
99
296
  let mcpUrl;
@@ -166,6 +363,22 @@ describe('getEffectiveProjectId', { concurrency: 1 }, () => {
166
363
  console.log(' ✓ Correctly rejected access to non-allowed project');
167
364
  }
168
365
  });
366
+ test('should reject explicit group IDs when GITLAB_ALLOWED_PROJECT_IDS is set', async () => {
367
+ let didThrow = false;
368
+ try {
369
+ await client.callTool('list_work_items', {
370
+ project_id: 'group:123',
371
+ });
372
+ }
373
+ catch (error) {
374
+ didThrow = true;
375
+ assert.ok(error instanceof Error);
376
+ assert.ok(error.message.includes('GITLAB_ALLOWED_PROJECT_IDS') &&
377
+ error.message.includes('project allowlist does not cover groups'), 'Should explain that project allowlists do not authorize groups');
378
+ console.log(' ✓ Rejected group:123 when GITLAB_ALLOWED_PROJECT_IDS is set');
379
+ }
380
+ assert.ok(didThrow, 'Should have rejected explicit group access');
381
+ });
169
382
  });
170
383
  describe('getEffectiveProjectId - With multiple GITLAB_ALLOWED_PROJECT_IDS', () => {
171
384
  let mcpUrl;
@@ -56,6 +56,7 @@ const DELETE_SAMPLE_TOOLS = [
56
56
  "delete_label",
57
57
  "delete_wiki_page",
58
58
  "delete_milestone",
59
+ "delete_group_milestone",
59
60
  "delete_project_variable",
60
61
  ];
61
62
  const MODIFY_SAMPLE_TOOLS = [
@@ -10,10 +10,29 @@ function buildProtectedBranch(overrides = {}) {
10
10
  id: 1,
11
11
  name: TEST_BRANCH,
12
12
  push_access_levels: [
13
- { access_level: 30, access_level_description: "Developers + Maintainers" },
13
+ {
14
+ access_level: 30,
15
+ access_level_description: "Developers + Maintainers",
16
+ user_id: null,
17
+ group_id: null,
18
+ },
19
+ ],
20
+ merge_access_levels: [
21
+ {
22
+ access_level: 40,
23
+ access_level_description: "Maintainers",
24
+ user_id: null,
25
+ group_id: null,
26
+ },
27
+ ],
28
+ unprotect_access_levels: [
29
+ {
30
+ access_level: 60,
31
+ access_level_description: "Administrators",
32
+ user_id: null,
33
+ group_id: null,
34
+ },
14
35
  ],
15
- merge_access_levels: [{ access_level: 40, access_level_description: "Maintainers" }],
16
- unprotect_access_levels: [{ access_level: 60, access_level_description: "Administrators" }],
17
36
  allow_force_push: false,
18
37
  code_owner_approval_required: false,
19
38
  ...overrides,
@@ -24,7 +24,7 @@ const TOOLSET_TOOL_COUNTS = {
24
24
  labels: 5,
25
25
  ci: 4,
26
26
  pipelines: 19,
27
- milestones: 9,
27
+ milestones: 17,
28
28
  wiki: 10,
29
29
  releases: 7,
30
30
  tags: 5,
@@ -75,7 +75,7 @@ const TOOLSET_SAMPLE_TOOLS = {
75
75
  labels: ["list_labels", "create_label"],
76
76
  ci: ["validate_ci_lint", "validate_project_ci_lint", "list_ci_catalog_resources", "get_ci_catalog_resource"],
77
77
  pipelines: ["list_pipelines", "create_pipeline", "cancel_pipeline_job", "list_deployments", "list_job_artifacts"],
78
- milestones: ["list_milestones", "create_milestone", "get_milestone_burndown_events"],
78
+ milestones: ["list_milestones", "create_milestone", "list_group_milestones", "get_group_milestone_burndown_events"],
79
79
  wiki: ["list_wiki_pages", "create_wiki_page", "list_group_wiki_pages", "create_group_wiki_page"],
80
80
  releases: ["list_releases", "create_release", "download_release_asset"],
81
81
  tags: ["list_tags", "create_tag", "get_tag_signature"],
@@ -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, SSE, STREAMABLE_HTTP, } from "../config.js";
4
- import { ApproveMergeRequestSchema, BulkPublishDraftNotesSchema, CancelPipelineJobSchema, CancelPipelineSchema, ConvertWorkItemTypeSchema, CreateBranchSchema, CreateDraftNoteSchema, CreateGroupSchema, 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, DeleteBranchSchema, GetProtectedBranchSchema, ListProtectedBranchesSchema, ProtectBranchSchema, UnprotectBranchSchema, UpdateDefaultBranchSchema, DeleteDraftNoteSchema, DeleteGroupWikiPageSchema, DeleteIssueLinkSchema, DeleteIssueSchema, DeleteIssueEmojiReactionSchema, DeleteIssueNoteEmojiReactionSchema, DeleteLabelSchema, DeleteMergeRequestDiscussionNoteSchema, DeleteMergeRequestNoteSchema, DeleteMergeRequestEmojiReactionSchema, DeleteMergeRequestNoteEmojiReactionSchema, DeleteProjectMilestoneSchema, DeleteReleaseSchema, DeleteTagSchema, DeleteWikiPageSchema, DeleteWorkItemEmojiReactionSchema, DeleteWorkItemNoteEmojiReactionSchema, DownloadAttachmentSchema, DownloadAttachmentRemoteSchema, DownloadJobArtifactsSchema, DownloadJobArtifactsRemoteSchema, DownloadReleaseAssetSchema, EditProjectMilestoneSchema, ExecuteGraphQLSchema, ForkRepositorySchema, HealthCheckSchema, GetBranchSchema, GetBranchDiffsSchema, GetCommitDiffSchema, GetCommitSchema, GetFileBlameSchema, GetDeploymentSchema, GetDraftNoteSchema, GetEnvironmentSchema, GetFileContentsSchema, GetGroupWikiPageSchema, GetIssueLinkSchema, GetIssueSchema, GetJobArtifactFileSchema, GetLabelSchema, GetMergeRequestApprovalStateSchema, GetMergeRequestConflictsSchema, GetMergeRequestDiffsSchema, GetMergeRequestFileDiffSchema, GetMergeRequestNoteSchema, GetMergeRequestNotesSchema, GetMergeRequestSchema, GetMergeRequestVersionSchema, GetMilestoneBurndownEventsSchema, GetMilestoneIssuesSchema, GetMilestoneMergeRequestsSchema, GetNamespaceSchema, GetPipelineJobOutputSchema, PipelineJobControlSchema, GetPipelineSchema, GetProjectEventsSchema, GetProjectMilestoneSchema, GetProjectSchema, GetReleaseSchema, GetRepositoryTreeSchema, GetTagSchema, GetTagSignatureSchema, GetTimelineEventsSchema, GetUsersSchema, GetUserSchema, WhoAmISchema, GetWebhookEventSchema, GetWikiPageSchema, GetWorkItemSchema, ListBranchesSchema, ListCommitsSchema, ListCommitStatusesSchema, ListCustomFieldDefinitionsSchema, ListDeploymentsSchema, ListDraftNotesSchema, ListEnvironmentsSchema, ListEventsSchema, ListGroupIterationsSchema, ListGroupProjectsSchema, ListGroupWikiPagesSchema, ListIssueDiscussionsSchema, ListIssueLinksSchema, ListIssuesSchema, ListJobArtifactsSchema, ListLabelsSchema, ListMergeRequestChangedFilesSchema, ListMergeRequestDiffsSchema, ListMergeRequestDiscussionsSchema, ListMergeRequestPipelinesSchema, ListMergeRequestVersionsSchema, ListMergeRequestsSchema, ListNamespacesSchema, ListPipelineJobsSchema, ListPipelineTriggerJobsSchema, ValidateCiLintSchema, ValidateProjectCiLintSchema, ListCiCatalogResourcesSchema, GetCiCatalogResourceSchema, ListPipelinesSchema, ListProjectMembersSchema, ListProjectMilestonesSchema, ListProjectsSchema, ListReleasesSchema, ListTagsSchema, ListWebhookEventsSchema, ListWebhooksSchema, ListWikiPagesSchema, ListWorkItemNotesSchema, ListWorkItemStatusesSchema, ListWorkItemsSchema, MarkdownUploadSchema, MarkdownUploadRemoteSchema, MergeMergeRequestSchema, MoveWorkItemSchema, MyIssuesSchema, PlayPipelineJobSchema, PromoteProjectMilestoneSchema, PublishDraftNoteSchema, PushFilesSchema, ResolveMergeRequestThreadSchema, RetryPipelineJobSchema, RetryPipelineSchema, SearchCodeSchema, SearchGroupCodeSchema, SearchProjectCodeSchema, SearchRepositoriesSchema, UnapproveMergeRequestSchema, UpdateDraftNoteSchema, UpdateGroupWikiPageSchema, UpdateIssueNoteSchema, UpdateIssueSchema, UpdateIssueDescriptionPatchSchema, UpdateLabelSchema, UpdateProjectSchema, UpdateMergeRequestDiscussionNoteSchema, UpdateMergeRequestNoteSchema, UpdateMergeRequestSchema, UpdateReleaseSchema, UpdateWikiPageSchema, UpdateWorkItemSchema, VerifyNamespaceSchema, ListProjectVariablesSchema, GetProjectVariableSchema, CreateProjectVariableSchema, UpdateProjectVariableSchema, DeleteProjectVariableSchema, ListGroupVariablesSchema, GetGroupVariableSchema, CreateGroupVariableSchema, UpdateGroupVariableSchema, DeleteGroupVariableSchema, GetDependencyProxySettingsSchema, UpdateDependencyProxySettingsSchema, ListDependencyProxyBlobsSchema, PurgeDependencyProxyCacheSchema, } from "../schemas.js";
4
+ import { ApproveMergeRequestSchema, BulkPublishDraftNotesSchema, CancelPipelineJobSchema, CancelPipelineSchema, ConvertWorkItemTypeSchema, CreateBranchSchema, CreateDraftNoteSchema, CreateGroupSchema, 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, CreateGroupMilestoneSchema, CreateReleaseEvidenceSchema, CreateReleaseSchema, CreateRepositorySchema, CreateTagSchema, CreateTimelineEventSchema, CreateWikiPageSchema, CreateWorkItemNoteSchema, CreateWorkItemEmojiReactionSchema, CreateWorkItemNoteEmojiReactionSchema, ListWorkItemEmojiReactionsSchema, ListWorkItemNoteEmojiReactionsSchema, CreateWorkItemSchema, DeleteBranchSchema, GetProtectedBranchSchema, ListProtectedBranchesSchema, ProtectBranchSchema, UnprotectBranchSchema, UpdateDefaultBranchSchema, DeleteDraftNoteSchema, DeleteGroupMilestoneSchema, DeleteGroupWikiPageSchema, DeleteIssueLinkSchema, DeleteIssueSchema, DeleteIssueEmojiReactionSchema, DeleteIssueNoteEmojiReactionSchema, DeleteLabelSchema, DeleteMergeRequestDiscussionNoteSchema, DeleteMergeRequestNoteSchema, DeleteMergeRequestEmojiReactionSchema, DeleteMergeRequestNoteEmojiReactionSchema, DeleteProjectMilestoneSchema, DeleteReleaseSchema, DeleteTagSchema, DeleteWikiPageSchema, DeleteWorkItemEmojiReactionSchema, DeleteWorkItemNoteEmojiReactionSchema, DownloadAttachmentSchema, DownloadAttachmentRemoteSchema, DownloadJobArtifactsSchema, DownloadJobArtifactsRemoteSchema, DownloadReleaseAssetSchema, EditProjectMilestoneSchema, EditGroupMilestoneSchema, ExecuteGraphQLSchema, ForkRepositorySchema, HealthCheckSchema, GetBranchSchema, GetBranchDiffsSchema, GetCommitDiffSchema, GetCommitSchema, GetFileBlameSchema, GetDeploymentSchema, GetDraftNoteSchema, GetEnvironmentSchema, GetFileContentsSchema, GetGroupWikiPageSchema, GetIssueLinkSchema, GetIssueSchema, GetJobArtifactFileSchema, GetLabelSchema, GetMergeRequestApprovalStateSchema, GetMergeRequestConflictsSchema, GetMergeRequestDiffsSchema, GetMergeRequestFileDiffSchema, GetMergeRequestNoteSchema, GetMergeRequestNotesSchema, GetMergeRequestSchema, GetMergeRequestVersionSchema, GetMilestoneBurndownEventsSchema, GetMilestoneIssuesSchema, GetMilestoneMergeRequestsSchema, GetGroupMilestoneSchema, GetGroupMilestoneIssuesSchema, GetGroupMilestoneMergeRequestsSchema, GetGroupMilestoneBurndownEventsSchema, GetNamespaceSchema, GetPipelineJobOutputSchema, PipelineJobControlSchema, GetPipelineSchema, GetProjectEventsSchema, GetProjectMilestoneSchema, GetProjectSchema, GetReleaseSchema, GetRepositoryTreeSchema, GetTagSchema, GetTagSignatureSchema, GetTimelineEventsSchema, GetUsersSchema, GetUserSchema, WhoAmISchema, GetWebhookEventSchema, GetWikiPageSchema, GetWorkItemSchema, ListBranchesSchema, ListCommitsSchema, ListCommitStatusesSchema, ListCustomFieldDefinitionsSchema, ListDeploymentsSchema, ListDraftNotesSchema, ListEnvironmentsSchema, ListEventsSchema, ListGroupIterationsSchema, ListGroupMilestonesSchema, ListGroupProjectsSchema, ListGroupWikiPagesSchema, ListIssueDiscussionsSchema, ListIssueLinksSchema, ListIssuesSchema, ListJobArtifactsSchema, ListLabelsSchema, ListMergeRequestChangedFilesSchema, ListMergeRequestDiffsSchema, ListMergeRequestDiscussionsSchema, ListMergeRequestPipelinesSchema, ListMergeRequestVersionsSchema, ListMergeRequestsSchema, ListNamespacesSchema, ListPipelineJobsSchema, ListPipelineTriggerJobsSchema, ValidateCiLintSchema, ValidateProjectCiLintSchema, ListCiCatalogResourcesSchema, GetCiCatalogResourceSchema, ListPipelinesSchema, ListProjectMembersSchema, ListProjectMilestonesSchema, ListProjectsSchema, ListReleasesSchema, ListTagsSchema, ListWebhookEventsSchema, ListWebhooksSchema, ListWikiPagesSchema, ListWorkItemNotesSchema, ListWorkItemStatusesSchema, ListWorkItemsSchema, MarkdownUploadSchema, MarkdownUploadRemoteSchema, MergeMergeRequestSchema, MoveWorkItemSchema, MyIssuesSchema, PlayPipelineJobSchema, PromoteProjectMilestoneSchema, PublishDraftNoteSchema, PushFilesSchema, ResolveMergeRequestThreadSchema, RetryPipelineJobSchema, RetryPipelineSchema, SearchCodeSchema, SearchGroupCodeSchema, SearchProjectCodeSchema, SearchRepositoriesSchema, UnapproveMergeRequestSchema, UpdateDraftNoteSchema, UpdateGroupWikiPageSchema, UpdateIssueNoteSchema, UpdateIssueSchema, UpdateIssueDescriptionPatchSchema, UpdateLabelSchema, UpdateProjectSchema, UpdateMergeRequestDiscussionNoteSchema, UpdateMergeRequestNoteSchema, UpdateMergeRequestSchema, UpdateReleaseSchema, UpdateWikiPageSchema, UpdateWorkItemSchema, VerifyNamespaceSchema, ListProjectVariablesSchema, GetProjectVariableSchema, CreateProjectVariableSchema, UpdateProjectVariableSchema, DeleteProjectVariableSchema, ListGroupVariablesSchema, GetGroupVariableSchema, CreateGroupVariableSchema, UpdateGroupVariableSchema, DeleteGroupVariableSchema, GetDependencyProxySettingsSchema, UpdateDependencyProxySettingsSchema, ListDependencyProxyBlobsSchema, PurgeDependencyProxyCacheSchema, } from "../schemas.js";
5
5
  const IS_REMOTE = SSE || STREAMABLE_HTTP;
6
6
  // Define all available tools
7
7
  export const allTools = [
@@ -703,6 +703,46 @@ export const allTools = [
703
703
  description: "Get burndown events for a specific milestone",
704
704
  inputSchema: toJSONSchema(GetMilestoneBurndownEventsSchema),
705
705
  },
706
+ {
707
+ name: "list_group_milestones",
708
+ description: "List group milestones with filtering options",
709
+ inputSchema: toJSONSchema(ListGroupMilestonesSchema),
710
+ },
711
+ {
712
+ name: "get_group_milestone",
713
+ description: "Get details of a specific group milestone",
714
+ inputSchema: toJSONSchema(GetGroupMilestoneSchema),
715
+ },
716
+ {
717
+ name: "create_group_milestone",
718
+ description: "Create a new group milestone",
719
+ inputSchema: toJSONSchema(CreateGroupMilestoneSchema),
720
+ },
721
+ {
722
+ name: "edit_group_milestone",
723
+ description: "Edit an existing group milestone",
724
+ inputSchema: toJSONSchema(EditGroupMilestoneSchema),
725
+ },
726
+ {
727
+ name: "delete_group_milestone",
728
+ description: "Delete a group milestone",
729
+ inputSchema: toJSONSchema(DeleteGroupMilestoneSchema),
730
+ },
731
+ {
732
+ name: "get_group_milestone_issue",
733
+ description: "Get issues associated with a specific group milestone",
734
+ inputSchema: toJSONSchema(GetGroupMilestoneIssuesSchema),
735
+ },
736
+ {
737
+ name: "get_group_milestone_merge_requests",
738
+ description: "Get merge requests associated with a specific group milestone",
739
+ inputSchema: toJSONSchema(GetGroupMilestoneMergeRequestsSchema),
740
+ },
741
+ {
742
+ name: "get_group_milestone_burndown_events",
743
+ description: "Get burndown events for a specific group milestone",
744
+ inputSchema: toJSONSchema(GetGroupMilestoneBurndownEventsSchema),
745
+ },
706
746
  {
707
747
  name: "get_users",
708
748
  description: "Get GitLab user details by usernames",
@@ -1126,6 +1166,11 @@ export const readOnlyTools = new Set([
1126
1166
  "get_milestone_issue",
1127
1167
  "get_milestone_merge_requests",
1128
1168
  "get_milestone_burndown_events",
1169
+ "list_group_milestones",
1170
+ "get_group_milestone",
1171
+ "get_group_milestone_issue",
1172
+ "get_group_milestone_merge_requests",
1173
+ "get_group_milestone_burndown_events",
1129
1174
  "list_wiki_pages",
1130
1175
  "get_wiki_page",
1131
1176
  "list_group_wiki_pages",
@@ -1181,6 +1226,7 @@ export const destructiveTools = new Set([
1181
1226
  "delete_wiki_page",
1182
1227
  "delete_group_wiki_page",
1183
1228
  "delete_milestone",
1229
+ "delete_group_milestone",
1184
1230
  "delete_release",
1185
1231
  "delete_tag",
1186
1232
  "delete_merge_request_note",
@@ -1209,6 +1255,7 @@ export const deleteTools = new Set([
1209
1255
  "delete_draft_note",
1210
1256
  "delete_group_variable",
1211
1257
  "delete_group_wiki_page",
1258
+ "delete_group_milestone",
1212
1259
  "delete_issue",
1213
1260
  "delete_issue_emoji_reaction",
1214
1261
  "delete_issue_link",
@@ -1252,6 +1299,14 @@ export const milestoneToolNames = new Set([
1252
1299
  "get_milestone_merge_requests",
1253
1300
  "promote_milestone",
1254
1301
  "get_milestone_burndown_events",
1302
+ "list_group_milestones",
1303
+ "get_group_milestone",
1304
+ "create_group_milestone",
1305
+ "edit_group_milestone",
1306
+ "delete_group_milestone",
1307
+ "get_group_milestone_issue",
1308
+ "get_group_milestone_merge_requests",
1309
+ "get_group_milestone_burndown_events",
1255
1310
  ]);
1256
1311
  // Define which tools are related to pipelines and can be toggled by USE_PIPELINE
1257
1312
  export const pipelineToolNames = new Set([
@@ -1471,6 +1526,14 @@ export const TOOLSET_DEFINITIONS = [
1471
1526
  "get_milestone_merge_requests",
1472
1527
  "promote_milestone",
1473
1528
  "get_milestone_burndown_events",
1529
+ "list_group_milestones",
1530
+ "get_group_milestone",
1531
+ "create_group_milestone",
1532
+ "edit_group_milestone",
1533
+ "delete_group_milestone",
1534
+ "get_group_milestone_issue",
1535
+ "get_group_milestone_merge_requests",
1536
+ "get_group_milestone_burndown_events",
1474
1537
  ]),
1475
1538
  },
1476
1539
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zereight/mcp-gitlab",
3
- "version": "2.1.30",
3
+ "version": "2.1.38",
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": [