@zereight/mcp-gitlab 1.0.64 → 1.0.65

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
@@ -36,7 +36,9 @@ When using with the Claude App, you need to set up your API key and URLs directl
36
36
  ```
37
37
 
38
38
  #### Docker
39
+
39
40
  - stdio
41
+
40
42
  ```mcp.json
41
43
  {
42
44
  "mcpServers": {
@@ -74,6 +76,7 @@ When using with the Claude App, you need to set up your API key and URLs directl
74
76
  ```
75
77
 
76
78
  - sse
79
+
77
80
  ```shell
78
81
  docker run -i --rm \
79
82
  -e GITLAB_PERSONAL_ACCESS_TOKEN=your_gitlab_token \
@@ -113,9 +116,12 @@ $ sh scripts/image_push.sh docker_user_name
113
116
  - `USE_PIPELINE`: When set to 'true', enables the pipeline-related tools (list_pipelines, get_pipeline, list_pipeline_jobs, get_pipeline_job, get_pipeline_job_output, create_pipeline, retry_pipeline, cancel_pipeline). By default, pipeline features are disabled.
114
117
  - `GITLAB_AUTH_COOKIE_PATH`: Path to an authentication cookie file for GitLab instances that require cookie-based authentication. When provided, the cookie will be included in all GitLab API requests.
115
118
 
119
+ [![Star History Chart](https://api.star-history.com/svg?repos=zereight/gitlab-mcp&type=Date)](https://www.star-history.com/#zereight/gitlab-mcp&Date)
120
+
116
121
  ## Tools 🛠️
117
122
 
118
123
  +<!-- TOOLS-START -->
124
+
119
125
  1. `create_or_update_file` - Create or update a single file in a GitLab project
120
126
  2. `search_repositories` - Search for GitLab projects
121
127
  3. `create_repository` - Create a new GitLab project
@@ -127,58 +133,59 @@ $ sh scripts/image_push.sh docker_user_name
127
133
  9. `create_branch` - Create a new branch in a GitLab project
128
134
  10. `get_merge_request` - Get details of a merge request (Either mergeRequestIid or branchName must be provided)
129
135
  11. `get_merge_request_diffs` - Get the changes/diffs of a merge request (Either mergeRequestIid or branchName must be provided)
130
- 12. `get_branch_diffs` - Get the changes/diffs between two branches or commits in a GitLab project
131
- 13. `update_merge_request` - Update a merge request (Either mergeRequestIid or branchName must be provided)
132
- 14. `create_note` - Create a new note (comment) to an issue or merge request
133
- 15. `create_merge_request_thread` - Create a new thread on a merge request
134
- 16. `mr_discussions` - List discussion items for a merge request
135
- 17. `update_merge_request_note` - Modify an existing merge request thread note
136
- 18. `create_merge_request_note` - Add a new note to an existing merge request thread
137
- 19. `update_issue_note` - Modify an existing issue thread note
138
- 20. `create_issue_note` - Add a new note to an existing issue thread
139
- 21. `list_issues` - List issues in a GitLab project with filtering options
140
- 22. `get_issue` - Get details of a specific issue in a GitLab project
141
- 23. `update_issue` - Update an issue in a GitLab project
142
- 24. `delete_issue` - Delete an issue from a GitLab project
143
- 25. `list_issue_links` - List all issue links for a specific issue
144
- 26. `list_issue_discussions` - List discussions for an issue in a GitLab project
145
- 27. `get_issue_link` - Get a specific issue link
146
- 28. `create_issue_link` - Create an issue link between two issues
147
- 29. `delete_issue_link` - Delete an issue link
148
- 30. `list_namespaces` - List all namespaces available to the current user
149
- 31. `get_namespace` - Get details of a namespace by ID or path
150
- 32. `verify_namespace` - Verify if a namespace path exists
151
- 33. `get_project` - Get details of a specific project
152
- 34. `list_projects` - List projects accessible by the current user
153
- 35. `list_labels` - List labels for a project
154
- 36. `get_label` - Get a single label from a project
155
- 37. `create_label` - Create a new label in a project
156
- 38. `update_label` - Update an existing label in a project
157
- 39. `delete_label` - Delete a label from a project
158
- 40. `list_group_projects` - List projects in a GitLab group with filtering options
159
- 41. `list_wiki_pages` - List wiki pages in a GitLab project
160
- 42. `get_wiki_page` - Get details of a specific wiki page
161
- 43. `create_wiki_page` - Create a new wiki page in a GitLab project
162
- 44. `update_wiki_page` - Update an existing wiki page in a GitLab project
163
- 45. `delete_wiki_page` - Delete a wiki page from a GitLab project
164
- 46. `get_repository_tree` - Get the repository tree for a GitLab project (list files and directories)
165
- 47. `list_pipelines` - List pipelines in a GitLab project with filtering options
166
- 48. `get_pipeline` - Get details of a specific pipeline in a GitLab project
167
- 49. `list_pipeline_jobs` - List all jobs in a specific pipeline
168
- 50. `get_pipeline_job` - Get details of a GitLab pipeline job number
169
- 51. `get_pipeline_job_output` - Get the output/trace of a GitLab pipeline job number
170
- 52. `create_pipeline` - Create a new pipeline for a branch or tag
171
- 53. `retry_pipeline` - Retry a failed or canceled pipeline
172
- 54. `cancel_pipeline` - Cancel a running pipeline
173
- 55. `list_merge_requests` - List merge requests in a GitLab project with filtering options
174
- 56. `list_milestones` - List milestones in a GitLab project with filtering options
175
- 57. `get_milestone` - Get details of a specific milestone
176
- 58. `create_milestone` - Create a new milestone in a GitLab project
177
- 59. `edit_milestone` - Edit an existing milestone in a GitLab project
178
- 60. `delete_milestone` - Delete a milestone from a GitLab project
179
- 61. `get_milestone_issue` - Get issues associated with a specific milestone
180
- 62. `get_milestone_merge_requests` - Get merge requests associated with a specific milestone
181
- 63. `promote_milestone` - Promote a milestone to the next stage
182
- 64. `get_milestone_burndown_events` - Get burndown events for a specific milestone
183
- 65. `get_users` - Get GitLab user details by usernames
136
+ 12. `list_merge_request_diffs` - List merge request diffs with pagination support (Either mergeRequestIid or branchName must be provided)
137
+ 13. `get_branch_diffs` - Get the changes/diffs between two branches or commits in a GitLab project
138
+ 14. `update_merge_request` - Update a merge request (Either mergeRequestIid or branchName must be provided)
139
+ 15. `create_note` - Create a new note (comment) to an issue or merge request
140
+ 16. `create_merge_request_thread` - Create a new thread on a merge request
141
+ 17. `mr_discussions` - List discussion items for a merge request
142
+ 18. `update_merge_request_note` - Modify an existing merge request thread note
143
+ 19. `create_merge_request_note` - Add a new note to an existing merge request thread
144
+ 20. `update_issue_note` - Modify an existing issue thread note
145
+ 21. `create_issue_note` - Add a new note to an existing issue thread
146
+ 22. `list_issues` - List issues in a GitLab project with filtering options
147
+ 23. `get_issue` - Get details of a specific issue in a GitLab project
148
+ 24. `update_issue` - Update an issue in a GitLab project
149
+ 25. `delete_issue` - Delete an issue from a GitLab project
150
+ 26. `list_issue_links` - List all issue links for a specific issue
151
+ 27. `list_issue_discussions` - List discussions for an issue in a GitLab project
152
+ 28. `get_issue_link` - Get a specific issue link
153
+ 29. `create_issue_link` - Create an issue link between two issues
154
+ 30. `delete_issue_link` - Delete an issue link
155
+ 31. `list_namespaces` - List all namespaces available to the current user
156
+ 32. `get_namespace` - Get details of a namespace by ID or path
157
+ 33. `verify_namespace` - Verify if a namespace path exists
158
+ 34. `get_project` - Get details of a specific project
159
+ 35. `list_projects` - List projects accessible by the current user
160
+ 36. `list_labels` - List labels for a project
161
+ 37. `get_label` - Get a single label from a project
162
+ 38. `create_label` - Create a new label in a project
163
+ 39. `update_label` - Update an existing label in a project
164
+ 40. `delete_label` - Delete a label from a project
165
+ 41. `list_group_projects` - List projects in a GitLab group with filtering options
166
+ 42. `list_wiki_pages` - List wiki pages in a GitLab project
167
+ 43. `get_wiki_page` - Get details of a specific wiki page
168
+ 44. `create_wiki_page` - Create a new wiki page in a GitLab project
169
+ 45. `update_wiki_page` - Update an existing wiki page in a GitLab project
170
+ 46. `delete_wiki_page` - Delete a wiki page from a GitLab project
171
+ 47. `get_repository_tree` - Get the repository tree for a GitLab project (list files and directories)
172
+ 48. `list_pipelines` - List pipelines in a GitLab project with filtering options
173
+ 49. `get_pipeline` - Get details of a specific pipeline in a GitLab project
174
+ 50. `list_pipeline_jobs` - List all jobs in a specific pipeline
175
+ 51. `get_pipeline_job` - Get details of a GitLab pipeline job number
176
+ 52. `get_pipeline_job_output` - Get the output/trace of a GitLab pipeline job number
177
+ 53. `create_pipeline` - Create a new pipeline for a branch or tag
178
+ 54. `retry_pipeline` - Retry a failed or canceled pipeline
179
+ 55. `cancel_pipeline` - Cancel a running pipeline
180
+ 56. `list_merge_requests` - List merge requests in a GitLab project with filtering options
181
+ 57. `list_milestones` - List milestones in a GitLab project with filtering options
182
+ 58. `get_milestone` - Get details of a specific milestone
183
+ 59. `create_milestone` - Create a new milestone in a GitLab project
184
+ 60. `edit_milestone` - Edit an existing milestone in a GitLab project
185
+ 61. `delete_milestone` - Delete a milestone from a GitLab project
186
+ 62. `get_milestone_issue` - Get issues associated with a specific milestone
187
+ 63. `get_milestone_merge_requests` - Get merge requests associated with a specific milestone
188
+ 64. `promote_milestone` - Promote a milestone to the next stage
189
+ 65. `get_milestone_burndown_events` - Get burndown events for a specific milestone
190
+ 66. `get_users` - Get GitLab user details by usernames
184
191
  <!-- TOOLS-END -->
package/build/index.js CHANGED
@@ -27,7 +27,7 @@ GetPipelineJobOutputSchema, GitLabPipelineJobSchema,
27
27
  GitLabDiscussionNoteSchema, // Added
28
28
  GitLabDiscussionSchema, PaginatedDiscussionsResponseSchema, UpdateMergeRequestNoteSchema, // Added
29
29
  CreateMergeRequestNoteSchema, // Added
30
- ListMergeRequestDiscussionsSchema, UpdateIssueNoteSchema, CreateIssueNoteSchema, ListMergeRequestsSchema, GitLabMilestonesSchema, ListProjectMilestonesSchema, GetProjectMilestoneSchema, CreateProjectMilestoneSchema, EditProjectMilestoneSchema, DeleteProjectMilestoneSchema, GetMilestoneIssuesSchema, GetMilestoneMergeRequestsSchema, PromoteProjectMilestoneSchema, GetMilestoneBurndownEventsSchema, GitLabCompareResultSchema, GetBranchDiffsSchema, } from "./schemas.js";
30
+ ListMergeRequestDiscussionsSchema, UpdateIssueNoteSchema, CreateIssueNoteSchema, ListMergeRequestsSchema, GitLabMilestonesSchema, ListProjectMilestonesSchema, GetProjectMilestoneSchema, CreateProjectMilestoneSchema, EditProjectMilestoneSchema, DeleteProjectMilestoneSchema, GetMilestoneIssuesSchema, GetMilestoneMergeRequestsSchema, PromoteProjectMilestoneSchema, GetMilestoneBurndownEventsSchema, GitLabCompareResultSchema, GetBranchDiffsSchema, ListCommitsSchema, GetCommitSchema, GetCommitDiffSchema, ListMergeRequestDiffsSchema, } from "./schemas.js";
31
31
  /**
32
32
  * Read version from package.json
33
33
  */
@@ -242,6 +242,11 @@ const allTools = [
242
242
  description: "Get the changes/diffs of a merge request (Either mergeRequestIid or branchName must be provided)",
243
243
  inputSchema: zodToJsonSchema(GetMergeRequestDiffsSchema),
244
244
  },
245
+ {
246
+ name: "list_merge_request_diffs",
247
+ description: "List merge request diffs with pagination support (Either mergeRequestIid or branchName must be provided)",
248
+ inputSchema: zodToJsonSchema(ListMergeRequestDiffsSchema),
249
+ },
245
250
  {
246
251
  name: "get_branch_diffs",
247
252
  description: "Get the changes/diffs between two branches or commits in a GitLab project",
@@ -512,6 +517,21 @@ const allTools = [
512
517
  description: "Get GitLab user details by usernames",
513
518
  inputSchema: zodToJsonSchema(GetUsersSchema),
514
519
  },
520
+ {
521
+ name: "list_commits",
522
+ description: "List repository commits with filtering options",
523
+ inputSchema: zodToJsonSchema(ListCommitsSchema),
524
+ },
525
+ {
526
+ name: "get_commit",
527
+ description: "Get details of a specific commit",
528
+ inputSchema: zodToJsonSchema(GetCommitSchema),
529
+ },
530
+ {
531
+ name: "get_commit_diff",
532
+ description: "Get changes/diffs of a specific commit",
533
+ inputSchema: zodToJsonSchema(GetCommitDiffSchema),
534
+ },
515
535
  ];
516
536
  // Define which tools are read-only
517
537
  const readOnlyTools = [
@@ -549,6 +569,9 @@ const readOnlyTools = [
549
569
  "list_wiki_pages",
550
570
  "get_wiki_page",
551
571
  "get_users",
572
+ "list_commits",
573
+ "get_commit",
574
+ "get_commit_diff",
552
575
  ];
553
576
  // Define which tools are related to wiki and can be toggled by USE_GITLAB_WIKI
554
577
  const wikiToolNames = [
@@ -1456,6 +1479,41 @@ async function getMergeRequestDiffs(projectId, mergeRequestIid, branchName, view
1456
1479
  const data = (await response.json());
1457
1480
  return z.array(GitLabDiffSchema).parse(data.changes);
1458
1481
  }
1482
+ /**
1483
+ * Get merge request changes with detailed information including commits, diff_refs, and more
1484
+ * 마지막으로 추가된 상세한 MR 변경사항 조회 함수 (Detailed merge request changes retrieval function)
1485
+ *
1486
+ * @param {string} projectId - The ID or URL-encoded path of the project
1487
+ * @param {number} mergeRequestIid - The internal ID of the merge request (Either mergeRequestIid or branchName must be provided)
1488
+ * @param {string} [branchName] - The name of the branch to search for merge request by branch name (Either mergeRequestIid or branchName must be provided)
1489
+ * @param {boolean} [unidiff] - Return diff in unidiff format
1490
+ * @returns {Promise<any>} The complete merge request changes response
1491
+ */
1492
+ async function listMergeRequestDiffs(projectId, mergeRequestIid, branchName, page, perPage, unidiff) {
1493
+ projectId = decodeURIComponent(projectId); // Decode project ID
1494
+ if (!mergeRequestIid && !branchName) {
1495
+ throw new Error("Either mergeRequestIid or branchName must be provided");
1496
+ }
1497
+ if (branchName && !mergeRequestIid) {
1498
+ const mergeRequest = await getMergeRequest(projectId, undefined, branchName);
1499
+ mergeRequestIid = mergeRequest.iid;
1500
+ }
1501
+ const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/merge_requests/${mergeRequestIid}/diffs`);
1502
+ if (page) {
1503
+ url.searchParams.append("page", page.toString());
1504
+ }
1505
+ if (perPage) {
1506
+ url.searchParams.append("per_page", perPage.toString());
1507
+ }
1508
+ if (unidiff) {
1509
+ url.searchParams.append("unidiff", "true");
1510
+ }
1511
+ const response = await fetch(url.toString(), {
1512
+ ...DEFAULT_FETCH_CONFIG,
1513
+ });
1514
+ await handleGitLabError(response);
1515
+ return await response.json(); // Return full response including commits, diff_refs, changes, etc.
1516
+ }
1459
1517
  /**
1460
1518
  * Get branch comparison diffs
1461
1519
  *
@@ -2395,6 +2453,89 @@ async function getUsers(usernames) {
2395
2453
  }
2396
2454
  return GitLabUsersResponseSchema.parse(users);
2397
2455
  }
2456
+ /**
2457
+ * List repository commits
2458
+ * 저장소 커밋 목록 조회
2459
+ *
2460
+ * @param {string} projectId - Project ID or URL-encoded path
2461
+ * @param {ListCommitsOptions} options - List commits options
2462
+ * @returns {Promise<GitLabCommit[]>} List of commits
2463
+ */
2464
+ async function listCommits(projectId, options = {}) {
2465
+ projectId = decodeURIComponent(projectId);
2466
+ const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/repository/commits`);
2467
+ // Add query parameters
2468
+ if (options.ref_name)
2469
+ url.searchParams.append("ref_name", options.ref_name);
2470
+ if (options.since)
2471
+ url.searchParams.append("since", options.since);
2472
+ if (options.until)
2473
+ url.searchParams.append("until", options.until);
2474
+ if (options.path)
2475
+ url.searchParams.append("path", options.path);
2476
+ if (options.author)
2477
+ url.searchParams.append("author", options.author);
2478
+ if (options.all)
2479
+ url.searchParams.append("all", options.all.toString());
2480
+ if (options.with_stats)
2481
+ url.searchParams.append("with_stats", options.with_stats.toString());
2482
+ if (options.first_parent)
2483
+ url.searchParams.append("first_parent", options.first_parent.toString());
2484
+ if (options.order)
2485
+ url.searchParams.append("order", options.order);
2486
+ if (options.trailers)
2487
+ url.searchParams.append("trailers", options.trailers.toString());
2488
+ if (options.page)
2489
+ url.searchParams.append("page", options.page.toString());
2490
+ if (options.per_page)
2491
+ url.searchParams.append("per_page", options.per_page.toString());
2492
+ const response = await fetch(url.toString(), {
2493
+ ...DEFAULT_FETCH_CONFIG,
2494
+ });
2495
+ await handleGitLabError(response);
2496
+ const data = await response.json();
2497
+ return z.array(GitLabCommitSchema).parse(data);
2498
+ }
2499
+ /**
2500
+ * Get a single commit
2501
+ * 단일 커밋 정보 조회
2502
+ *
2503
+ * @param {string} projectId - Project ID or URL-encoded path
2504
+ * @param {string} sha - The commit hash or name of a repository branch or tag
2505
+ * @param {boolean} [stats] - Include commit stats
2506
+ * @returns {Promise<GitLabCommit>} The commit details
2507
+ */
2508
+ async function getCommit(projectId, sha, stats) {
2509
+ projectId = decodeURIComponent(projectId);
2510
+ const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/repository/commits/${encodeURIComponent(sha)}`);
2511
+ if (stats) {
2512
+ url.searchParams.append("stats", "true");
2513
+ }
2514
+ const response = await fetch(url.toString(), {
2515
+ ...DEFAULT_FETCH_CONFIG,
2516
+ });
2517
+ await handleGitLabError(response);
2518
+ const data = await response.json();
2519
+ return GitLabCommitSchema.parse(data);
2520
+ }
2521
+ /**
2522
+ * Get commit diff
2523
+ * 커밋 변경사항 조회
2524
+ *
2525
+ * @param {string} projectId - Project ID or URL-encoded path
2526
+ * @param {string} sha - The commit hash or name of a repository branch or tag
2527
+ * @returns {Promise<GitLabMergeRequestDiff[]>} The commit diffs
2528
+ */
2529
+ async function getCommitDiff(projectId, sha) {
2530
+ projectId = decodeURIComponent(projectId);
2531
+ const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/repository/commits/${encodeURIComponent(sha)}/diff`);
2532
+ const response = await fetch(url.toString(), {
2533
+ ...DEFAULT_FETCH_CONFIG,
2534
+ });
2535
+ await handleGitLabError(response);
2536
+ const data = await response.json();
2537
+ return z.array(GitLabDiffSchema).parse(data);
2538
+ }
2398
2539
  server.setRequestHandler(ListToolsRequestSchema, async () => {
2399
2540
  // Apply read-only filter first
2400
2541
  const tools0 = GITLAB_READ_ONLY_MODE
@@ -2591,6 +2732,13 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
2591
2732
  content: [{ type: "text", text: JSON.stringify(diffs, null, 2) }],
2592
2733
  };
2593
2734
  }
2735
+ case "list_merge_request_diffs": {
2736
+ const args = ListMergeRequestDiffsSchema.parse(request.params.arguments);
2737
+ const changes = await listMergeRequestDiffs(args.project_id, args.merge_request_iid, args.source_branch, args.page, args.per_page, args.unidiff);
2738
+ return {
2739
+ content: [{ type: "text", text: JSON.stringify(changes, null, 2) }],
2740
+ };
2741
+ }
2594
2742
  case "update_merge_request": {
2595
2743
  const args = UpdateMergeRequestSchema.parse(request.params.arguments);
2596
2744
  const { project_id, merge_request_iid, source_branch, ...options } = args;
@@ -3088,6 +3236,27 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
3088
3236
  ],
3089
3237
  };
3090
3238
  }
