@zereight/mcp-gitlab 2.1.10 → 2.1.11

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
@@ -644,6 +644,7 @@ Register the skill directory in your AI client to get optimal tool usage guidanc
644
644
  151. `search_project_code` - Search for code within a specific GitLab project (requires advanced search or exact code search to be enabled)
645
645
  152. `search_group_code` - Search for code within a specific GitLab group (requires advanced search or exact code search to be enabled)
646
646
  153. `execute_graphql` - Execute a GitLab GraphQL query
647
+ 154. `list_merge_request_pipelines` - List pipelines for a merge request with pagination support
647
648
 
648
649
  <!-- TOOLS-END -->
649
650
 
package/build/index.js CHANGED
@@ -25,13 +25,13 @@ import { requireBearerAuth } from "@modelcontextprotocol/sdk/server/auth/middlew
25
25
  import { GitLabClientPool } from "./gitlab-client-pool.js";
26
26
  import { allTools, readOnlyTools, destructiveTools, parseEnabledToolsets, parseIndividualTools, buildFeatureFlagOverrides, isToolInEnabledToolset, TOOLSET_DEFINITIONS, ALL_TOOLSET_IDS, } from "./tools/registry.js";
27
27
  import { BulkPublishDraftNotesSchema, CancelPipelineJobSchema, CancelPipelineSchema, CreateBranchSchema, CreateDraftNoteSchema, CreateIssueLinkSchema, CreateIssueNoteSchema, CreateIssueSchema, CreateIssueEmojiReactionSchema, CreateIssueNoteEmojiReactionSchema, ListIssueEmojiReactionsSchema, ListIssueNoteEmojiReactionsSchema, CreateLabelSchema, // Added
28
- CreateMergeRequestNoteSchema, CreateMergeRequestDiscussionNoteSchema, CreateMergeRequestEmojiReactionSchema, CreateMergeRequestNoteEmojiReactionSchema, ListMergeRequestEmojiReactionsSchema, ListMergeRequestNoteEmojiReactionsSchema, CreateMergeRequestSchema, CreateMergeRequestThreadSchema, CreateNoteSchema, CreateCommitStatusSchema, CreateOrUpdateFileSchema, CreatePipelineSchema, CreateProjectMilestoneSchema, CreateRepositorySchema, CreateWikiPageSchema, CreateGroupWikiPageSchema, DeleteDraftNoteSchema, DeleteGroupWikiPageSchema, DeleteIssueLinkSchema, DeleteIssueSchema, DeleteIssueEmojiReactionSchema, DeleteIssueNoteEmojiReactionSchema, DeleteLabelSchema, DeleteProjectMilestoneSchema, DeleteWikiPageSchema, DeleteMergeRequestNoteSchema, DeleteMergeRequestEmojiReactionSchema, DeleteMergeRequestNoteEmojiReactionSchema, EditProjectMilestoneSchema, ForkRepositorySchema, GetBranchDiffsSchema, GetCommitDiffSchema, GetCommitSchema, GetDraftNoteSchema, GetFileContentsSchema, GetIssueLinkSchema, GetIssueSchema, GetLabelSchema, GetMergeRequestDiffsSchema, GetMergeRequestSchema, GetMilestoneBurndownEventsSchema, GetMilestoneIssuesSchema, GetMilestoneMergeRequestsSchema, GetDeploymentSchema, GetEnvironmentSchema, GetNamespaceSchema, GitLabCiLintResultSchema, GetPipelineJobOutputSchema, GetPipelineSchema, GetProjectMilestoneSchema, GetProjectSchema, GetRepositoryTreeSchema, GetUsersSchema, GetWikiPageSchema, GitLabCommitSchema, GitLabCommitStatusSchema, GitLabCompareResultSchema, GitLabContentSchema, GitLabCreateUpdateFileResponseSchema, GitLabDiffSchema,
28
+ CreateMergeRequestNoteSchema, CreateMergeRequestDiscussionNoteSchema, CreateMergeRequestEmojiReactionSchema, CreateMergeRequestNoteEmojiReactionSchema, ListMergeRequestEmojiReactionsSchema, ListMergeRequestNoteEmojiReactionsSchema, CreateMergeRequestSchema, CreateMergeRequestThreadSchema, CreateNoteSchema, CreateCommitStatusSchema, CreateOrUpdateFileSchema, CreatePipelineSchema, CreateProjectMilestoneSchema, CreateRepositorySchema, CreateWikiPageSchema, CreateGroupWikiPageSchema, DeleteDraftNoteSchema, DeleteGroupWikiPageSchema, DeleteIssueLinkSchema, DeleteIssueSchema, DeleteIssueEmojiReactionSchema, DeleteIssueNoteEmojiReactionSchema, DeleteLabelSchema, DeleteProjectMilestoneSchema, DeleteWikiPageSchema, DeleteMergeRequestNoteSchema, DeleteMergeRequestEmojiReactionSchema, DeleteMergeRequestNoteEmojiReactionSchema, EditProjectMilestoneSchema, ForkRepositorySchema, GetBranchDiffsSchema, GetCommitDiffSchema, GetCommitSchema, GetDraftNoteSchema, GetFileContentsSchema, GetIssueLinkSchema, GetIssueSchema, GetLabelSchema, GetMergeRequestDiffsSchema, GetMergeRequestSchema, GetMilestoneBurndownEventsSchema, GetMilestoneIssuesSchema, GetMilestoneMergeRequestsSchema, GetDeploymentSchema, GetEnvironmentSchema, GetNamespaceSchema, GitLabCiLintResultSchema, GetPipelineJobOutputSchema, GetPipelineSchema, GetProjectMilestoneSchema, GetProjectSchema, GetRepositoryTreeSchema, GetUsersSchema, GetUserSchema, GitLabUserFullSchema, WhoAmISchema, GitLabCurrentUserSchema, GetWikiPageSchema, GitLabCommitSchema, GitLabCommitStatusSchema, GitLabCompareResultSchema, GitLabContentSchema, GitLabCreateUpdateFileResponseSchema, GitLabDiffSchema,
29
29
  // Discussion Schemas
30
30
  GitLabDiscussionNoteSchema, // Added
31
31
  GitLabDiscussionSchema,
32
32
  // Draft Notes Schemas
33
- GitLabDraftNoteSchema, GitLabForkSchema, GitLabIssueLinkSchema, GitLabIssueSchema, GitLabIssueWithLinkDetailsSchema, GitLabMarkdownUploadSchema, GitLabMergeRequestSchema, GitLabMilestonesSchema, GitLabNamespaceExistsResponseSchema, GitLabNamespaceSchema, GitLabPipelineJobSchema, GitLabDeploymentSchema, GitLabEnvironmentSchema, GitLabPipelineSchema, GitLabPipelineTriggerJobSchema, GitLabProjectMemberSchema, GitLabProjectSchema, GitLabTodoSchema, GitLabReferenceSchema, GitLabRepositorySchema, GitLabSearchBlobResultSchema, GitLabSearchResponseSchema, GitLabTreeItemSchema, GitLabUserSchema, GitLabUsersResponseSchema, GitLabWikiPageSchema, GroupIteration, ListCommitStatusesSchema, ListCommitsSchema, ListDraftNotesSchema, ListGroupIterationsSchema, ListGroupProjectsSchema, ListIssueDiscussionsSchema, ListIssueLinksSchema, ListIssuesSchema, ListTodosSchema, ListLabelsSchema, ListMergeRequestDiffsSchema, // Added
34
- GetMergeRequestFileDiffSchema, ListMergeRequestChangedFilesSchema, ListMergeRequestDiscussionsSchema, ListMergeRequestsSchema, ListMergeRequestVersionsSchema, GetMergeRequestVersionSchema, GitLabMergeRequestVersionSchema, GitLabMergeRequestVersionDetailSchema, ListNamespacesSchema, ListPipelineJobsSchema, ListPipelinesSchema, ListDeploymentsSchema, ListEnvironmentsSchema, ListPipelineTriggerJobsSchema, ValidateCiLintSchema, ValidateProjectCiLintSchema, ListProjectMembersSchema, ListProjectMilestonesSchema, ListProjectsSchema, ListWikiPagesSchema, GetGroupWikiPageSchema, ListGroupWikiPagesSchema, UpdateGroupWikiPageSchema, MarkdownUploadSchema, DownloadAttachmentSchema, DownloadJobArtifactsSchema, GetJobArtifactFileSchema, GitLabArtifactEntrySchema, ListJobArtifactsSchema, MergeMergeRequestSchema, ApproveMergeRequestSchema, UnapproveMergeRequestSchema, GetMergeRequestApprovalStateSchema, GetMergeRequestConflictsSchema, GitLabMergeRequestApprovalsResponseSchema, GitLabMergeRequestApprovalStateSchema, MyIssuesSchema, MarkAllTodosDoneSchema, MarkTodoDoneSchema, PaginatedDiscussionsResponseSchema, PromoteProjectMilestoneSchema, PublishDraftNoteSchema, PlayPipelineJobSchema, PushFilesSchema, RetryPipelineJobSchema, RetryPipelineSchema, SearchCodeSchema, SearchGroupCodeSchema, SearchProjectCodeSchema, SearchRepositoriesSchema, UpdateDraftNoteSchema, UpdateIssueNoteSchema, UpdateIssueSchema, UpdateLabelSchema, UpdateMergeRequestNoteSchema, UpdateMergeRequestDiscussionNoteSchema, UpdateMergeRequestSchema, UpdateWikiPageSchema, VerifyNamespaceSchema, GitLabEventSchema, ListEventsSchema, GetProjectEventsSchema, ExecuteGraphQLSchema, GitLabReleaseSchema, ListReleasesSchema, GetReleaseSchema, CreateReleaseSchema, UpdateReleaseSchema, DeleteReleaseSchema, CreateReleaseEvidenceSchema, DownloadReleaseAssetSchema, ListTagsSchema, GetTagSchema, CreateTagSchema, DeleteTagSchema, GetTagSignatureSchema, GitLabTagSchema, GitLabTagSignatureSchema, GetMergeRequestNotesSchema, GetMergeRequestNoteSchema, DeleteMergeRequestDiscussionNoteSchema, ResolveMergeRequestThreadSchema, GetWorkItemSchema, ListWorkItemsSchema, CreateWorkItemSchema, UpdateWorkItemSchema, ConvertWorkItemTypeSchema, ListWorkItemStatusesSchema, ListWorkItemNotesSchema, CreateWorkItemNoteSchema, CreateWorkItemEmojiReactionSchema, CreateWorkItemNoteEmojiReactionSchema, ListWorkItemEmojiReactionsSchema, ListWorkItemNoteEmojiReactionsSchema, DeleteWorkItemEmojiReactionSchema, DeleteWorkItemNoteEmojiReactionSchema, MoveWorkItemSchema, ListCustomFieldDefinitionsSchema, GetTimelineEventsSchema, CreateTimelineEventSchema, ListWebhooksSchema, ListWebhookEventsSchema, GetWebhookEventSchema, } from "./schemas.js";
33
+ GitLabDraftNoteSchema, GitLabForkSchema, GitLabIssueLinkSchema, GitLabIssueSchema, GitLabIssueWithLinkDetailsSchema, GitLabMarkdownUploadSchema, GitLabMergeRequestPipelineSchema, GitLabMergeRequestSchema, GitLabMilestonesSchema, GitLabNamespaceExistsResponseSchema, GitLabNamespaceSchema, GitLabPipelineJobSchema, GitLabDeploymentSchema, GitLabEnvironmentSchema, GitLabPipelineSchema, GitLabPipelineTriggerJobSchema, GitLabProjectMemberSchema, GitLabProjectSchema, GitLabTodoSchema, GitLabReferenceSchema, GitLabRepositorySchema, GitLabSearchBlobResultSchema, GitLabSearchResponseSchema, GitLabTreeItemSchema, GitLabUserSchema, GitLabUsersResponseSchema, GitLabWikiPageSchema, GroupIteration, ListCommitStatusesSchema, ListCommitsSchema, ListDraftNotesSchema, ListGroupIterationsSchema, ListGroupProjectsSchema, ListIssueDiscussionsSchema, ListIssueLinksSchema, ListIssuesSchema, ListTodosSchema, ListLabelsSchema, ListMergeRequestDiffsSchema, // Added
34
+ GetMergeRequestFileDiffSchema, ListMergeRequestChangedFilesSchema, ListMergeRequestDiscussionsSchema, ListMergeRequestPipelinesSchema, ListMergeRequestsSchema, ListMergeRequestVersionsSchema, GetMergeRequestVersionSchema, GitLabMergeRequestVersionSchema, GitLabMergeRequestVersionDetailSchema, ListNamespacesSchema, ListPipelineJobsSchema, ListPipelinesSchema, ListDeploymentsSchema, ListEnvironmentsSchema, ListPipelineTriggerJobsSchema, ValidateCiLintSchema, ValidateProjectCiLintSchema, ListProjectMembersSchema, ListProjectMilestonesSchema, ListProjectsSchema, ListWikiPagesSchema, GetGroupWikiPageSchema, ListGroupWikiPagesSchema, UpdateGroupWikiPageSchema, MarkdownUploadSchema, DownloadAttachmentSchema, DownloadJobArtifactsSchema, GetJobArtifactFileSchema, GitLabArtifactEntrySchema, ListJobArtifactsSchema, MergeMergeRequestSchema, ApproveMergeRequestSchema, UnapproveMergeRequestSchema, GetMergeRequestApprovalStateSchema, GetMergeRequestConflictsSchema, GitLabMergeRequestApprovalsResponseSchema, GitLabMergeRequestApprovalStateSchema, MyIssuesSchema, MarkAllTodosDoneSchema, MarkTodoDoneSchema, PaginatedDiscussionsResponseSchema, PromoteProjectMilestoneSchema, PublishDraftNoteSchema, PlayPipelineJobSchema, PushFilesSchema, RetryPipelineJobSchema, RetryPipelineSchema, SearchCodeSchema, SearchGroupCodeSchema, SearchProjectCodeSchema, SearchRepositoriesSchema, UpdateDraftNoteSchema, UpdateIssueNoteSchema, UpdateIssueSchema, UpdateLabelSchema, UpdateMergeRequestNoteSchema, UpdateMergeRequestDiscussionNoteSchema, UpdateMergeRequestSchema, UpdateWikiPageSchema, VerifyNamespaceSchema, GitLabEventSchema, ListEventsSchema, GetProjectEventsSchema, ExecuteGraphQLSchema, GitLabReleaseSchema, ListReleasesSchema, GetReleaseSchema, CreateReleaseSchema, UpdateReleaseSchema, DeleteReleaseSchema, CreateReleaseEvidenceSchema, DownloadReleaseAssetSchema, ListTagsSchema, GetTagSchema, CreateTagSchema, DeleteTagSchema, GetTagSignatureSchema, GitLabTagSchema, GitLabTagSignatureSchema, GetMergeRequestNotesSchema, GetMergeRequestNoteSchema, DeleteMergeRequestDiscussionNoteSchema, ResolveMergeRequestThreadSchema, GetWorkItemSchema, ListWorkItemsSchema, CreateWorkItemSchema, UpdateWorkItemSchema, ConvertWorkItemTypeSchema, ListWorkItemStatusesSchema, ListWorkItemNotesSchema, CreateWorkItemNoteSchema, CreateWorkItemEmojiReactionSchema, CreateWorkItemNoteEmojiReactionSchema, ListWorkItemEmojiReactionsSchema, ListWorkItemNoteEmojiReactionsSchema, DeleteWorkItemEmojiReactionSchema, DeleteWorkItemNoteEmojiReactionSchema, MoveWorkItemSchema, ListCustomFieldDefinitionsSchema, GetTimelineEventsSchema, CreateTimelineEventSchema, ListWebhooksSchema, ListWebhookEventsSchema, GetWebhookEventSchema, HealthCheckSchema, } from "./schemas.js";
35
35
  import { randomUUID } from "node:crypto";
