@zereight/mcp-gitlab 1.0.22 → 1.0.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/build/index.js CHANGED
@@ -9,7 +9,11 @@ import { fileURLToPath } from "url";
9
9
  import { dirname } from "path";
10
10
  import fs from "fs";
11
11
  import path from "path";
12
- import { GitLabForkSchema, GitLabReferenceSchema, GitLabRepositorySchema, GitLabIssueSchema, GitLabMergeRequestSchema, GitLabContentSchema, GitLabCreateUpdateFileResponseSchema, GitLabSearchResponseSchema, GitLabTreeSchema, GitLabCommitSchema, GitLabNamespaceSchema, GitLabNamespaceExistsResponseSchema, GitLabProjectSchema, CreateOrUpdateFileSchema, SearchRepositoriesSchema, CreateRepositorySchema, GetFileContentsSchema, PushFilesSchema, CreateIssueSchema, CreateMergeRequestSchema, ForkRepositorySchema, CreateBranchSchema, GitLabMergeRequestDiffSchema, GetMergeRequestSchema, GetMergeRequestDiffsSchema, UpdateMergeRequestSchema, ListIssuesSchema, GetIssueSchema, UpdateIssueSchema, DeleteIssueSchema, GitLabIssueLinkSchema, GitLabIssueWithLinkDetailsSchema, ListIssueLinksSchema, GetIssueLinkSchema, CreateIssueLinkSchema, DeleteIssueLinkSchema, ListNamespacesSchema, GetNamespaceSchema, VerifyNamespaceSchema, GetProjectSchema, ListProjectsSchema, ListLabelsSchema, GetLabelSchema, CreateLabelSchema, UpdateLabelSchema, DeleteLabelSchema, CreateNoteSchema, ListGroupProjectsSchema, } from "./schemas.js";
12
+ import { GitLabForkSchema, GitLabReferenceSchema, GitLabRepositorySchema, GitLabIssueSchema, GitLabMergeRequestSchema, GitLabContentSchema, GitLabCreateUpdateFileResponseSchema, GitLabSearchResponseSchema, GitLabTreeSchema, GitLabCommitSchema, GitLabNamespaceSchema, GitLabNamespaceExistsResponseSchema, GitLabProjectSchema, CreateOrUpdateFileSchema, SearchRepositoriesSchema, CreateRepositorySchema, GetFileContentsSchema, PushFilesSchema, CreateIssueSchema, CreateMergeRequestSchema, ForkRepositorySchema, CreateBranchSchema, GitLabMergeRequestDiffSchema, GetMergeRequestSchema, GetMergeRequestDiffsSchema, UpdateMergeRequestSchema, ListIssuesSchema, GetIssueSchema, UpdateIssueSchema, DeleteIssueSchema, GitLabIssueLinkSchema, GitLabIssueWithLinkDetailsSchema, ListIssueLinksSchema, GetIssueLinkSchema, CreateIssueLinkSchema, DeleteIssueLinkSchema, ListNamespacesSchema, GetNamespaceSchema, VerifyNamespaceSchema, GetProjectSchema, ListProjectsSchema, ListLabelsSchema, GetLabelSchema, CreateLabelSchema, UpdateLabelSchema, DeleteLabelSchema, CreateNoteSchema, ListGroupProjectsSchema,
13
+ // Discussion Schemas
14
+ GitLabDiscussionNoteSchema, // Added
15
+ GitLabDiscussionSchema, UpdateMergeRequestNoteSchema, // Added
16
+ ListMergeRequestDiscussionsSchema, } from "./schemas.js";
13
17
  /**
14
18
  * Read version from package.json
15
19
  */
@@ -56,12 +60,6 @@ function normalizeGitLabApiUrl(url) {
56
60
  }
57
61
  // Use the normalizeGitLabApiUrl function to handle various URL formats
58
62
  const GITLAB_API_URL = normalizeGitLabApiUrl(process.env.GITLAB_API_URL || "");
