Skip to content

Commit 6acecd2

Browse files
committed
feat: implement list_merge_requests functionality
- Add ListMergeRequestsSchema with comprehensive filtering options - Implement listMergeRequests function following GitLab API - Add tool definition and switch case handler - Include in readOnlyTools array - Update README.md with new tool documentation
1 parent 6f3630b commit 6acecd2

File tree

4 files changed

+137
-2
lines changed

4 files changed

+137
-2
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,4 +125,5 @@ When using with the Claude App, you need to set up your API key and URLs directl
125125
48. `list_pipeline_jobs` - List all jobs in a specific pipeline
126126
49. `get_pipeline_job` - Get details of a GitLab pipeline job number
127127
50. `get_pipeline_job_output` - Get the output/trace of a GitLab pipeline job number
128+
51. `list_merge_requests` - List merge requests in a GitLab project with filtering options
128129
<!-- TOOLS-END -->

index.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ import {
134134
type GetRepositoryTreeOptions,
135135
UpdateIssueNoteSchema,
136136
CreateIssueNoteSchema,
137+
ListMergeRequestsSchema,
137138
} from "./schemas.js";
138139

139140
/**
@@ -466,6 +467,11 @@ const allTools = [
466467
description: "Get the output/trace of a GitLab pipeline job number",
467468
inputSchema: zodToJsonSchema(GetPipelineJobOutputSchema),
468469
},
470+
{
471+
name: "list_merge_requests",
472+
description: "List merge requests in a GitLab project with filtering options",
473+
inputSchema: zodToJsonSchema(ListMergeRequestsSchema),
474+
},
469475
];
470476

471477
// Define which tools are read-only
@@ -476,6 +482,7 @@ const readOnlyTools = [
476482
"get_merge_request_diffs",
477483
"mr_discussions",
478484
"list_issues",
485+
"list_merge_requests",
479486
"get_issue",
480487
"list_issue_links",
481488
"list_issue_discussions",
@@ -791,6 +798,43 @@ async function listIssues(
791798
return z.array(GitLabIssueSchema).parse(data);
792799
}
793800

801+
/**
802+
* List merge requests in a GitLab project with optional filtering
803+
*
804+
* @param {string} projectId - The ID or URL-encoded path of the project
805+
* @param {Object} options - Optional filtering parameters
806+
* @returns {Promise<GitLabMergeRequest[]>} List of merge requests
807+
*/
808+
async function listMergeRequests(
809+
projectId: string,
810+
options: Omit<z.infer<typeof ListMergeRequestsSchema>, "project_id"> = {}
811+
): Promise<GitLabMergeRequest[]> {
812+
projectId = decodeURIComponent(projectId); // Decode project ID
813+
const url = new URL(
814+
`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/merge_requests`
815+
);
816+
817+
// Add all query parameters
818+
Object.entries(options).forEach(([key, value]) => {
819+
if (value !== undefined) {
820+
if (key === "labels" && Array.isArray(value)) {
821+
// Handle array of labels
822+
url.searchParams.append(key, value.join(","));
823+
} else {
824+
url.searchParams.append(key, value.toString());
825+
}
826+
}
827+
});
828+
829+
const response = await fetch(url.toString(), {
830+
...DEFAULT_FETCH_CONFIG,
831+
});
832+
833+
await handleGitLabError(response);
834+
const data = await response.json();
835+
return z.array(GitLabMergeRequestSchema).parse(data);
836+
}
837+
794838
/**
795839
* Get a single issue from a GitLab project
796840
* 단일 이슈 조회
@@ -3300,6 +3344,14 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
33003344
};
33013345
}
33023346

3347+
case "list_merge_requests": {
3348+
const args = ListMergeRequestsSchema.parse(request.params.arguments);
3349+
const mergeRequests = await listMergeRequests(args.project_id, args);
3350+
return {
3351+
content: [{ type: "text", text: JSON.stringify(mergeRequests, null, 2) }],
3352+
};
3353+
}
3354+
33033355
default:
33043356
throw new Error(`Unknown tool: ${request.params.name}`);
33053357
}

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

schemas.ts

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -834,6 +834,88 @@ export const ListIssuesSchema = z.object({
834834
per_page: z.number().optional().describe("Number of items per page"),
835835
});
836836

837+
// Merge Requests API operation schemas
838+
export const ListMergeRequestsSchema = z.object({
839+
project_id: z.string().describe("Project ID or URL-encoded path"),
840+
assignee_id: z
841+
.number()
842+
.optional()
843+
.describe("Returns merge requests assigned to the given user ID"),
844+
assignee_username: z
845+
.string()
846+
.optional()
847+
.describe("Returns merge requests assigned to the given username"),
848+
author_id: z
849+
.number()
850+
.optional()
851+
.describe("Returns merge requests created by the given user ID"),
852+
author_username: z
853+
.string()
854+
.optional()
855+
.describe("Returns merge requests created by the given username"),
856+
reviewer_id: z
857+
.number()
858+
.optional()
859+
.describe("Returns merge requests which have the user as a reviewer"),
860+
reviewer_username: z
861+
.string()
862+
.optional()
863+
.describe("Returns merge requests which have the user as a reviewer"),
864+
created_after: z
865+
.string()
866+
.optional()
867+
.describe("Return merge requests created after the given time"),
868+
created_before: z
869+
.string()
870+
.optional()
871+
.describe("Return merge requests created before the given time"),
872+
updated_after: z
873+
.string()
874+
.optional()
875+
.describe("Return merge requests updated after the given time"),
876+
updated_before: z
877+
.string()
878+
.optional()
879+
.describe("Return merge requests updated before the given time"),
880+
labels: z.array(z.string()).optional().describe("Array of label names"),
881+
milestone: z.string().optional().describe("Milestone title"),
882+
scope: z
883+
.enum(["created_by_me", "assigned_to_me", "all"])
884+
.optional()
885+
.describe("Return merge requests from a specific scope"),
886+
search: z.string().optional().describe("Search for specific terms"),
887+
state: z
888+
.enum(["opened", "closed", "locked", "merged", "all"])
889+
.optional()
890+
.describe("Return merge requests with a specific state"),
891+
order_by: z
892+
.enum(["created_at", "updated_at", "priority", "label_priority", "milestone_due", "popularity"])
893+
.optional()
894+
.describe("Return merge requests ordered by the given field"),
895+
sort: z
896+
.enum(["asc", "desc"])
897+
.optional()
898+
.describe("Return merge requests sorted in ascending or descending order"),
899+
target_branch: z
900+
.string()
901+
.optional()
902+
.describe("Return merge requests targeting a specific branch"),
903+
source_branch: z
904+
.string()
905+
.optional()
906+
.describe("Return merge requests from a specific source branch"),
907+
wip: z
908+
.enum(["yes", "no"])
909+
.optional()
910+
.describe("Filter merge requests against their wip status"),
911+
with_labels_details: z
912+
.boolean()
913+
.optional()
914+
.describe("Return more details for each label"),
915+
page: z.number().optional().describe("Page number for pagination"),
916+
per_page: z.number().optional().describe("Number of items per page"),
917+
});
918+
837919
export const GetIssueSchema = z.object({
838920
project_id: z.string().describe("Project ID or URL-encoded path"),
839921
issue_iid: z.number().describe("The internal ID of the project issue"),

0 commit comments

Comments
 (0)