3239
+ case "list_commits": {
3240
+ const args = ListCommitsSchema.parse(request.params.arguments);
3241
+ const commits = await listCommits(args.project_id, args);
3242
+ return {
3243
+ content: [{ type: "text", text: JSON.stringify(commits, null, 2) }],
3244
+ };
3245
+ }
3246
+ case "get_commit": {
3247
+ const args = GetCommitSchema.parse(request.params.arguments);
3248
+ const commit = await getCommit(args.project_id, args.sha, args.stats);
3249
+ return {
3250
+ content: [{ type: "text", text: JSON.stringify(commit, null, 2) }],
3251
+ };
3252
+ }
3253
+ case "get_commit_diff": {
3254
+ const args = GetCommitDiffSchema.parse(request.params.arguments);
3255
+ const diff = await getCommitDiff(args.project_id, args.sha);
3256
+ return {
3257
+ content: [{ type: "text", text: JSON.stringify(diff, null, 2) }],
3258
+ };
3259
+ }
3091
3260
  default:
3092
3261
  throw new Error(`Unknown tool: ${request.params.name}`);
3093
3262
  }
package/build/schemas.js CHANGED
@@ -374,8 +374,17 @@ export const GitLabCommitSchema = z.object({
374
374
  committer_name: z.string(),
375
375
  committer_email: z.string(),
376
376
  committed_date: z.string(),
377
+ created_at: z.string().optional(), // Add created_at field
378
+ message: z.string().optional(), // Add full message field
377
379
  web_url: z.string(), // Changed from html_url to match GitLab API
378
380
  parent_ids: z.array(z.string()), // Changed from parents to match GitLab API
381
+ stats: z.object({
382
+ additions: z.number().optional().nullable(),
383
+ deletions: z.number().optional().nullable(),
384
+ total: z.number().optional().nullable(),
385
+ }).optional(), // Only present when with_stats=true
386
+ trailers: z.record(z.string()).optional().default({}), // Git trailers, may be empty object
387
+ extended_trailers: z.record(z.array(z.string())).optional().default({}), // Extended trailers, may be empty object
379
388
  });