36
36
  import { pino } from "pino";
37
37
  const logger = pino({
@@ -783,6 +783,15 @@ function buildAuthHeaders() {
783
783
  }
784
784
  return {};
785
785
  }
786
+ function usesJobTokenHeader() {
787
+ if (GITLAB_JOB_TOKEN)
788
+ return true;
789
+ if (REMOTE_AUTHORIZATION || GITLAB_MCP_OAUTH) {
790
+ const ctx = sessionAuthStore.getStore();
791
+ return ctx?.header === "JOB-TOKEN";
792
+ }
793
+ return false;
794
+ }
786
795
  /**
787
796
  * Get the effective GitLab API URL for the current request
788
797
  * In REMOTE_AUTHORIZATION mode with ENABLE_DYNAMIC_API_URL, reads from session context
@@ -3263,6 +3272,21 @@ async function getMergeRequestSourceCommitCount(projectId, mergeRequestIid) {
3263
3272
  }
3264
3273
  return totalCount;
3265
3274
  }
3275
+ async function listMergeRequestPipelines(projectId, mergeRequestIid, options = {}) {
3276
+ projectId = decodeURIComponent(projectId);
3277
+ const url = new URL(`${getEffectiveApiUrl()}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/merge_requests/${mergeRequestIid}/pipelines`);
3278
+ Object.entries(options).forEach(([key, value]) => {
3279
+ if (value !== undefined) {
3280
+ url.searchParams.append(key, value.toString());
3281
+ }
3282
+ });
3283
+ const response = await fetch(url.toString(), {
3284
+ ...getFetchConfig(),
3285
+ });
3286
+ await handleGitLabError(response);
3287
+ const data = await response.json();
3288
+ return z.array(GitLabMergeRequestPipelineSchema).parse(data);
3289
+ }
3266
3290
  async function getProjectMergeMethod(projectId) {
3267
3291
  const url = new URL(`${getEffectiveApiUrl()}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}`);
3268
3292
  const response = await fetch(url.toString(), {
@@ -5449,9 +5473,21 @@ async function createCommitStatus(projectId, sha, options) {
5449
5473
  */
5450
5474
  async function getCurrentUser() {
5451
5475
  const response = await fetch(`${getEffectiveApiUrl()}/user`, getFetchConfig());
5476
+ if (response.ok) {
5477
+ const data = await response.json();
5478
+ return GitLabUserSchema.parse(data);
5479
+ }
5480
+ if ((response.status === 401 || response.status === 403) && usesJobTokenHeader()) {
5481
+ const jobResponse = await fetch(`${getEffectiveApiUrl()}/job`, getFetchConfig());
5482
+ if (jobResponse.ok) {
5483
+ const jobData = await jobResponse.json();
5484
+ if (jobData.user) {
5485
+ return GitLabUserSchema.parse(jobData.user);
5486
+ }
5487
+ }
5488
+ }
5452
5489
  await handleGitLabError(response);
5453
- const data = await response.json();
5454
- return GitLabUserSchema.parse(data);
5490
+ throw new Error(`GitLab API error: ${response.status} ${response.statusText}`);
5455
5491
  }
5456
5492
  /**
5457
5493
  * List issues assigned to the current authenticated user
@@ -6329,6 +6365,14 @@ async function handleToolCall(params) {
6329
6365
  content: [{ type: "text", text: JSON.stringify(files, null, 2) }],
6330
6366
  };
6331
6367
  }
6368
+ case "list_merge_request_pipelines": {
6369
+ const args = ListMergeRequestPipelinesSchema.parse(params.arguments);
6370
+ const { project_id, merge_request_iid, ...options } = args;
6371
+ const pipelines = await listMergeRequestPipelines(project_id, merge_request_iid, options);
6372
+ return {
6373
+ content: [{ type: "text", text: JSON.stringify(pipelines, null, 2) }],
6374
+ };
6375
+ }
6332
6376
  case "list_merge_request_diffs": {
6333
6377
  const args = ListMergeRequestDiffsSchema.parse(params.arguments);
6334
6378
  const changes = await listMergeRequestDiffs(args.project_id, args.merge_request_iid, args.source_branch, args.page, args.per_page, args.unidiff);
@@ -6503,6 +6547,32 @@ async function handleToolCall(params) {
6503
6547
  content: [{ type: "text", text: JSON.stringify(usersMap, null, 2) }],
6504
6548
  };
6505
6549
  }
6550
+ case "get_user": {
6551
+ const args = GetUserSchema.parse(params.arguments);
6552
+ const url = new URL(`${getEffectiveApiUrl()}/users/${encodeURIComponent(args.user_id)}`);
6553
+ const response = await fetch(url.toString(), {
6554
+ ...getFetchConfig(),
6555
+ });
6556
+ await handleGitLabError(response);
6557
+ const data = await response.json();
6558
+ const user = GitLabUserFullSchema.parse(data);
6559
+ return {
6560
+ content: [{ type: "text", text: JSON.stringify(user, null, 2) }],
6561
+ };
6562
+ }
6563
+ case "whoami": {
6564
+ WhoAmISchema.parse(params.arguments ?? {});
6565
+ const url = new URL(`${getEffectiveApiUrl()}/user`);
6566
+ const response = await fetch(url.toString(), {
6567
+ ...getFetchConfig(),
6568
+ });
6569
+ await handleGitLabError(response);
6570
+ const data = await response.json();
6571
+ const user = GitLabCurrentUserSchema.parse(data);
6572
+ return {
6573
+ content: [{ type: "text", text: JSON.stringify(user, null, 2) }],
6574
+ };
6575
+ }
6506
6576
  case "create_note": {
6507
6577
  const args = CreateNoteSchema.parse(params.arguments);
6508
6578
  const { project_id, noteable_type, noteable_iid, body } = args;
@@ -7528,6 +7598,20 @@ async function handleToolCall(params) {
7528
7598
  content: [{ type: "text", text: JSON.stringify(event, null, 2) }],
7529
7599
  };
7530
7600
  }
7601
+ case "health_check": {
7602
+ HealthCheckSchema.parse(params.arguments ?? {});
7603
+ const url = new URL(`${getEffectiveApiUrl()}/user`);
7604
+ const response = await fetch(url.toString(), getFetchConfig());
7605
+ let authenticated = response.ok;
7606
+ if (!authenticated && (response.status === 401 || response.status === 403) && (GITLAB_JOB_TOKEN || usesJobTokenHeader())) {
7607
+ const jobUrl = new URL(`${getEffectiveApiUrl()}/job`);
7608
+ const jobResponse = await fetch(jobUrl.toString(), getFetchConfig());
7609
+ authenticated = jobResponse.ok;
7610
+ }
7611
+ return {
7612
+ content: [{ type: "text", text: JSON.stringify({ status: authenticated ? "ok" : "error", authenticated, gitlab_url: getEffectiveApiUrl() }) }],
7613
+ };
7614
+ }
7531
7615
  default:
7532
7616
  throw new Error(`Unknown tool: ${params.name}`);
7533
7617
  }
package/build/schemas.js CHANGED
@@ -248,6 +248,17 @@ export const GetPipelineSchema = z.object({
248
248
  project_id: z.coerce.string().describe("Project ID or URL-encoded path"),
249
249
  pipeline_id: z.coerce.string().describe("The ID of the pipeline"),
250
250
  });
251
+ export const GitLabMergeRequestPipelineSchema = z.object({
252
+ id: z.coerce.string(),
253
+ sha: z.string(),
254
+ ref: z.string(),
255
+ status: z.string(),
256
+ project_id: z.coerce.string().optional(),
257
+ source: z.string().optional(),
258
+ created_at: z.string().optional(),
259
+ updated_at: z.string().optional(),
260
+ web_url: z.string().optional(),
261
+ });
251
262
  // Schema for listing jobs in a pipeline
252
263
  export const ListPipelineJobsSchema = z
253
264
  .object({
@@ -514,6 +525,76 @@ export const GitLabUsersResponseSchema = z.record(z.string(), z
514
525
  web_url: z.string(),
515
526
  })
516
527
  .nullable());
528
+ export const GetUserSchema = z.object({
529
+ user_id: z.coerce.string().describe("The ID of the user"),
530
+ });
531
+ export const GitLabUserFullSchema = z.object({
532
+ id: z.coerce.string(),
533
+ username: z.string(),
534
+ name: z.string(),
535
+ state: z.string(),
536
+ avatar_url: z.string().nullable(),
537
+ web_url: z.string(),
538
+ created_at: z.string(),
539
+ bio: z.string().nullable(),
540
+ location: z.string().nullable(),
541
+ public_email: z.string().nullable(),
542
+ website_url: z.string().nullable(),
543
+ organization: z.string().nullable(),
544
+ job_title: z.string().nullable(),
545
+ pronouns: z.string().nullable(),
546
+ bot: z.boolean().optional(),
547
+ work_information: z.string().nullable(),
548
+ followers: z.number().optional(),
549
+ following: z.number().optional(),
550
+ is_followed: z.boolean().optional(),
551
+ local_time: z.string().nullable().optional(),
552
+ last_sign_in_at: z.string().nullable().optional(),
553
+ confirmed_at: z.string().nullable().optional(),
554
+ last_activity_on: z.string().nullable().optional(),
555
+ email: z.string().nullable().optional(),
556
+ theme_id: z.number().nullable().optional(),
557
+ color_scheme_id: z.number().nullable().optional(),
558
+ projects_limit: z.number().nullable().optional(),
559
+ current_sign_in_at: z.string().nullable().optional(),
560
+ identities: z.array(z.object({
561
+ provider: z.string(),
562
+ extern_uid: z.string(),
563
+ })).optional(),
564
+ can_create_group: z.boolean().nullable().optional(),
565
+ can_create_project: z.boolean().nullable().optional(),
566
+ two_factor_enabled: z.boolean().nullable().optional(),
567
+ external: z.boolean().nullable().optional(),
568
+ private_profile: z.boolean().nullable().optional(),
569
+ is_admin: z.boolean().nullable().optional(),
570
+ }).passthrough();
571
+ export const WhoAmISchema = z.object({});
572
+ export const GitLabCurrentUserSchema = z.object({
573
+ id: z.coerce.string(),
574
+ username: z.string(),
575
+ name: z.string(),
576
+ state: z.string(),
577
+ avatar_url: z.string().nullable(),
578
+ web_url: z.string(),
579
+ created_at: z.string(),
580
+ bio: z.string().nullable(),
581
+ location: z.string().nullable(),
582
+ public_email: z.string().nullable(),
583
+ website_url: z.string().nullable(),
584
+ organization: z.string().nullable(),
585
+ job_title: z.string().nullable(),
586
+ email: z.string().nullable(),
587
+ last_sign_in_at: z.string().nullable(),
588
+ confirmed_at: z.string().nullable(),
589
+ last_activity_on: z.string().nullable(),
590
+ is_admin: z.boolean().optional(),
591
+ can_create_group: z.boolean().optional(),
592
+ can_create_project: z.boolean().optional(),
593
+ identities: z.array(z.object({
594
+ provider: z.string(),
595
+ extern_uid: z.string(),
596
+ })).optional(),
597
+ }).passthrough();
517
598
  // Namespace related schemas
518
599
  // Base schema for project-related operations
519
600
  const ProjectParamsSchema = z.object({
@@ -1541,6 +1622,17 @@ export const GetMergeRequestApprovalStateSchema = ProjectParamsSchema.extend({
1541
1622
  export const GetMergeRequestConflictsSchema = ProjectParamsSchema.extend({
1542
1623
  merge_request_iid: z.coerce.string().describe("The IID of the merge request"),
1543
1624
  });
1625
+ export const ListMergeRequestPipelinesSchema = ProjectParamsSchema.extend({
1626
+ merge_request_iid: z
1627
+ .preprocess(value => (value === undefined || value === null ? value : String(value)), z
1628
+ .string({
1629
+ required_error: "merge_request_iid is required",
1630
+ invalid_type_error: "merge_request_iid is required",
1631
+ })
1632
+ .refine(value => value.trim().length > 0, "merge_request_iid is required")
1633
+ .transform(value => value.trim()))
1634
+ .describe("The internal ID of the merge request"),
1635
+ }).merge(PaginationOptionsSchema);
1544
1636
  export const GetMergeRequestDiffsSchema = GetMergeRequestSchema.extend({
1545
1637
  view: z.enum(["inline", "parallel"]).optional().describe("Diff view type"),
1546
1638
  excluded_file_patterns: z
@@ -3141,3 +3233,4 @@ export const GetWebhookEventSchema = z
3141
3233
  .refine(data => (data.project_id || data.group_id) && !(data.project_id && data.group_id), {
3142
3234
  message: "Provide exactly one of project_id or group_id",
3143
3235
  });
3236
+ export const HealthCheckSchema = z.object({});
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env ts-node
2
- import { GetFileContentsSchema, GitLabFileContentSchema, GitLabRepositorySchema, CreatePipelineSchema, CreateCommitStatusSchema, ListCommitStatusesSchema, CreateIssueNoteSchema, CreateMergeRequestEmojiReactionSchema, CreateIssueEmojiReactionSchema, DeleteMergeRequestEmojiReactionSchema, DeleteIssueEmojiReactionSchema, CreateWorkItemEmojiReactionSchema, CreateWorkItemNoteEmojiReactionSchema, CreateIssueSchema, ListIssuesSchema, ListMergeRequestsSchema, ListLabelsSchema, GitLabMergeRequestSchema, GitLabTreeItemSchema, GetMergeRequestSchema, GetRepositoryTreeSchema } from '../schemas.js';
2
+ import { GetFileContentsSchema, GitLabFileContentSchema, GitLabRepositorySchema, CreatePipelineSchema, CreateCommitStatusSchema, ListCommitStatusesSchema, CreateIssueNoteSchema, CreateMergeRequestEmojiReactionSchema, CreateIssueEmojiReactionSchema, DeleteMergeRequestEmojiReactionSchema, DeleteIssueEmojiReactionSchema, CreateWorkItemEmojiReactionSchema, CreateWorkItemNoteEmojiReactionSchema, CreateIssueSchema, ListIssuesSchema, ListMergeRequestsSchema, ListLabelsSchema, GitLabMergeRequestSchema, GitLabTreeItemSchema, GetMergeRequestSchema, ListMergeRequestPipelinesSchema, GetRepositoryTreeSchema, GitLabUserFullSchema } from '../schemas.js';
3
3
  function runGetFileContentsSchemaTests() {
4
4
  console.log('🧪 Testing GetFileContentsSchema...');
5
5
  const cases = [
@@ -609,6 +609,60 @@ function runGetMergeRequestSchemaTests() {
609
609
  console.log(`\nResults: ${passed} passed, ${failed} failed`);
610
610
  return { passed, failed };
611
611
  }
612
+ function runListMergeRequestPipelinesSchemaTests() {
613
+ console.log('\n🧪 Testing ListMergeRequestPipelinesSchema...');
614
+ const cases = [
615
+ {
616
+ name: 'schema:list_merge_request_pipelines:minimal-required-fields',
617
+ input: { project_id: 'my/project', merge_request_iid: '42' },
618
+ expected: { project_id: 'my/project', merge_request_iid: '42' },
619
+ },
620
+ {
621
+ name: 'schema:list_merge_request_pipelines:coerces-pagination',
622
+ input: { project_id: 123, merge_request_iid: 42, page: '2', per_page: '10' },
623
+ expected: { project_id: '123', merge_request_iid: '42', page: 2, per_page: 10 },
624
+ },
625
+ {
626
+ name: 'schema:list_merge_request_pipelines:reject-missing-merge-request-iid',
627
+ input: { project_id: 'my/project' },
628
+ shouldFail: true,
629
+ },
630
+ ];
631
+ let passed = 0;
632
+ let failed = 0;
633
+ cases.forEach(testCase => {
634
+ const result = { name: testCase.name, status: 'failed' };
635
+ const parsed = ListMergeRequestPipelinesSchema.safeParse(testCase.input);
636
+ if (testCase.shouldFail) {
637
+ result.status = parsed.success ? 'failed' : 'passed';
638
+ if (parsed.success)
639
+ result.error = 'Expected schema validation to fail';
640
+ }
641
+ else if (parsed.success) {
642
+ const expected = testCase.expected || {};
643
+ const matches = Object.entries(expected).every(([key, value]) => {
644
+ const actual = parsed.data[key];
645
+ return actual === value;
646
+ });
647
+ result.status = matches ? 'passed' : 'failed';
648
+ if (!matches)
649
+ result.error = `Unexpected parsed result: ${JSON.stringify(parsed.data)}`;
650
+ }
651
+ else {
652
+ result.error = parsed.error?.message || 'Schema validation failed';
653
+ }
654
+ if (result.status === 'passed') {
655
+ passed++;
656
+ console.log(`✅ ${result.name}`);
657
+ }
658
+ else {
659
+ failed++;
660
+ console.log(`❌ ${result.name}: ${result.error}`);
661
+ }
662
+ });
663
+ console.log(`\nResults: ${passed} passed, ${failed} failed`);
664
+ return { passed, failed };
665
+ }
612
666
  function runGitLabMergeRequestSchemaTests() {
613
667
  console.log('\n🧪 Testing GitLabMergeRequestSchema...');
614
668
  const baseMergeRequest = {
@@ -1068,6 +1122,87 @@ function runGetRepositoryTreeSchemaTests() {
1068
1122
  console.log(`\nResults: ${passed} passed, ${failed} failed`);
1069
1123
  return { passed, failed };
1070
1124
  }
1125
+ function runGitLabUserFullSchemaTests() {
1126
+ console.log('🧪 Testing GitLabUserFullSchema...');
1127
+ const adminResponse = {
1128
+ id: 1,
1129
+ username: 'root',
1130
+ name: 'Administrator',
1131
+ state: 'active',
1132
+ avatar_url: 'https://gitlab.example.com/uploads/-/system/user/avatar/1/avatar.png',
1133
+ web_url: 'https://gitlab.example.com/root',
1134
+ created_at: '2012-09-22T16:50:56.000Z',
1135
+ bio: null,
1136
+ location: null,
1137
+ public_email: '',
1138
+ website_url: '',
1139
+ organization: null,
1140
+ job_title: null,
1141
+ pronouns: null,
1142
+ work_information: null,
1143
+ followers: 0,
1144
+ following: 0,
1145
+ is_followed: false,
1146
+ local_time: null,
1147
+ last_sign_in_at: null,
1148
+ confirmed_at: '2012-09-22T16:50:56.000Z',
1149
+ last_activity_on: '2026-05-12',
1150
+ email: 'admin@example.com',
1151
+ theme_id: 1,
1152
+ color_scheme_id: 1,
1153
+ projects_limit: 100000,
1154
+ current_sign_in_at: '2026-05-12T08:14:22.885Z',
1155
+ identities: [],
1156
+ can_create_group: true,
1157
+ can_create_project: true,
1158
+ two_factor_enabled: false,
1159
+ external: false,
1160
+ private_profile: false,
1161
+ is_admin: true,
1162
+ };
1163
+ const cases = [
1164
+ {
1165
+ name: 'schema:user_full:admin-response-no-bot',
1166
+ input: { ...adminResponse },
1167
+ shouldFail: false,
1168
+ },
1169
+ {
1170
+ name: 'schema:user_full:admin-response-with-bot',
1171
+ input: { ...adminResponse, bot: false },
1172
+ shouldFail: false,
1173
+ },
1174
+ ];
1175
+ let passed = 0;
1176
+ let failed = 0;
1177
+ cases.forEach(testCase => {
1178
+ const result = { name: testCase.name, status: 'failed' };
1179
+ const parsed = GitLabUserFullSchema.safeParse(testCase.input);
1180
+ if (testCase.shouldFail) {
1181
+ if (parsed.success) {
1182
+ result.error = 'Expected schema validation to fail';
1183
+ }
1184
+ else {
1185
+ result.status = 'passed';
1186
+ }
1187
+ }
1188
+ else if (parsed.success) {
1189
+ result.status = 'passed';
1190
+ }
1191
+ else {
1192
+ result.error = parsed.error?.message || 'Schema validation failed';
1193
+ }
1194
+ if (result.status === 'passed') {
1195
+ passed++;
1196
+ console.log(`✅ ${result.name}`);
1197
+ }
1198
+ else {
1199
+ failed++;
1200
+ console.log(`❌ ${result.name}: ${result.error}`);
1201
+ }
1202
+ });
1203
+ console.log(`\nResults: ${passed} passed, ${failed} failed`);
1204
+ return { passed, failed };
1205
+ }
1071
1206
  if (import.meta.url === `file://${process.argv[1]}`) {
1072
1207
  const getFileContentsResult = runGetFileContentsSchemaTests();
1073
1208
  const fileContentResult = runGitLabFileContentSchemaTests();
@@ -1075,6 +1210,7 @@ if (import.meta.url === `file://${process.argv[1]}`) {
1075
1210
  const commitStatusResult = runCommitStatusSchemaTests();
1076
1211
  const createIssueNoteResult = runCreateIssueNoteSchemaTests();
1077
1212
  const getMergeRequestResult = runGetMergeRequestSchemaTests();
1213
+ const listMergeRequestPipelinesResult = runListMergeRequestPipelinesSchemaTests();
1078
1214
  const gitLabMergeRequestResult = runGitLabMergeRequestSchemaTests();
1079
1215
  const emojiReactionResult = runEmojiReactionSchemaTests();
1080
1216
  const repositorySchemaResult = runGitLabRepositorySchemaTests();
@@ -1082,8 +1218,9 @@ if (import.meta.url === `file://${process.argv[1]}`) {
1082
1218
  const listLabelsResult = runListLabelsSchemaTests();
1083
1219
  const treeItemResult = runGitLabTreeItemSchemaTests();
1084
1220
  const repositoryTreeResult = runGetRepositoryTreeSchemaTests();
1085
- const totalPassed = getFileContentsResult.passed + fileContentResult.passed + createPipelineResult.passed + commitStatusResult.passed + createIssueNoteResult.passed + getMergeRequestResult.passed + gitLabMergeRequestResult.passed + emojiReactionResult.passed + repositorySchemaResult.passed + labelsCoercionResult.passed + listLabelsResult.passed + treeItemResult.passed + repositoryTreeResult.passed;
1086
- const totalFailed = getFileContentsResult.failed + fileContentResult.failed + createPipelineResult.failed + commitStatusResult.failed + createIssueNoteResult.failed + getMergeRequestResult.failed + gitLabMergeRequestResult.failed + emojiReactionResult.failed + repositorySchemaResult.failed + labelsCoercionResult.failed + listLabelsResult.failed + treeItemResult.failed + repositoryTreeResult.failed;
1221
+ const gitLabUserFullResult = runGitLabUserFullSchemaTests();
1222
+ const totalPassed = getFileContentsResult.passed + fileContentResult.passed + createPipelineResult.passed + commitStatusResult.passed + createIssueNoteResult.passed + getMergeRequestResult.passed + listMergeRequestPipelinesResult.passed + gitLabMergeRequestResult.passed + emojiReactionResult.passed + repositorySchemaResult.passed + labelsCoercionResult.passed + listLabelsResult.passed + treeItemResult.passed + repositoryTreeResult.passed + gitLabUserFullResult.passed;
1223
+ const totalFailed = getFileContentsResult.failed + fileContentResult.failed + createPipelineResult.failed + commitStatusResult.failed + createIssueNoteResult.failed + getMergeRequestResult.failed + listMergeRequestPipelinesResult.failed + gitLabMergeRequestResult.failed + emojiReactionResult.failed + repositorySchemaResult.failed + labelsCoercionResult.failed + listLabelsResult.failed + treeItemResult.failed + repositoryTreeResult.failed + gitLabUserFullResult.failed;
1087
1224
  console.log(`\nTotal Results: ${totalPassed} passed, ${totalFailed} failed`);
1088
1225
  if (totalFailed > 0) {
1089
1226
  process.exit(1);
@@ -0,0 +1,106 @@
1
+ import { describe, test, before, after } from "node:test";
2
+ import assert from "node:assert";
3
+ import { spawn } from "child_process";
4
+ import { MockGitLabServer, findMockServerPort } from "./utils/mock-gitlab-server.js";
5
+ const MOCK_TOKEN = "glpat-mr-pipelines-test-token";
6
+ const TEST_PROJECT_ID = "123";
7
+ const TEST_MR_IID = "1";
8
+ async function callTool(toolName, args, env) {
9
+ return new Promise((resolve, reject) => {
10
+ const proc = spawn("node", ["build/index.js"], {
11
+ stdio: ["pipe", "pipe", "pipe"],
12
+ env: {
13
+ ...process.env,
14
+ ...env,
15
+ GITLAB_READ_ONLY_MODE: "true",
16
+ },
17
+ });
18
+ let output = "";
19
+ let errorOutput = "";
20
+ proc.stdout?.on("data", d => output += d);
21
+ proc.stderr?.on("data", d => errorOutput += d);
22
+ proc.on("close", code => {
23
+ if (code !== 0) {
24
+ reject(new Error(`Process exited with code ${code}: ${errorOutput}`));
25
+ return;
26
+ }
27
+ const line = output.split("\n").find(l => l.startsWith("{"));
28
+ if (!line) {
29
+ reject(new Error("No JSON output found"));
30
+ return;
31
+ }
32
+ try {
33
+ const response = JSON.parse(line);
34
+ if (response.error) {
35
+ reject(response.error);
36
+ return;
37
+ }
38
+ const content = response.result?.content?.[0]?.text;
39
+ resolve(content ? JSON.parse(content) : response.result);
40
+ }
41
+ catch (error) {
42
+ reject(error);
43
+ }
44
+ });
45
+ proc.stdin?.end(JSON.stringify({
46
+ jsonrpc: "2.0",
47
+ id: 1,
48
+ method: "tools/call",
49
+ params: { name: toolName, arguments: args },
50
+ }) + "\n");
51
+ });
52
+ }
53
+ describe("list_merge_request_pipelines", () => {
54
+ let mockGitLab;
55
+ let mockGitLabUrl;
56
+ let lastQuery = {};
57
+ before(async () => {
58
+ const mockPort = await findMockServerPort(9250);
59
+ mockGitLab = new MockGitLabServer({
60
+ port: mockPort,
61
+ validTokens: [MOCK_TOKEN],
62
+ });
63
+ mockGitLab.addMockHandler("get", `/projects/${TEST_PROJECT_ID}/merge_requests/${TEST_MR_IID}/pipelines`, (req, res) => {
64
+ lastQuery = { ...req.query };
65
+ res.json([
66
+ {
67
+ id: 77,
68
+ sha: "959e04d7c7a30600c894bd3c0cd0e1ce7f42c11d",
69
+ ref: "main",
70
+ status: "success",
71
+ },
72
+ {
73
+ id: 78,
74
+ sha: "a59e04d7c7a30600c894bd3c0cd0e1ce7f42c22e",
75
+ ref: "refs/merge-requests/1/head",
76
+ status: "running",
77
+ source: "merge_request_event",
78
+ web_url: "https://gitlab.mock/test/project/-/pipelines/78",
79
+ },
80
+ ]);
81
+ });
82
+ await mockGitLab.start();
83
+ mockGitLabUrl = mockGitLab.getUrl();
84
+ });
85
+ after(async () => {
86
+ await mockGitLab.stop();
87
+ });
88
+ test("lists pipelines for a merge request", async () => {
89
+ const pipelines = await callTool("list_merge_request_pipelines", {
90
+ project_id: TEST_PROJECT_ID,
91
+ merge_request_iid: TEST_MR_IID,
92
+ page: 2,
93
+ per_page: 10,
94
+ }, {
95
+ GITLAB_API_URL: `${mockGitLabUrl}/api/v4`,
96
+ GITLAB_PERSONAL_ACCESS_TOKEN: MOCK_TOKEN,
97
+ });
98
+ assert.ok(Array.isArray(pipelines), "Response should be an array");
99
+ assert.strictEqual(pipelines.length, 2);
100
+ assert.strictEqual(pipelines[0].id, "77");
101
+ assert.strictEqual(pipelines[0].status, "success");
102
+ assert.strictEqual(pipelines[1].source, "merge_request_event");
103
+ assert.strictEqual(lastQuery.page, "2");
104
+ assert.strictEqual(lastQuery.per_page, "10");
105
+ });
106
+ });
@@ -16,11 +16,11 @@ const MOCK_PORT_BASE = 9200;
16
16
  const MCP_PORT_BASE = 3200;
17
17
  // Known tool counts per toolset (from TOOLSET_DEFINITIONS)
18
18
  const TOOLSET_TOOL_COUNTS = {
19
- merge_requests: 40,
19
+ merge_requests: 41,
20
20
  issues: 23,
21
21
  repositories: 7,
22
22
  branches: 6,
23
- projects: 8,
23
+ projects: 9,
24
24
  labels: 5,
25
25
  ci: 2,
26
26
  pipelines: 19,
@@ -28,7 +28,7 @@ const TOOLSET_TOOL_COUNTS = {
28
28
  wiki: 10,
29
29
  releases: 7,
30
30
  tags: 5,
31
- users: 5,
31
+ users: 7,
32
32
  search: 3,
33
33
  workitems: 18,
34
34
  webhooks: 3,
@@ -78,11 +78,12 @@ export async function launchServer(config) {
78
78
  if (!serverProcess.killed) {
79
79
  serverProcess.kill("SIGTERM");
80
80
  // Force kill if not terminated within 5 seconds
81
- setTimeout(() => {
81
+ const forceKillTimer = setTimeout(() => {
82
82
  if (!serverProcess.killed) {
83
83
  serverProcess.kill("SIGKILL");
84
84
  }
85
85
  }, 5000);
86
+ forceKillTimer.unref();
86
87
  }
87
88
  },
88
89
  };
@@ -1,7 +1,7 @@
1
1
  import { zodToJsonSchema } from "zod-to-json-schema";
2
2
  import { toJSONSchema } from "../utils/schema.js";
3
3
  import { USE_GITLAB_WIKI, USE_MILESTONE, USE_PIPELINE, } from "../config.js";
4
- import { ApproveMergeRequestSchema, BulkPublishDraftNotesSchema, CancelPipelineJobSchema, CancelPipelineSchema, ConvertWorkItemTypeSchema, CreateBranchSchema, CreateDraftNoteSchema, CreateGroupWikiPageSchema, CreateIssueLinkSchema, CreateIssueNoteSchema, CreateIssueSchema, CreateIssueEmojiReactionSchema, CreateIssueNoteEmojiReactionSchema, ListIssueEmojiReactionsSchema, ListIssueNoteEmojiReactionsSchema, CreateLabelSchema, MarkAllTodosDoneSchema, ListTodosSchema, MarkTodoDoneSchema, CreateMergeRequestDiscussionNoteSchema, CreateMergeRequestEmojiReactionSchema, ListMergeRequestEmojiReactionsSchema, ListMergeRequestNoteEmojiReactionsSchema, CreateMergeRequestNoteSchema, CreateMergeRequestNoteEmojiReactionSchema, CreateMergeRequestSchema, CreateMergeRequestThreadSchema, CreateNoteSchema, CreateCommitStatusSchema, CreateOrUpdateFileSchema, CreatePipelineSchema, CreateProjectMilestoneSchema, CreateReleaseEvidenceSchema, CreateReleaseSchema, CreateRepositorySchema, CreateTagSchema, CreateTimelineEventSchema, CreateWikiPageSchema, CreateWorkItemNoteSchema, CreateWorkItemEmojiReactionSchema, CreateWorkItemNoteEmojiReactionSchema, ListWorkItemEmojiReactionsSchema, ListWorkItemNoteEmojiReactionsSchema, CreateWorkItemSchema, DeleteDraftNoteSchema, DeleteGroupWikiPageSchema, DeleteIssueLinkSchema, DeleteIssueSchema, DeleteIssueEmojiReactionSchema, DeleteIssueNoteEmojiReactionSchema, DeleteLabelSchema, DeleteMergeRequestDiscussionNoteSchema, DeleteMergeRequestNoteSchema, DeleteMergeRequestEmojiReactionSchema, DeleteMergeRequestNoteEmojiReactionSchema, DeleteProjectMilestoneSchema, DeleteReleaseSchema, DeleteTagSchema, DeleteWikiPageSchema, DeleteWorkItemEmojiReactionSchema, DeleteWorkItemNoteEmojiReactionSchema, DownloadAttachmentSchema, DownloadJobArtifactsSchema, DownloadReleaseAssetSchema, EditProjectMilestoneSchema, ExecuteGraphQLSchema, ForkRepositorySchema, GetBranchDiffsSchema, GetCommitDiffSchema, GetCommitSchema, GetDeploymentSchema, GetDraftNoteSchema, GetEnvironmentSchema, GetFileContentsSchema, GetGroupWikiPageSchema, GetIssueLinkSchema, GetIssueSchema, GetJobArtifactFileSchema, GetLabelSchema, GetMergeRequestApprovalStateSchema, GetMergeRequestConflictsSchema, GetMergeRequestDiffsSchema, GetMergeRequestFileDiffSchema, GetMergeRequestNoteSchema, GetMergeRequestNotesSchema, GetMergeRequestSchema, GetMergeRequestVersionSchema, GetMilestoneBurndownEventsSchema, GetMilestoneIssuesSchema, GetMilestoneMergeRequestsSchema, GetNamespaceSchema, GetPipelineJobOutputSchema, GetPipelineSchema, GetProjectEventsSchema, GetProjectMilestoneSchema, GetProjectSchema, GetReleaseSchema, GetRepositoryTreeSchema, GetTagSchema, GetTagSignatureSchema, GetTimelineEventsSchema, GetUsersSchema, GetWebhookEventSchema, GetWikiPageSchema, GetWorkItemSchema, ListCommitsSchema, ListCommitStatusesSchema, ListCustomFieldDefinitionsSchema, ListDeploymentsSchema, ListDraftNotesSchema, ListEnvironmentsSchema, ListEventsSchema, ListGroupIterationsSchema, ListGroupProjectsSchema, ListGroupWikiPagesSchema, ListIssueDiscussionsSchema, ListIssueLinksSchema, ListIssuesSchema, ListJobArtifactsSchema, ListLabelsSchema, ListMergeRequestChangedFilesSchema, ListMergeRequestDiffsSchema, ListMergeRequestDiscussionsSchema, ListMergeRequestVersionsSchema, ListMergeRequestsSchema, ListNamespacesSchema, ListPipelineJobsSchema, ListPipelineTriggerJobsSchema, ValidateCiLintSchema, ValidateProjectCiLintSchema, ListPipelinesSchema, ListProjectMembersSchema, ListProjectMilestonesSchema, ListProjectsSchema, ListReleasesSchema, ListTagsSchema, ListWebhookEventsSchema, ListWebhooksSchema, ListWikiPagesSchema, ListWorkItemNotesSchema, ListWorkItemStatusesSchema, ListWorkItemsSchema, MarkdownUploadSchema, MergeMergeRequestSchema, MoveWorkItemSchema, MyIssuesSchema, PlayPipelineJobSchema, PromoteProjectMilestoneSchema, PublishDraftNoteSchema, PushFilesSchema, ResolveMergeRequestThreadSchema, RetryPipelineJobSchema, RetryPipelineSchema, SearchCodeSchema, SearchGroupCodeSchema, SearchProjectCodeSchema, SearchRepositoriesSchema, UnapproveMergeRequestSchema, UpdateDraftNoteSchema, UpdateGroupWikiPageSchema, UpdateIssueNoteSchema, UpdateIssueSchema, UpdateLabelSchema, UpdateMergeRequestDiscussionNoteSchema, UpdateMergeRequestNoteSchema, UpdateMergeRequestSchema, UpdateReleaseSchema, UpdateWikiPageSchema, UpdateWorkItemSchema, VerifyNamespaceSchema, } from "../schemas.js";
4
+ import { ApproveMergeRequestSchema, BulkPublishDraftNotesSchema, CancelPipelineJobSchema, CancelPipelineSchema, ConvertWorkItemTypeSchema, CreateBranchSchema, CreateDraftNoteSchema, CreateGroupWikiPageSchema, CreateIssueLinkSchema, CreateIssueNoteSchema, CreateIssueSchema, CreateIssueEmojiReactionSchema, CreateIssueNoteEmojiReactionSchema, ListIssueEmojiReactionsSchema, ListIssueNoteEmojiReactionsSchema, CreateLabelSchema, MarkAllTodosDoneSchema, ListTodosSchema, MarkTodoDoneSchema, CreateMergeRequestDiscussionNoteSchema, CreateMergeRequestEmojiReactionSchema, ListMergeRequestEmojiReactionsSchema, ListMergeRequestNoteEmojiReactionsSchema, CreateMergeRequestNoteSchema, CreateMergeRequestNoteEmojiReactionSchema, CreateMergeRequestSchema, CreateMergeRequestThreadSchema, CreateNoteSchema, CreateCommitStatusSchema, CreateOrUpdateFileSchema, CreatePipelineSchema, CreateProjectMilestoneSchema, CreateReleaseEvidenceSchema, CreateReleaseSchema, CreateRepositorySchema, CreateTagSchema, CreateTimelineEventSchema, CreateWikiPageSchema, CreateWorkItemNoteSchema, CreateWorkItemEmojiReactionSchema, CreateWorkItemNoteEmojiReactionSchema, ListWorkItemEmojiReactionsSchema, ListWorkItemNoteEmojiReactionsSchema, CreateWorkItemSchema, DeleteDraftNoteSchema, DeleteGroupWikiPageSchema, DeleteIssueLinkSchema, DeleteIssueSchema, DeleteIssueEmojiReactionSchema, DeleteIssueNoteEmojiReactionSchema, DeleteLabelSchema, DeleteMergeRequestDiscussionNoteSchema, DeleteMergeRequestNoteSchema, DeleteMergeRequestEmojiReactionSchema, DeleteMergeRequestNoteEmojiReactionSchema, DeleteProjectMilestoneSchema, DeleteReleaseSchema, DeleteTagSchema, DeleteWikiPageSchema, DeleteWorkItemEmojiReactionSchema, DeleteWorkItemNoteEmojiReactionSchema, DownloadAttachmentSchema, DownloadJobArtifactsSchema, DownloadReleaseAssetSchema, EditProjectMilestoneSchema, ExecuteGraphQLSchema, ForkRepositorySchema, HealthCheckSchema, GetBranchDiffsSchema, GetCommitDiffSchema, GetCommitSchema, GetDeploymentSchema, GetDraftNoteSchema, GetEnvironmentSchema, GetFileContentsSchema, GetGroupWikiPageSchema, GetIssueLinkSchema, GetIssueSchema, GetJobArtifactFileSchema, GetLabelSchema, GetMergeRequestApprovalStateSchema, GetMergeRequestConflictsSchema, GetMergeRequestDiffsSchema, GetMergeRequestFileDiffSchema, GetMergeRequestNoteSchema, GetMergeRequestNotesSchema, GetMergeRequestSchema, GetMergeRequestVersionSchema, GetMilestoneBurndownEventsSchema, GetMilestoneIssuesSchema, GetMilestoneMergeRequestsSchema, GetNamespaceSchema, GetPipelineJobOutputSchema, GetPipelineSchema, GetProjectEventsSchema, GetProjectMilestoneSchema, GetProjectSchema, GetReleaseSchema, GetRepositoryTreeSchema, GetTagSchema, GetTagSignatureSchema, GetTimelineEventsSchema, GetUsersSchema, GetUserSchema, WhoAmISchema, GetWebhookEventSchema, GetWikiPageSchema, GetWorkItemSchema, ListCommitsSchema, ListCommitStatusesSchema, ListCustomFieldDefinitionsSchema, ListDeploymentsSchema, ListDraftNotesSchema, ListEnvironmentsSchema, ListEventsSchema, ListGroupIterationsSchema, ListGroupProjectsSchema, ListGroupWikiPagesSchema, ListIssueDiscussionsSchema, ListIssueLinksSchema, ListIssuesSchema, ListJobArtifactsSchema, ListLabelsSchema, ListMergeRequestChangedFilesSchema, ListMergeRequestDiffsSchema, ListMergeRequestDiscussionsSchema, ListMergeRequestPipelinesSchema, ListMergeRequestVersionsSchema, ListMergeRequestsSchema, ListNamespacesSchema, ListPipelineJobsSchema, ListPipelineTriggerJobsSchema, ValidateCiLintSchema, ValidateProjectCiLintSchema, ListPipelinesSchema, ListProjectMembersSchema, ListProjectMilestonesSchema, ListProjectsSchema, ListReleasesSchema, ListTagsSchema, ListWebhookEventsSchema, ListWebhooksSchema, ListWikiPagesSchema, ListWorkItemNotesSchema, ListWorkItemStatusesSchema, ListWorkItemsSchema, MarkdownUploadSchema, MergeMergeRequestSchema, MoveWorkItemSchema, MyIssuesSchema, PlayPipelineJobSchema, PromoteProjectMilestoneSchema, PublishDraftNoteSchema, PushFilesSchema, ResolveMergeRequestThreadSchema, RetryPipelineJobSchema, RetryPipelineSchema, SearchCodeSchema, SearchGroupCodeSchema, SearchProjectCodeSchema, SearchRepositoriesSchema, UnapproveMergeRequestSchema, UpdateDraftNoteSchema, UpdateGroupWikiPageSchema, UpdateIssueNoteSchema, UpdateIssueSchema, UpdateLabelSchema, UpdateMergeRequestDiscussionNoteSchema, UpdateMergeRequestNoteSchema, UpdateMergeRequestSchema, UpdateReleaseSchema, UpdateWikiPageSchema, UpdateWorkItemSchema, VerifyNamespaceSchema, } from "../schemas.js";
5
5
  // Define all available tools
6
6
  export const allTools = [
7
7
  {
@@ -29,6 +29,11 @@ export const allTools = [
29
29
  description: "Get the conflicts of a merge request",
30
30
  inputSchema: toJSONSchema(GetMergeRequestConflictsSchema),
31
31
  },
32
+ {
33
+ name: "list_merge_request_pipelines",
34
+ description: "List pipelines for a merge request with pagination",
35
+ inputSchema: toJSONSchema(ListMergeRequestPipelinesSchema),
36
+ },
32
37
  {
33
38
  name: "execute_graphql",
34
39
  description: "Execute a GitLab GraphQL query",
@@ -631,6 +636,16 @@ export const allTools = [
631
636
  description: "Get GitLab user details by usernames",
632
637
  inputSchema: toJSONSchema(GetUsersSchema),
633
638
  },
639
+ {
640
+ name: "get_user",
641
+ description: "Get user details by ID",
642
+ inputSchema: toJSONSchema(GetUserSchema),
643
+ },
644
+ {
645
+ name: "whoami",
646
+ description: "Get current authenticated user details",
647
+ inputSchema: toJSONSchema(WhoAmISchema),
648
+ },
634
649
  {
635
650
  name: "list_commits",
636
651
  description: "List repository commits with filtering options",
@@ -671,6 +686,11 @@ export const allTools = [
671
686
  description: "Download an uploaded file from a project (images returned as base64; use local_path to save to disk)",
672
687
  inputSchema: toJSONSchema(DownloadAttachmentSchema),
673
688
  },
689
+ {
690
+ name: "health_check",
691
+ description: "Verify server status and authentication",
692
+ inputSchema: toJSONSchema(HealthCheckSchema),
693
+ },
674
694
  {
675
695
  name: "list_events",
676
696
  description: "List events for the authenticated user (before/after: YYYY-MM-DD)",
@@ -882,6 +902,7 @@ export const allTools = [
882
902
  // Define which tools are read-only
883
903
  export const readOnlyTools = new Set([
884
904
  "discover_tools",
905
+ "health_check",
885
906
  "search_repositories",
886
907
  "search_code",
887
908
  "search_project_code",
@@ -896,6 +917,7 @@ export const readOnlyTools = new Set([
896
917
  "list_merge_request_versions",
897
918
  "get_merge_request_version",
898
919
  "get_branch_diffs",
920
+ "list_merge_request_pipelines",
899
921
  "get_merge_request_note",
900
922
  "get_merge_request_notes",
901
923
  "get_draft_note",
@@ -944,6 +966,8 @@ export const readOnlyTools = new Set([
944
966
  "list_group_wiki_pages",
945
967
  "get_group_wiki_page",
946
968
  "get_users",
969
+ "get_user",
970
+ "whoami",
947
971
  "list_commits",
948
972
  "get_commit",
949
973
  "get_commit_diff",
@@ -1059,6 +1083,7 @@ export const TOOLSET_DEFINITIONS = [
1059
1083
  "unapprove_merge_request",
1060
1084
  "get_merge_request_approval_state",
1061
1085
  "get_merge_request_conflicts",
1086
+ "list_merge_request_pipelines",
1062
1087
  "get_merge_request",
1063
1088
  "get_merge_request_diffs",
1064
1089
  "list_merge_request_changed_files",
@@ -1162,6 +1187,7 @@ export const TOOLSET_DEFINITIONS = [
1162
1187
  "verify_namespace",
1163
1188
  "list_group_projects",
1164
1189
  "list_group_iterations",
1190
+ "health_check",
1165
1191
  ]),
1166
1192
  },
1167
1193
  {
@@ -1265,6 +1291,8 @@ export const TOOLSET_DEFINITIONS = [
1265
1291
  isDefault: true,
1266
1292
  tools: new Set([
1267
1293
  "get_users",
1294
+ "get_user",
1295
+ "whoami",
1268
1296
  "list_events",
1269
1297
  "get_project_events",
1270
1298
  "upload_markdown",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zereight/mcp-gitlab",
3
- "version": "2.1.10",
3
+ "version": "2.1.11",
4
4
  "mcpName": "io.github.zereight/gitlab-mcp",
5
5
  "description": "GitLab MCP server for projects, merge requests, issues, pipelines, wiki, releases, and more",
6
6
  "keywords": [
@@ -51,7 +51,7 @@
51
51
  "changelog": "auto-changelog -p",
52
52
  "test": "npm run test:all",
53
53
  "test:all": "npm run build && npm run test:mock && npm run test:live",
54
- "test:mock": "node --import tsx/esm --test test/remote-auth-simple-test.ts && node --import tsx/esm --test test/mcp-oauth-tests.ts && node --import tsx/esm --test test/streamable-http-static-token-auth.test.ts && tsx test/oauth-tests.ts && tsx test/test-list-merge-requests.ts && tsx test/test-list-project-members.ts && tsx test/test-download-attachment.ts && node --import tsx/esm --test test/test-job-artifacts.ts && node --import tsx/esm --test test/test-deployment-tools.ts && node --import tsx/esm --test test/test-merge-request-approval-state-tools.ts && node --import tsx/esm --test test/test-search-code.ts && node --import tsx/esm --test test/test-tags.ts && node --import tsx/esm --test test/test-toolset-filtering.ts && node --import tsx/esm --test test/test-ci-lint.ts && node --import tsx/esm --test test/test-todos.ts && node --import tsx/esm --test test/test-auth-retry.ts && node --import tsx/esm --test test/stateless/codec.test.ts test/stateless/client-id.test.ts test/stateless/callback-proxy.test.ts test/stateless/session-id.test.ts test/stateless/session-id-integration.test.ts test/stateless/config-ttl.test.ts",
54
+ "test:mock": "node --import tsx/esm --test test/remote-auth-simple-test.ts && node --import tsx/esm --test test/mcp-oauth-tests.ts && node --import tsx/esm --test test/streamable-http-static-token-auth.test.ts && tsx test/oauth-tests.ts && tsx test/test-list-merge-requests.ts && node --import tsx/esm --test test/test-merge-request-pipelines.ts && tsx test/test-list-project-members.ts && tsx test/test-download-attachment.ts && node --import tsx/esm --test test/test-job-artifacts.ts && node --import tsx/esm --test test/test-deployment-tools.ts && node --import tsx/esm --test test/test-merge-request-approval-state-tools.ts && node --import tsx/esm --test test/test-search-code.ts && node --import tsx/esm --test test/test-tags.ts && node --import tsx/esm --test test/test-toolset-filtering.ts && node --import tsx/esm --test test/test-ci-lint.ts && node --import tsx/esm --test test/test-todos.ts && node --import tsx/esm --test test/test-auth-retry.ts && node --import tsx/esm --test test/stateless/codec.test.ts test/stateless/client-id.test.ts test/stateless/callback-proxy.test.ts test/stateless/session-id.test.ts test/stateless/session-id-integration.test.ts test/stateless/config-ttl.test.ts",
55
55
  "test:stateless": "npm run build && node --import tsx/esm --test test/stateless/codec.test.ts test/stateless/client-id.test.ts test/stateless/callback-proxy.test.ts test/stateless/session-id.test.ts test/stateless/session-id-integration.test.ts test/stateless/config-ttl.test.ts",
56
56
  "test:mcp-oauth": "npm run build && node --import tsx/esm --test test/mcp-oauth-tests.ts",
57
57
  "test:live": "node test/validate-api.js",