@zereight/mcp-gitlab 1.0.47 → 1.0.48

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.md CHANGED
@@ -52,7 +52,7 @@ When using with the Claude App, you need to set up your API key and URLs directl
52
52
  "GITLAB_READ_ONLY_MODE",
53
53
  "-e",
54
54
  "USE_GITLAB_WIKI",
55
- "nkwd/gitlab-mcp"
55
+ "iwakitakuma/gitlab-mcp"
56
56
  ],
57
57
  "env": {
58
58
  "GITLAB_PERSONAL_ACCESS_TOKEN": "your_gitlab_token",
@@ -65,6 +65,12 @@ When using with the Claude App, you need to set up your API key and URLs directl
65
65
  }
66
66
  ```
67
67
 
68
+ #### Docker Image Push
69
+
70
+ ```shell
71
+ $ sh scripts/image_push.sh docker_user_name
72
+ ```
73
+
68
74
  ### Environment Variables
69
75
 
70
76
  - `GITLAB_PERSONAL_ACCESS_TOKEN`: Your GitLab personal access token.
@@ -126,4 +132,13 @@ When using with the Claude App, you need to set up your API key and URLs directl
126
132
  49. `get_pipeline_job` - Get details of a GitLab pipeline job number
127
133
  50. `get_pipeline_job_output` - Get the output/trace of a GitLab pipeline job number
128
134
  51. `list_merge_requests` - List merge requests in a GitLab project with filtering options
135
+ 52. `list_milestones` - List milestones in a GitLab project with filtering options
136
+ 53. `get_milestone` - Get details of a specific milestone
137
+ 54. `create_milestone` - Create a new milestone in a GitLab project
138
+ 55. `edit_milestone ` - Edit an existing milestone in a GitLab project
139
+ 56. `delete_milestone` - Delete a milestone from a GitLab project
140
+ 57. `get_milestone_issue` - Get issues associated with a specific milestone
141
+ 58. `get_milestone_merge_requests` - Get merge requests associated with a specific milestone
142
+ 59. `promote_milestone` - Promote a milestone to the next stage
143
+ 60. `get_milestone_burndown_events` - Get burndown events for a specific milestone
129
144
  <!-- TOOLS-END -->
package/build/index.js CHANGED
@@ -20,7 +20,7 @@ GetPipelineJobOutputSchema, GitLabPipelineJobSchema,
20
20
  GitLabDiscussionNoteSchema, // Added
21
21
  GitLabDiscussionSchema, UpdateMergeRequestNoteSchema, // Added
22
22
  CreateMergeRequestNoteSchema, // Added
23
- ListMergeRequestDiscussionsSchema, UpdateIssueNoteSchema, CreateIssueNoteSchema, ListMergeRequestsSchema, } from "./schemas.js";
23
+ ListMergeRequestDiscussionsSchema, UpdateIssueNoteSchema, CreateIssueNoteSchema, ListMergeRequestsSchema, GitLabMilestonesSchema, ListProjectMilestonesSchema, GetProjectMilestoneSchema, CreateProjectMilestoneSchema, EditProjectMilestoneSchema, DeleteProjectMilestoneSchema, GetMilestoneIssuesSchema, GetMilestoneMergeRequestsSchema, PromoteProjectMilestoneSchema, GetMilestoneBurndownEventsSchema, } from "./schemas.js";
24
24
  /**
25
25
  * Read version from package.json
26
26
  */
@@ -343,6 +343,51 @@ const allTools = [
343
343
  description: "List merge requests in a GitLab project with filtering options",
344
344
  inputSchema: zodToJsonSchema(ListMergeRequestsSchema),
345
345
  },
346
+ {
347
+ name: "list_milestones",
348
+ description: "List milestones in a GitLab project with filtering options",
349
+ inputSchema: zodToJsonSchema(ListProjectMilestonesSchema),
350
+ },
351
+ {
352
+ name: "get_milestone",
353
+ description: "Get details of a specific milestone",
354
+ inputSchema: zodToJsonSchema(GetProjectMilestoneSchema),
355
+ },
356
+ {
357
+ name: "create_milestone",
358
+ description: "Create a new milestone in a GitLab project",
359
+ inputSchema: zodToJsonSchema(CreateProjectMilestoneSchema),
360
+ },
361
+ {
362
+ name: "edit_milestone ",
363
+ description: "Edit an existing milestone in a GitLab project",
364
+ inputSchema: zodToJsonSchema(EditProjectMilestoneSchema),
365
+ },
366
+ {
367
+ name: "delete_milestone",
368
+ description: "Delete a milestone from a GitLab project",
369
+ inputSchema: zodToJsonSchema(DeleteProjectMilestoneSchema),
370
+ },
371
+ {
372
+ name: "get_milestone_issue",
373
+ description: "Get issues associated with a specific milestone",
374
+ inputSchema: zodToJsonSchema(GetMilestoneIssuesSchema),
375
+ },
376
+ {
377
+ name: "get_milestone_merge_requests",
378
+ description: "Get merge requests associated with a specific milestone",
379
+ inputSchema: zodToJsonSchema(GetMilestoneMergeRequestsSchema),
380
+ },
381
+ {
382
+ name: "promote_milestone",
383
+ description: "Promote a milestone to the next stage",
384
+ inputSchema: zodToJsonSchema(PromoteProjectMilestoneSchema),
385
+ },
386
+ {
387
+ name: "get_milestone_burndown_events",
388
+ description: "Get burndown events for a specific milestone",
389
+ inputSchema: zodToJsonSchema(GetMilestoneBurndownEventsSchema),
390
+ },
346
391
  ];
347
392
  // Define which tools are read-only
348
393
  const readOnlyTools = [
@@ -371,6 +416,11 @@ const readOnlyTools = [
371
416
  "get_label",
372
417
  "list_group_projects",
373
418
  "get_repository_tree",
419
+ "list_milestones",
420
+ "get_milestone",
421
+ "get_milestone_issue",
422
+ "get_milestone_merge_requests",
423
+ "get_milestone_burndown_events"
374
424
  ];
375
425
  // Define which tools are related to wiki and can be toggled by USE_GITLAB_WIKI
376
426
  const wikiToolNames = [
@@ -1830,6 +1880,167 @@ async function getRepositoryTree(options) {
1830
1880
  const data = await response.json();
1831
1881
  return z.array(GitLabTreeItemSchema).parse(data);
1832
1882
  }
1883
+ /**
1884
+ * List project milestones in a GitLab project
1885
+ * @param {string} projectId - The ID or URL-encoded path of the project
1886
+ * @param {Object} options - Options for listing milestones
1887
+ * @returns {Promise<GitLabMilestones[]>} List of milestones
1888
+ */
1889
+ async function listProjectMilestones(projectId, options) {
1890
+ projectId = decodeURIComponent(projectId);
1891
+ const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/milestones`);
1892
+ Object.entries(options).forEach(([key, value]) => {
1893
+ if (value !== undefined) {
1894
+ if (key === "iids" && Array.isArray(value) && value.length > 0) {
1895
+ value.forEach((iid) => {
1896
+ url.searchParams.append("iids[]", iid.toString());
1897
+ });
1898
+ }
1899
+ else if (value !== undefined) {
1900
+ url.searchParams.append(key, value.toString());
1901
+ }
1902
+ }
1903
+ });
1904
+ const response = await fetch(url.toString(), {
1905
+ ...DEFAULT_FETCH_CONFIG,
1906
+ });
1907
+ await handleGitLabError(response);
1908
+ const data = await response.json();
1909
+ return z.array(GitLabMilestonesSchema).parse(data);
1910
+ }
1911
+ /**
1912
+ * Get a single milestone in a GitLab project
1913
+ * @param {string} projectId - The ID or URL-encoded path of the project
1914
+ * @param {number} milestoneId - The ID of the milestone
1915
+ * @returns {Promise<GitLabMilestones>} Milestone details
1916
+ */
1917
+ async function getProjectMilestone(projectId, milestoneId) {
1918
+ projectId = decodeURIComponent(projectId);
1919
+ const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/milestones/${milestoneId}`);
1920
+ const response = await fetch(url.toString(), {
1921
+ ...DEFAULT_FETCH_CONFIG,
1922
+ });
1923
+ await handleGitLabError(response);
1924
+ const data = await response.json();
1925
+ return GitLabMilestonesSchema.parse(data);
1926
+ }
1927
+ /**
1928
+ * Create a new milestone in a GitLab project
1929
+ * @param {string} projectId - The ID or URL-encoded path of the project
1930
+ * @param {Object} options - Options for creating a milestone
1931
+ * @returns {Promise<GitLabMilestones>} Created milestone
1932
+ */
1933
+ async function createProjectMilestone(projectId, options) {
1934
+ projectId = decodeURIComponent(projectId);
1935
+ const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/milestones`);
1936
+ const response = await fetch(url.toString(), {
1937
+ ...DEFAULT_FETCH_CONFIG,
1938
+ method: "POST",
1939
+ body: JSON.stringify(options),
1940
+ });
1941
+ await handleGitLabError(response);
1942
+ const data = await response.json();
1943
+ return GitLabMilestonesSchema.parse(data);
1944
+ }
1945
+ /**
1946
+ * Edit an existing milestone in a GitLab project
1947
+ * @param {string} projectId - The ID or URL-encoded path of the project
1948
+ * @param {number} milestoneId - The ID of the milestone
1949
+ * @param {Object} options - Options for editing a milestone
1950
+ * @returns {Promise<GitLabMilestones>} Updated milestone
1951
+ */
1952
+ async function editProjectMilestone(projectId, milestoneId, options) {
1953
+ projectId = decodeURIComponent(projectId);
1954
+ const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/milestones/${milestoneId}`);
1955
+ const response = await fetch(url.toString(), {
1956
+ ...DEFAULT_FETCH_CONFIG,
1957
+ method: "PUT",
1958
+ body: JSON.stringify(options),
1959
+ });
1960
+ await handleGitLabError(response);
1961
+ const data = await response.json();
1962
+ return GitLabMilestonesSchema.parse(data);
1963
+ }
1964
+ /**
1965
+ * Delete a milestone from a GitLab project
1966
+ * @param {string} projectId - The ID or URL-encoded path of the project
1967
+ * @param {number} milestoneId - The ID of the milestone
1968
+ * @returns {Promise<void>}
1969
+ */
1970
+ async function deleteProjectMilestone(projectId, milestoneId) {
1971
+ projectId = decodeURIComponent(projectId);
1972
+ const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/milestones/${milestoneId}`);
1973
+ const response = await fetch(url.toString(), {
1974
+ ...DEFAULT_FETCH_CONFIG,
1975
+ method: "DELETE",
1976
+ });
1977
+ await handleGitLabError(response);
1978
+ }
1979
+ /**
1980
+ * Get all issues assigned to a single milestone
1981
+ * @param {string} projectId - The ID or URL-encoded path of the project
1982
+ * @param {number} milestoneId - The ID of the milestone
1983
+ * @returns {Promise<GitLabIssue[]>} List of issues
1984
+ */
1985
+ async function getMilestoneIssues(projectId, milestoneId) {
1986
+ projectId = decodeURIComponent(projectId);
1987
+ const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/milestones/${milestoneId}/issues`);
1988
+ const response = await fetch(url.toString(), {
1989
+ ...DEFAULT_FETCH_CONFIG,
1990
+ });
1991
+ await handleGitLabError(response);
1992
+ const data = await response.json();
1993
+ return z.array(GitLabIssueSchema).parse(data);
1994
+ }
1995
+ /**
1996
+ * Get all merge requests assigned to a single milestone
1997
+ * @param {string} projectId - The ID or URL-encoded path of the project
1998
+ * @param {number} milestoneId - The ID of the milestone
1999
+ * @returns {Promise<GitLabMergeRequest[]>} List of merge requests
2000
+ */
2001
+ async function getMilestoneMergeRequests(projectId, milestoneId) {
2002
+ projectId = decodeURIComponent(projectId);
2003
+ const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/milestones/${milestoneId}/merge_requests`);
2004
+ const response = await fetch(url.toString(), {
2005
+ ...DEFAULT_FETCH_CONFIG,
2006
+ });
2007
+ await handleGitLabError(response);
2008
+ const data = await response.json();
2009
+ return z.array(GitLabMergeRequestSchema).parse(data);
2010
+ }
2011
+ /**
2012
+ * Promote a project milestone to a group milestone
2013
+ * @param {string} projectId - The ID or URL-encoded path of the project
2014
+ * @param {number} milestoneId - The ID of the milestone
2015
+ * @returns {Promise<GitLabMilestones>} Promoted milestone
2016
+ */
2017
+ async function promoteProjectMilestone(projectId, milestoneId) {
2018
+ projectId = decodeURIComponent(projectId);
2019
+ const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/milestones/${milestoneId}/promote`);
2020
+ const response = await fetch(url.toString(), {
2021
+ ...DEFAULT_FETCH_CONFIG,
2022
+ method: "POST",
2023
+ });
2024
+ await handleGitLabError(response);
2025
+ const data = await response.json();
2026
+ return GitLabMilestonesSchema.parse(data);
2027
+ }
2028
+ /**
2029
+ * Get all burndown chart events for a single milestone
2030
+ * @param {string} projectId - The ID or URL-encoded path of the project
2031
+ * @param {number} milestoneId - The ID of the milestone
2032
+ * @returns {Promise<any[]>} Burndown chart events
2033
+ */
2034
+ async function getMilestoneBurndownEvents(projectId, milestoneId) {
2035
+ projectId = decodeURIComponent(projectId);
2036
+ const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/milestones/${milestoneId}/burndown_events`);
2037
+ const response = await fetch(url.toString(), {
2038
+ ...DEFAULT_FETCH_CONFIG,
2039
+ });
2040
+ await handleGitLabError(response);
2041
+ const data = await response.json();
2042
+ return data;
2043
+ }
1833
2044
  server.setRequestHandler(ListToolsRequestSchema, async () => {
1834
2045
  // Apply read-only filter first
1835
2046
  const tools0 = GITLAB_READ_ONLY_MODE
@@ -2360,6 +2571,117 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
2360
2571
  content: [{ type: "text", text: JSON.stringify(mergeRequests, null, 2) }],
2361
2572
  };
2362
2573
  }
