Skip to content

Commit 23b0348

Browse files
author
Nicholas Crum
committed
feat: Add create_merge_request_thread tool for diff notes
- Implement new tool for creating MR threads with positioning support - Create schemas to handle diff notes with file and line number positions - Support optional created_at timestamp parameter - Update README with the new tool information
1 parent 95ad321 commit 23b0348

File tree

3 files changed

+130
-27
lines changed

3 files changed

+130
-27
lines changed

README.md

Lines changed: 28 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -55,31 +55,32 @@ When using with the Claude App, you need to set up your API key and URLs directl
5555
11. `get_merge_request_diffs` - Get the changes/diffs of a merge request (Either mergeRequestIid or branchName must be provided)
5656
12. `update_merge_request` - Update a merge request (Either mergeRequestIid or branchName must be provided)
5757
13. `create_note` - Create a new note (comment) to an issue or merge request
58-
14. `mr_discussions` - List discussion items for a merge request
59-
15. `update_merge_request_note` - Modify an existing merge request thread note
60-
16. `list_issues` - List issues in a GitLab project with filtering options
61-
17. `get_issue` - Get details of a specific issue in a GitLab project
62-
18. `update_issue` - Update an issue in a GitLab project
63-
19. `delete_issue` - Delete an issue from a GitLab project
64-
20. `list_issue_links` - List all issue links for a specific issue
65-
21. `get_issue_link` - Get a specific issue link
66-
22. `create_issue_link` - Create an issue link between two issues
67-
23. `delete_issue_link` - Delete an issue link
68-
24. `list_namespaces` - List all namespaces available to the current user
69-
25. `get_namespace` - Get details of a namespace by ID or path
70-
26. `verify_namespace` - Verify if a namespace path exists
71-
27. `get_project` - Get details of a specific project
72-
28. `list_projects` - List projects accessible by the current user
73-
29. `list_labels` - List labels for a project
74-
30. `get_label` - Get a single label from a project
75-
31. `create_label` - Create a new label in a project
76-
32. `update_label` - Update an existing label in a project
77-
33. `delete_label` - Delete a label from a project
78-
34. `list_group_projects` - List projects in a GitLab group with filtering options
79-
35. `list_wiki_pages` - List wiki pages in a GitLab project
80-
36. `get_wiki_page` - Get details of a specific wiki page
81-
37. `create_wiki_page` - Create a new wiki page in a GitLab project
82-
38. `update_wiki_page` - Update an existing wiki page in a GitLab project
83-
39. `delete_wiki_page` - Delete a wiki page from a GitLab project
84-
40. `get_repository_tree` - Get the repository tree for a GitLab project (list files and directories)
58+
14. `create_merge_request_thread` - Create a new thread on a merge request
59+
15. `mr_discussions` - List discussion items for a merge request
60+
16. `update_merge_request_note` - Modify an existing merge request thread note
61+
17. `list_issues` - List issues in a GitLab project with filtering options
62+
18. `get_issue` - Get details of a specific issue in a GitLab project
63+
19. `update_issue` - Update an issue in a GitLab project
64+
20. `delete_issue` - Delete an issue from a GitLab project
65+
21. `list_issue_links` - List all issue links for a specific issue
66+
22. `get_issue_link` - Get a specific issue link
67+
23. `create_issue_link` - Create an issue link between two issues
68+
24. `delete_issue_link` - Delete an issue link
69+
25. `list_namespaces` - List all namespaces available to the current user
70+
26. `get_namespace` - Get details of a namespace by ID or path
71+
27. `verify_namespace` - Verify if a namespace path exists
72+
28. `get_project` - Get details of a specific project
73+
29. `list_projects` - List projects accessible by the current user
74+
30. `list_labels` - List labels for a project
75+
31. `get_label` - Get a single label from a project
76+
32. `create_label` - Create a new label in a project
77+
33. `update_label` - Update an existing label in a project
78+
34. `delete_label` - Delete a label from a project
79+
35. `list_group_projects` - List projects in a GitLab group with filtering options
80+
36. `list_wiki_pages` - List wiki pages in a GitLab project
81+
37. `get_wiki_page` - Get details of a specific wiki page
82+
38. `create_wiki_page` - Create a new wiki page in a GitLab project
83+
39. `update_wiki_page` - Update an existing wiki page in a GitLab project
84+
40. `delete_wiki_page` - Delete a wiki page from a GitLab project
85+
41. `get_repository_tree` - Get the repository tree for a GitLab project (list files and directories)
8586
<!-- TOOLS-END -->