380
389
  // Reference schema
381
390
  export const GitLabReferenceSchema = z.object({
@@ -596,6 +605,20 @@ export const GitLabMergeRequestSchema = z.object({
596
605
  squash: z.boolean().optional(),
597
606
  labels: z.array(z.string()).optional(),
598
607
  });
608
+ export const LineRangeSchema = z.object({
609
+ start: z.object({
610
+ line_code: z.string().nullable().optional().describe("CRITICAL: Line identifier in format '{file_path_sha1_hash}_{old_line_number}_{new_line_number}'. USUALLY REQUIRED for GitLab diff comments despite being optional in schema. Example: 'a1b2c3d4e5f6_10_15'. Get this from GitLab diff API response, never fabricate."),
611
+ type: z.enum(["new", "old"]).nullable().optional().describe("Line type: 'old' = deleted/original line, 'new' = added/modified line, null = unchanged context. MUST match the line_code format and old_line/new_line values."),
612
+ old_line: z.number().nullable().optional().describe("Line number in original file (before changes). REQUIRED when type='old', NULL when type='new' (for purely added lines), can be present for context lines."),
613
+ new_line: z.number().nullable().optional().describe("Line number in modified file (after changes). REQUIRED when type='new', NULL when type='old' (for purely deleted lines), can be present for context lines."),
614
+ }).describe("Start line position for multiline comment range. MUST specify either old_line OR new_line (or both for context), never neither."),
615
+ end: z.object({
616
+ line_code: z.string().nullable().optional().describe("CRITICAL: Line identifier in format '{file_path_sha1_hash}_{old_line_number}_{new_line_number}'. USUALLY REQUIRED for GitLab diff comments despite being optional in schema. Example: 'a1b2c3d4e5f6_12_17'. Must be from same file as start.line_code."),
617
+ type: z.enum(["new", "old"]).nullable().optional().describe("Line type: 'old' = deleted/original line, 'new' = added/modified line, null = unchanged context. SHOULD MATCH start.type for consistent ranges (don't mix old/new types)."),
618
+ old_line: z.number().nullable().optional().describe("Line number in original file (before changes). REQUIRED when type='old', NULL when type='new' (for purely added lines), can be present for context lines. MUST be >= start.old_line if both specified."),
619
+ new_line: z.number().nullable().optional().describe("Line number in modified file (after changes). REQUIRED when type='new', NULL when type='old' (for purely deleted lines), can be present for context lines. MUST be >= start.new_line if both specified."),
620
+ }).describe("End line position for multiline comment range. MUST specify either old_line OR new_line (or both for context), never neither. Range must be valid (end >= start)."),
621
+ }).describe("Line range for multiline comments on GitLab merge request diffs. VALIDATION RULES: 1) line_code is critical for GitLab API success, 2) start/end must have consistent types, 3) line numbers must form valid range, 4) get line_code from GitLab diff API, never generate manually.");
599
622
  // Discussion related schemas
600
623
  export const GitLabDiscussionNoteSchema = z.object({
601
624
  id: z.number(),
@@ -620,24 +643,24 @@ export const GitLabDiscussionNoteSchema = z.object({
620
643
  base_sha: z.string(),
621
644
  start_sha: z.string(),
622
645
  head_sha: z.string(),
623
- old_path: z.string(),
624
- new_path: z.string(),
646
+ old_path: z.string().optional().describe("File path before change"),
647
+ new_path: z.string().optional().describe("File path after change"),
625
648
  position_type: z.enum(["text", "image", "file"]),
626
- old_line: z.number().nullish(), // This is missing for image diffs
627
- new_line: z.number().nullish(), // This is missing for image diffs
649
+ new_line: z.number().nullable().optional().describe("Line number in the modified file (after changes). Used for added lines and context lines. Null for deleted lines."),
650
+ old_line: z.number().nullable().optional().describe("Line number in the original file (before changes). Used for deleted lines and context lines. Null for newly added lines."),
628
651
  line_range: z
629
652
  .object({
630
653
  start: z.object({
631
- line_code: z.string(),
654
+ line_code: z.string().nullable().optional().describe("Line identifier in format: '{file_path_sha1_hash}_{old_line_number}_{new_line_number}'. Used to uniquely identify a specific line in the diff."),
632
655
  type: z.enum(["new", "old", "expanded"]),
633
- old_line: z.number().nullish(), // This is missing for image diffs
634
- new_line: z.number().nullish(), // This is missing for image diffs
656
+ old_line: z.number().nullable().optional().describe("Line number in the original file (before changes). Null for newly added lines or unchanged context lines."),
657
+ new_line: z.number().nullable().optional().describe("Line number in the modified file (after changes). Null for deleted lines or unchanged context lines."),
635
658
  }),
636
659
  end: z.object({
637
- line_code: z.string(),
660
+ line_code: z.string().nullable().optional().describe("Line identifier in format: '{file_path_sha1_hash}_{old_line_number}_{new_line_number}'. Used to uniquely identify a specific line in the diff."),
638
661
  type: z.enum(["new", "old", "expanded"]),
639
- old_line: z.number().nullish(), // This is missing for image diffs
640
- new_line: z.number().nullish(), // This is missing for image diffs
662
+ old_line: z.number().nullable().optional().describe("Line number in the original file (before changes). Null for newly added lines or unchanged context lines."),
663
+ new_line: z.number().nullable().optional().describe("Line number in the modified file (after changes). Null for deleted lines or unchanged context lines."),
641
664
  }),
642
665
  })
643
666
  .nullable()
@@ -818,6 +841,11 @@ export const UpdateMergeRequestSchema = GetMergeRequestSchema.extend({
818
841
  export const GetMergeRequestDiffsSchema = GetMergeRequestSchema.extend({
819
842
  view: z.enum(["inline", "parallel"]).optional().describe("Diff view type"),
820
843
  });
844
+ export const ListMergeRequestDiffsSchema = GetMergeRequestSchema.extend({
845
+ page: z.number().optional().describe("Page number for pagination (default: 1)"),
846
+ per_page: z.number().optional().describe("Number of items per page (max: 100, default: 20)"),
847
+ unidiff: z.boolean().optional().describe("Present diffs in the unified diff format. Default is false. Introduced in GitLab 16.5."),
848
+ });
821
849
  export const CreateNoteSchema = z.object({
822
850
  project_id: z.string().describe("Project ID or namespace/project_path"),
823
851
  noteable_type: z
@@ -1124,18 +1152,19 @@ export const GitLabWikiPageSchema = z.object({
1124
1152
  });
1125
1153
  // Merge Request Thread position schema - used for diff notes
1126
1154
  export const MergeRequestThreadPositionSchema = z.object({
1127
- base_sha: z.string().describe("Base commit SHA in the source branch"),
1128
- head_sha: z.string().describe("SHA referencing HEAD of the source branch"),
1129
- start_sha: z.string().describe("SHA referencing the start commit of the source branch"),
1130
- position_type: z.enum(["text", "image", "file"]).describe("Type of position reference"),
1131
- new_path: z.string().optional().describe("File path after change"),
1132
- old_path: z.string().optional().describe("File path before change"),
1133
- new_line: z.number().nullable().optional().describe("Line number after change"),
1134
- old_line: z.number().nullable().optional().describe("Line number before change"),
1135
- width: z.number().optional().describe("Width of the image (for image diffs)"),
1136
- height: z.number().optional().describe("Height of the image (for image diffs)"),
1137
- x: z.number().optional().describe("X coordinate on the image (for image diffs)"),
1138
- y: z.number().optional().describe("Y coordinate on the image (for image diffs)"),
1155
+ base_sha: z.string().describe("REQUIRED: Base commit SHA in the source branch. Get this from merge request diff_refs.base_sha."),
1156
+ head_sha: z.string().describe("REQUIRED: SHA referencing HEAD of the source branch. Get this from merge request diff_refs.head_sha."),
1157
+ start_sha: z.string().describe("REQUIRED: SHA referencing the start commit of the source branch. Get this from merge request diff_refs.start_sha."),
1158
+ position_type: z.enum(["text", "image", "file"]).describe("REQUIRED: Position type. Use 'text' for code diffs, 'image' for image diffs, 'file' for file-level comments."),
1159
+ new_path: z.string().optional().describe("File path after changes. REQUIRED for most diff comments. Use same as old_path if file wasn't renamed."),
1160
+ old_path: z.string().optional().describe("File path before changes. REQUIRED for most diff comments. Use same as new_path if file wasn't renamed."),
1161
+ new_line: z.number().nullable().optional().describe("Line number in modified file (after changes). Use for added lines or context lines. NULL for deleted lines. For single-line comments on new lines."),
1162
+ old_line: z.number().nullable().optional().describe("Line number in original file (before changes). Use for deleted lines or context lines. NULL for added lines. For single-line comments on old lines."),
1163
+ line_range: LineRangeSchema.optional().describe("MULTILINE COMMENTS: Specify start/end line positions for commenting on multiple lines. Alternative to single old_line/new_line."),
1164
+ width: z.number().optional().describe("IMAGE DIFFS ONLY: Width of the image (for position_type='image')."),
1165
+ height: z.number().optional().describe("IMAGE DIFFS ONLY: Height of the image (for position_type='image')."),
1166
+ x: z.number().optional().describe("IMAGE DIFFS ONLY: X coordinate on the image (for position_type='image')."),
1167
+ y: z.number().optional().describe("IMAGE DIFFS ONLY: Y coordinate on the image (for position_type='image')."),
1139
1168
  });
1140
1169
  // Schema for creating a new merge request thread
1141
1170
  export const CreateMergeRequestThreadSchema = ProjectParamsSchema.extend({
@@ -1202,3 +1231,28 @@ export const GetMilestoneMergeRequestsSchema = GetProjectMilestoneSchema.merge(P
1202
1231
  export const PromoteProjectMilestoneSchema = GetProjectMilestoneSchema;
1203
1232
  // Schema for getting burndown chart events for a milestone
1204
1233
  export const GetMilestoneBurndownEventsSchema = GetProjectMilestoneSchema.merge(PaginationOptionsSchema);
1234
+ // Add schemas for commit operations
1235
+ export const ListCommitsSchema = z.object({
1236
+ project_id: z.string().describe("Project ID or complete URL-encoded path to project"),
1237
+ ref_name: z.string().optional().describe("The name of a repository branch, tag or revision range, or if not given the default branch"),
1238
+ since: z.string().optional().describe("Only commits after or on this date are returned in ISO 8601 format YYYY-MM-DDTHH:MM:SSZ"),
1239
+ until: z.string().optional().describe("Only commits before or on this date are returned in ISO 8601 format YYYY-MM-DDTHH:MM:SSZ"),
1240
+ path: z.string().optional().describe("The file path"),
1241
+ author: z.string().optional().describe("Search commits by commit author"),
1242
+ all: z.boolean().optional().describe("Retrieve every commit from the repository"),
1243
+ with_stats: z.boolean().optional().describe("Stats about each commit are added to the response"),
1244
+ first_parent: z.boolean().optional().describe("Follow only the first parent commit upon seeing a merge commit"),
1245
+ order: z.enum(["default", "topo"]).optional().describe("List commits in order"),
1246
+ trailers: z.boolean().optional().describe("Parse and include Git trailers for every commit"),
1247
+ page: z.number().optional().describe("Page number for pagination (default: 1)"),
1248
+ per_page: z.number().optional().describe("Number of items per page (max: 100, default: 20)"),
1249
+ });
1250
+ export const GetCommitSchema = z.object({
1251
+ project_id: z.string().describe("Project ID or complete URL-encoded path to project"),
1252
+ sha: z.string().describe("The commit hash or name of a repository branch or tag"),
1253
+ stats: z.boolean().optional().describe("Include commit stats"),
1254
+ });
1255
+ export const GetCommitDiffSchema = z.object({
1256
+ project_id: z.string().describe("Project ID or complete URL-encoded path to project"),
1257
+ sha: z.string().describe("The commit hash or name of a repository branch or tag"),
1258
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zereight/mcp-gitlab",
3
- "version": "1.0.64",
3
+ "version": "1.0.65",
4
4
  "description": "MCP server for using the GitLab API",
5
5
  "license": "MIT",
6
6
  "author": "zereight",