59
- // Add debug logging for API URL construction
60
- console.log("=== MCP Server Configuration ===");
61
- console.log(`GITLAB_API_URL = "${GITLAB_API_URL}"`);
62
- console.log(`Example project API URL = "${GITLAB_API_URL}/projects/123"`);
63
- console.log(`Example Notes API URL = "${GITLAB_API_URL}/projects/123/issues/1/notes"`);
64
- console.log("===============================");
65
63
  if (!GITLAB_PERSONAL_ACCESS_TOKEN) {
66
64
  console.error("GITLAB_PERSONAL_ACCESS_TOKEN environment variable is not set");
67
65
  process.exit(1);
@@ -417,6 +415,51 @@ async function createMergeRequest(projectId, options) {
417
415
  const data = await response.json();
418
416
  return GitLabMergeRequestSchema.parse(data);
419
417
  }
418
+ /**
419
+ * List merge request discussion items
420
+ * 병합 요청 토론 목록 조회
421
+ *
422
+ * @param {string} projectId - The ID or URL-encoded path of the project
423
+ * @param {number} mergeRequestIid - The IID of a merge request
424
+ * @returns {Promise<GitLabDiscussion[]>} List of discussions
425
+ */
426
+ async function listMergeRequestDiscussions(projectId, mergeRequestIid) {
427
+ const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/merge_requests/${mergeRequestIid}/discussions`);
428
+ const response = await fetch(url.toString(), {
429
+ headers: DEFAULT_HEADERS,
430
+ });
431
+ await handleGitLabError(response);
432
+ const data = await response.json();
433
+ // Ensure the response is parsed as an array of discussions
434
+ return z.array(GitLabDiscussionSchema).parse(data);
435
+ }
436
+ /**
437
+ * Modify an existing merge request thread note
438
+ * 병합 요청 토론 노트 수정
439
+ *
440
+ * @param {string} projectId - The ID or URL-encoded path of the project
441
+ * @param {number} mergeRequestIid - The IID of a merge request
442
+ * @param {string} discussionId - The ID of a thread
443
+ * @param {number} noteId - The ID of a thread note
444
+ * @param {string} body - The new content of the note
445
+ * @param {boolean} [resolved] - Resolve/unresolve state
446
+ * @returns {Promise<GitLabDiscussionNote>} The updated note
447
+ */
448
+ async function updateMergeRequestNote(projectId, mergeRequestIid, discussionId, noteId, body, resolved) {
449
+ const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/merge_requests/${mergeRequestIid}/discussions/${discussionId}/notes/${noteId}`);
450
+ const payload = { body };
451
+ if (resolved !== undefined) {
452
+ payload.resolved = resolved;
453
+ }
454
+ const response = await fetch(url.toString(), {
455
+ method: "PUT",
456
+ headers: DEFAULT_HEADERS,
457
+ body: JSON.stringify(payload),
458
+ });
459
+ await handleGitLabError(response);
460
+ const data = await response.json();
461
+ return GitLabDiscussionNoteSchema.parse(data);
462
+ }
420
463
  /**
421
464
  * Create or update a file in a GitLab project
422
465
  * 파일 생성 또는 업데이트
@@ -1077,6 +1120,16 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
1077
1120
  description: "Create a new note (comment) to an issue or merge request",
1078
1121
  inputSchema: zodToJsonSchema(CreateNoteSchema),
1079
1122
  },
1123
+ {
1124
+ name: "list_merge_request_discussions",
1125
+ description: "List discussion items for a merge request",
1126
+ inputSchema: zodToJsonSchema(ListMergeRequestDiscussionsSchema),
1127
+ },
1128
+ {
1129
+ name: "update_merge_request_note",
1130
+ description: "Modify an existing merge request thread note",
1131
+ inputSchema: zodToJsonSchema(UpdateMergeRequestNoteSchema),
1132
+ },
1080
1133
  {
1081
1134
  name: "list_issues",
1082
1135
  description: "List issues in a GitLab project with filtering options",
@@ -1269,6 +1322,14 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
1269
1322
  ],
1270
1323
  };
1271
1324
  }
1325
+ case "update_merge_request_note": {
1326
+ const args = UpdateMergeRequestNoteSchema.parse(request.params.arguments);
1327
+ const note = await updateMergeRequestNote(args.project_id, args.merge_request_iid, args.discussion_id, args.note_id, args.body, args.resolved // Pass resolved if provided
1328
+ );
1329
+ return {
1330
+ content: [{ type: "text", text: JSON.stringify(note, null, 2) }],
1331
+ };
1332
+ }
1272
1333
  case "get_merge_request": {
1273
1334
  const args = GetMergeRequestSchema.parse(request.params.arguments);
1274
1335
  const mergeRequest = await getMergeRequest(args.project_id, args.merge_request_iid);
@@ -1295,6 +1356,15 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
1295
1356
  ],
1296
1357
  };
1297
1358
  }
1359
+ case "list_merge_request_discussions": {
1360
+ const args = ListMergeRequestDiscussionsSchema.parse(request.params.arguments);
1361
+ const discussions = await listMergeRequestDiscussions(args.project_id, args.merge_request_iid);
1362
+ return {
1363
+ content: [
1364
+ { type: "text", text: JSON.stringify(discussions, null, 2) },
1365
+ ],
1366
+ };
1367
+ }
1298
1368
  case "list_namespaces": {
1299
1369
  const args = ListNamespacesSchema.parse(request.params.arguments);
1300
1370
  const url = new URL(`${GITLAB_API_URL}/namespaces`);
package/build/schemas.js CHANGED
@@ -6,6 +6,10 @@ export const GitLabAuthorSchema = z.object({
6
6
  date: z.string(),
7
7
  });
8
8
  // Namespace related schemas
9
+ // Base schema for project-related operations
10
+ const ProjectParamsSchema = z.object({
11
+ project_id: z.string().describe("Project ID or URL-encoded path"), // Changed from owner/repo to match GitLab API
12
+ });
9
13
  export const GitLabNamespaceSchema = z.object({
10
14
  id: z.number(),
11
15
  name: z.string(),
@@ -324,10 +328,71 @@ export const GitLabMergeRequestSchema = z.object({
324
328
  squash: z.boolean().optional(),
325
329
  labels: z.array(z.string()).optional(),
326
330
  });
327
- // API Operation Parameter Schemas
328
- const ProjectParamsSchema = z.object({
329
- project_id: z.string().describe("Project ID or URL-encoded path"), // Changed from owner/repo to match GitLab API
331
+ // Discussion related schemas
332
+ export const GitLabDiscussionNoteSchema = z.object({
333
+ id: z.number(),
334
+ type: z.enum(["DiscussionNote", "DiffNote", "Note"]).nullable(), // Allow null type for regular notes
335
+ body: z.string(),
336
+ attachment: z.any().nullable(), // Can be string or object, handle appropriately
337
+ author: GitLabUserSchema,
338
+ created_at: z.string(),
339
+ updated_at: z.string(),
340
+ system: z.boolean(),
341
+ noteable_id: z.number(),
342
+ noteable_type: z.enum(["Issue", "MergeRequest", "Snippet", "Commit", "Epic"]),
343
+ project_id: z.number().optional(), // Optional for group-level discussions like Epics
344
+ noteable_iid: z.number().nullable(),
345
+ resolvable: z.boolean().optional(),
346
+ resolved: z.boolean().optional(),
347
+ resolved_by: GitLabUserSchema.nullable().optional(),
348
+ resolved_at: z.string().nullable().optional(),
349
+ position: z.object({
350
+ base_sha: z.string(),
351
+ start_sha: z.string(),
352
+ head_sha: z.string(),
353
+ old_path: z.string(),
354
+ new_path: z.string(),
355
+ position_type: z.enum(["text", "image", "file"]),
356
+ old_line: z.number().nullable(),
357
+ new_line: z.number().nullable(),
358
+ line_range: z.object({
359
+ start: z.object({
360
+ line_code: z.string(),
361
+ type: z.enum(["new", "old"]),
362
+ old_line: z.number().nullable(),
363
+ new_line: z.number().nullable(),
364
+ }),
365
+ end: z.object({
366
+ line_code: z.string(),
367
+ type: z.enum(["new", "old"]),
368
+ old_line: z.number().nullable(),
369
+ new_line: z.number().nullable(),
370
+ }),
371
+ }).nullable().optional(), // For multi-line diff notes
372
+ width: z.number().optional(), // For image diff notes
373
+ height: z.number().optional(), // For image diff notes
374
+ x: z.number().optional(), // For image diff notes
375
+ y: z.number().optional(), // For image diff notes
376
+ }).optional(),
377
+ });
378
+ export const GitLabDiscussionSchema = z.object({
379
+ id: z.string(),
380
+ individual_note: z.boolean(),
381
+ notes: z.array(GitLabDiscussionNoteSchema),
330
382
  });
383
+ // Input schema for listing merge request discussions
384
+ export const ListMergeRequestDiscussionsSchema = ProjectParamsSchema.extend({
385
+ merge_request_iid: z.number().describe("The IID of a merge request"),
386
+ });
387
+ // Input schema for updating a merge request discussion note
388
+ export const UpdateMergeRequestNoteSchema = ProjectParamsSchema.extend({
389
+ merge_request_iid: z.number().describe("The IID of a merge request"),
390
+ discussion_id: z.string().describe("The ID of a thread"),
391
+ note_id: z.number().describe("The ID of a thread note"),
392
+ body: z.string().describe("The content of the note or reply"),
393
+ resolved: z.boolean().optional().describe("Resolve or unresolve the note"), // Optional based on API docs
394
+ });
395
+ // API Operation Parameter Schemas
331
396
  export const CreateOrUpdateFileSchema = ProjectParamsSchema.extend({
332
397
  file_path: z.string().describe("Path where to create/update the file"),
333
398
  content: z.string().describe("Content of the file"),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zereight/mcp-gitlab",
3
- "version": "1.0.22",
3
+ "version": "1.0.24",
4
4
  "description": "MCP server for using the GitLab API",
5
5
  "license": "MIT",
6
6
  "author": "zereight",