index.ts

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ import {
7575
UpdateLabelSchema,
7676
DeleteLabelSchema,
7777
CreateNoteSchema,
78+
CreateMergeRequestThreadSchema,
7879
ListGroupProjectsSchema,
7980
ListWikiPagesSchema,
8081
GetWikiPageSchema,
@@ -108,6 +109,7 @@ import {
108109
// Discussion Types
109110
type GitLabDiscussionNote, // Added
110111
type GitLabDiscussion,
112+
type MergeRequestThreadPosition,
111113
type GetWikiPageOptions,
112114
type CreateWikiPageOptions,
113115
type UpdateWikiPageOptions,
@@ -263,6 +265,11 @@ const allTools = [
263265
description: "Create a new note (comment) to an issue or merge request",
264266
inputSchema: zodToJsonSchema(CreateNoteSchema),
265267
},
268+
{
269+
name: "create_merge_request_thread",
270+
description: "Create a new thread on a merge request",
271+
inputSchema: zodToJsonSchema(CreateMergeRequestThreadSchema),
272+
},
266273
{
267274
name: "mr_discussions",
268275
description: "List discussion items for a merge request",
@@ -1520,6 +1527,59 @@ async function createNote(
15201527
return await response.json();
15211528
}
15221529

1530+
/**
1531+
* Create a new thread on a merge request
1532+
* 📦 새로운 함수: createMergeRequestThread - 병합 요청에 새로운 스레드(토론)를 생성하는 함수
1533+
* (New function: createMergeRequestThread - Function to create a new thread (discussion) on a merge request)
1534+
*
1535+
* This function provides more capabilities than createNote, including the ability to:
1536+
* - Create diff notes (comments on specific lines of code)
1537+
* - Specify exact positions for comments
1538+
* - Set creation timestamps
1539+
*
1540+
* @param {string} projectId - The ID or URL-encoded path of the project
1541+
* @param {number} mergeRequestIid - The internal ID of the merge request
1542+
* @param {string} body - The content of the thread
1543+
* @param {MergeRequestThreadPosition} [position] - Position information for diff notes
1544+
* @param {string} [createdAt] - ISO 8601 formatted creation date
1545+
* @returns {Promise<GitLabDiscussion>} The created discussion thread
1546+
*/
1547+
async function createMergeRequestThread(
1548+
projectId: string,
1549+
mergeRequestIid: number,
1550+
body: string,
1551+
position?: MergeRequestThreadPosition,
1552+
createdAt?: string
1553+
): Promise<GitLabDiscussion> {
1554+
projectId = decodeURIComponent(projectId); // Decode project ID
1555+
const url = new URL(
1556+
`${GITLAB_API_URL}/projects/${encodeURIComponent(
1557+
projectId
1558+
)}/merge_requests/${mergeRequestIid}/discussions`
1559+
);
1560+
1561+
const payload: Record<string, any> = { body };
1562+
1563+
// Add optional parameters if provided
1564+
if (position) {
1565+
payload.position = position;
1566+
}
1567+
1568+
if (createdAt) {
1569+
payload.created_at = createdAt;
1570+
}
1571+
1572+
const response = await fetch(url.toString(), {
1573+
...DEFAULT_FETCH_CONFIG,
1574+
method: "POST",
1575+
body: JSON.stringify(payload),
1576+
});
1577+
1578+
await handleGitLabError(response);
1579+
const data = await response.json();
1580+
return GitLabDiscussionSchema.parse(data);
1581+
}
1582+
15231583
/**
15241584
* List all namespaces
15251585
* 사용 가능한 모든 네임스페이스 목록 조회
@@ -2454,6 +2514,22 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
24542514
};
24552515
}
24562516

2517+
case "create_merge_request_thread": {
2518+
const args = CreateMergeRequestThreadSchema.parse(request.params.arguments);
2519+
const { project_id, merge_request_iid, body, position, created_at } = args;
2520+
2521+
const thread = await createMergeRequestThread(
2522+
project_id,
2523+
merge_request_iid,
2524+
body,
2525+
position,
2526+
created_at
2527+
);
2528+
return {
2529+
content: [{ type: "text", text: JSON.stringify(thread, null, 2) }],
2530+
};
2531+
}
2532+
24572533
case "list_issues": {
24582534
const args = ListIssuesSchema.parse(request.params.arguments);
24592535
const { project_id, ...options } = args;

schemas.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1004,6 +1004,30 @@ export const GitLabWikiPageSchema = z.object({
10041004
updated_at: z.string().optional(),
10051005
});
10061006

1007+
// Merge Request Thread position schema - used for diff notes
1008+
export const MergeRequestThreadPositionSchema = z.object({
1009+
base_sha: z.string().describe("Base commit SHA in the source branch"),
1010+
head_sha: z.string().describe("SHA referencing HEAD of the source branch"),
1011+
start_sha: z.string().describe("SHA referencing the start commit of the source branch"),
1012+
position_type: z.enum(["text", "image", "file"]).describe("Type of position reference"),
1013+
new_path: z.string().optional().describe("File path after change"),
1014+
old_path: z.string().optional().describe("File path before change"),
1015+
new_line: z.number().nullable().optional().describe("Line number after change"),
1016+
old_line: z.number().nullable().optional().describe("Line number before change"),
1017+
width: z.number().optional().describe("Width of the image (for image diffs)"),
1018+
height: z.number().optional().describe("Height of the image (for image diffs)"),
1019+
x: z.number().optional().describe("X coordinate on the image (for image diffs)"),
1020+
y: z.number().optional().describe("Y coordinate on the image (for image diffs)"),
1021+
});
1022+
1023+
// Schema for creating a new merge request thread
1024+
export const CreateMergeRequestThreadSchema = ProjectParamsSchema.extend({
1025+
merge_request_iid: z.number().describe("The IID of a merge request"),
1026+
body: z.string().describe("The content of the thread"),
1027+
position: MergeRequestThreadPositionSchema.optional().describe("Position when creating a diff note"),
1028+
created_at: z.string().optional().describe("Date the thread was created at (ISO 8601 format)"),
1029+
});
1030+
10071031
// Export types
10081032
export type GitLabAuthor = z.infer<typeof GitLabAuthorSchema>;
10091033
export type GitLabFork = z.infer<typeof GitLabForkSchema>;
@@ -1053,3 +1077,5 @@ export type DeleteWikiPageOptions = z.infer<typeof DeleteWikiPageSchema>;
10531077
export type GitLabWikiPage = z.infer<typeof GitLabWikiPageSchema>;
10541078
export type GitLabTreeItem = z.infer<typeof GitLabTreeItemSchema>;
10551079
export type GetRepositoryTreeOptions = z.infer<typeof GetRepositoryTreeSchema>;
1080+
export type MergeRequestThreadPosition = z.infer<typeof MergeRequestThreadPositionSchema>;
1081+
export type CreateMergeRequestThreadOptions = z.infer<typeof CreateMergeRequestThreadSchema>;

0 commit comments

Comments
 (0)