2574
+ case "list_milestones": {
2575
+ const { project_id, ...options } = ListProjectMilestonesSchema.parse(request.params.arguments);
2576
+ const milestones = await listProjectMilestones(project_id, options);
2577
+ return {
2578
+ content: [
2579
+ {
2580
+ type: "text",
2581
+ text: JSON.stringify(milestones, null, 2),
2582
+ },
2583
+ ],
2584
+ };
2585
+ }
2586
+ case "get_milestone": {
2587
+ const { project_id, milestone_id } = GetProjectMilestoneSchema.parse(request.params.arguments);
2588
+ const milestone = await getProjectMilestone(project_id, milestone_id);
2589
+ return {
2590
+ content: [
2591
+ {
2592
+ type: "text",
2593
+ text: JSON.stringify(milestone, null, 2),
2594
+ },
2595
+ ],
2596
+ };
2597
+ }
2598
+ case "create_milestone": {
2599
+ const { project_id, ...options } = CreateProjectMilestoneSchema.parse(request.params.arguments);
2600
+ const milestone = await createProjectMilestone(project_id, options);
2601
+ return {
2602
+ content: [
2603
+ {
2604
+ type: "text",
2605
+ text: JSON.stringify(milestone, null, 2),
2606
+ },
2607
+ ],
2608
+ };
2609
+ }
2610
+ case "edit_milestone": {
2611
+ const { project_id, milestone_id, ...options } = EditProjectMilestoneSchema.parse(request.params.arguments);
2612
+ const milestone = await editProjectMilestone(project_id, milestone_id, options);
2613
+ return {
2614
+ content: [
2615
+ {
2616
+ type: "text",
2617
+ text: JSON.stringify(milestone, null, 2),
2618
+ },
2619
+ ],
2620
+ };
2621
+ }
2622
+ case "delete_milestone": {
2623
+ const { project_id, milestone_id } = DeleteProjectMilestoneSchema.parse(request.params.arguments);
2624
+ await deleteProjectMilestone(project_id, milestone_id);
2625
+ return {
2626
+ content: [
2627
+ {
2628
+ type: "text",
2629
+ text: JSON.stringify({
2630
+ status: "success",
2631
+ message: "Milestone deleted successfully",
2632
+ }, null, 2),
2633
+ },
2634
+ ],
2635
+ };
2636
+ }
2637
+ case "get_milestone_issue": {
2638
+ const { project_id, milestone_id } = GetMilestoneIssuesSchema.parse(request.params.arguments);
2639
+ const issues = await getMilestoneIssues(project_id, milestone_id);
2640
+ return {
2641
+ content: [
2642
+ {
2643
+ type: "text",
2644
+ text: JSON.stringify(issues, null, 2),
2645
+ },
2646
+ ],
2647
+ };
2648
+ }
2649
+ case "get_milestone_merge_requests": {
2650
+ const { project_id, milestone_id } = GetMilestoneMergeRequestsSchema.parse(request.params.arguments);
2651
+ const mergeRequests = await getMilestoneMergeRequests(project_id, milestone_id);
2652
+ return {
2653
+ content: [
2654
+ {
2655
+ type: "text",
2656
+ text: JSON.stringify(mergeRequests, null, 2),
2657
+ },
2658
+ ],
2659
+ };
2660
+ }
2661
+ case "promote_milestone": {
2662
+ const { project_id, milestone_id } = PromoteProjectMilestoneSchema.parse(request.params.arguments);
2663
+ const milestone = await promoteProjectMilestone(project_id, milestone_id);
2664
+ return {
2665
+ content: [
2666
+ {
2667
+ type: "text",
2668
+ text: JSON.stringify(milestone, null, 2),
2669
+ },
2670
+ ],
2671
+ };
2672
+ }
2673
+ case "get_milestone_burndown_events": {
2674
+ const { project_id, milestone_id } = GetMilestoneBurndownEventsSchema.parse(request.params.arguments);
2675
+ const events = await getMilestoneBurndownEvents(project_id, milestone_id);
2676
+ return {
2677
+ content: [
2678
+ {
2679
+ type: "text",
2680
+ text: JSON.stringify(events, null, 2),
2681
+ },
2682
+ ],
2683
+ };
2684
+ }
2363
2685
  default:
2364
2686
  throw new Error(`Unknown tool: ${request.params.name}`);
2365
2687
  }
package/build/schemas.js CHANGED
@@ -306,6 +306,21 @@ export const GitLabReferenceSchema = z.object({
306
306
  web_url: z.string(), // Changed from url to match GitLab API
307
307
  }),
308
308
  });
309
+ // Milestones rest api output schemas
310
+ export const GitLabMilestonesSchema = z.object({
311
+ id: z.number(),
312
+ iid: z.number(),
313
+ project_id: z.number(),
314
+ title: z.string(),
315
+ description: z.string().nullable(),
316
+ due_date: z.string().nullable(),
317
+ start_date: z.string().nullable(),
318
+ state: z.string(),
319
+ updated_at: z.string(),
320
+ created_at: z.string(),
321
+ expired: z.boolean(),
322
+ web_url: z.string().optional()
323
+ });
309
324
  // Input schemas for operations
310
325
  export const CreateRepositoryOptionsSchema = z.object({
311
326
  name: z.string(),
@@ -1162,3 +1177,51 @@ export const CreateMergeRequestThreadSchema = ProjectParamsSchema.extend({
1162
1177
  position: MergeRequestThreadPositionSchema.optional().describe("Position when creating a diff note"),
1163
1178
  created_at: z.string().optional().describe("Date the thread was created at (ISO 8601 format)"),
1164
1179
  });
1180
+ // Milestone related schemas
1181
+ // Schema for listing project milestones
1182
+ export const ListProjectMilestonesSchema = ProjectParamsSchema.extend({
1183
+ iids: z.array(z.number()).optional().describe("Return only the milestones having the given iid"),
1184
+ state: z.enum(["active", "closed"]).optional().describe("Return only active or closed milestones"),
1185
+ title: z.string().optional().describe("Return only milestones with a title matching the provided string"),
1186
+ search: z.string().optional().describe("Return only milestones with a title or description matching the provided string"),
1187
+ include_ancestors: z.boolean().optional().describe("Include ancestor groups"),
1188
+ updated_before: z.string().optional().describe("Return milestones updated before the specified date (ISO 8601 format)"),
1189
+ updated_after: z.string().optional().describe("Return milestones updated after the specified date (ISO 8601 format)"),
1190
+ page: z.number().optional().describe("Page number for pagination"),
1191
+ per_page: z.number().optional().describe("Number of items per page (max 100)"),
1192
+ });
1193
+ // Schema for getting a single milestone
1194
+ export const GetProjectMilestoneSchema = ProjectParamsSchema.extend({
1195
+ milestone_id: z.number().describe("The ID of a project milestone"),
1196
+ });
1197
+ // Schema for creating a new milestone
1198
+ export const CreateProjectMilestoneSchema = ProjectParamsSchema.extend({
1199
+ title: z.string().describe("The title of the milestone"),
1200
+ description: z.string().optional().describe("The description of the milestone"),
1201
+ due_date: z.string().optional().describe("The due date of the milestone (YYYY-MM-DD)"),
1202
+ start_date: z.string().optional().describe("The start date of the milestone (YYYY-MM-DD)"),
1203
+ });
1204
+ // Schema for editing a milestone
1205
+ export const EditProjectMilestoneSchema = GetProjectMilestoneSchema.extend({
1206
+ title: z.string().optional().describe("The title of the milestone"),
1207
+ description: z.string().optional().describe("The description of the milestone"),
1208
+ due_date: z.string().optional().describe("The due date of the milestone (YYYY-MM-DD)"),
1209
+ start_date: z.string().optional().describe("The start date of the milestone (YYYY-MM-DD)"),
1210
+ state_event: z.enum(["close", "activate"]).optional().describe("The state event of the milestone"),
1211
+ });
1212
+ // Schema for deleting a milestone
1213
+ export const DeleteProjectMilestoneSchema = GetProjectMilestoneSchema;
1214
+ // Schema for getting issues assigned to a milestone
1215
+ export const GetMilestoneIssuesSchema = GetProjectMilestoneSchema;
1216
+ // Schema for getting merge requests assigned to a milestone
1217
+ export const GetMilestoneMergeRequestsSchema = GetProjectMilestoneSchema.extend({
1218
+ page: z.number().optional().describe("Page number for pagination"),
1219
+ per_page: z.number().optional().describe("Number of items per page (max 100)"),
1220
+ });
1221
+ // Schema for promoting a project milestone to a group milestone
1222
+ export const PromoteProjectMilestoneSchema = GetProjectMilestoneSchema;
1223
+ // Schema for getting burndown chart events for a milestone
1224
+ export const GetMilestoneBurndownEventsSchema = GetProjectMilestoneSchema.extend({
1225
+ page: z.number().optional().describe("Page number for pagination"),
1226
+ per_page: z.number().optional().describe("Number of items per page (max 100)"),
1227
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zereight/mcp-gitlab",
3
- "version": "1.0.47",
3
+ "version": "1.0.48",
4
4
  "description": "MCP server for using the GitLab API",
5
5
  "license": "MIT",
6
6
  "author": "zereight",