@zereight/mcp-gitlab 2.1.58 → 2.1.60

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
@@ -104,14 +104,14 @@ import { parseSearchReplaceBlocks, applySearchReplace, applyUnifiedDiff, } from
104
104
  import { requireBearerAuth } from "@modelcontextprotocol/sdk/server/auth/middleware/bearerAuth.js";
105
105
  import { GitLabClientPool } from "./gitlab-client-pool.js";
106
106
  import { allTools, readOnlyTools, destructiveTools, deleteTools, parseEnabledToolsets, parseIndividualTools, buildFeatureFlagOverrides, isToolInEnabledToolset, TOOLSET_DEFINITIONS, ALL_TOOLSET_IDS, } from "./tools/registry.js";
107
- import { BulkPublishDraftNotesSchema, CancelPipelineJobSchema, CancelPipelineSchema, CreateBranchSchema, CreateDraftNoteSchema, CreateIssueLinkSchema, CreateIssueNoteSchema, CreateIssueSchema, CreateIssueEmojiReactionSchema, CreateIssueNoteEmojiReactionSchema, ListIssueEmojiReactionsSchema, ListIssueNoteEmojiReactionsSchema, CreateLabelSchema, // Added
108
- CreateMergeRequestNoteSchema, CreateMergeRequestDiscussionNoteSchema, CreateMergeRequestEmojiReactionSchema, CreateMergeRequestNoteEmojiReactionSchema, ListMergeRequestEmojiReactionsSchema, ListMergeRequestNoteEmojiReactionsSchema, CreateMergeRequestSchema, CreateMergeRequestThreadSchema, CreateNoteSchema, CreateCommitStatusSchema, CreateOrUpdateFileSchema, CreatePipelineSchema, CreateProjectMilestoneSchema, CreateGroupMilestoneSchema, CreateRepositorySchema, CreateGroupSchema, CreateWikiPageSchema, CreateGroupWikiPageSchema, DeleteBranchSchema, GetProtectedBranchSchema, ListProtectedBranchesSchema, ProtectBranchSchema, UnprotectBranchSchema, UpdateDefaultBranchSchema, DeleteDraftNoteSchema, DeleteGroupMilestoneSchema, DeleteGroupWikiPageSchema, DeleteIssueLinkSchema, DeleteIssueSchema, DeleteIssueEmojiReactionSchema, DeleteIssueNoteEmojiReactionSchema, DeleteLabelSchema, DeleteProjectMilestoneSchema, DeleteWikiPageSchema, DeleteMergeRequestNoteSchema, DeleteMergeRequestEmojiReactionSchema, DeleteMergeRequestNoteEmojiReactionSchema, EditProjectMilestoneSchema, EditGroupMilestoneSchema, ForkRepositorySchema, GetBranchDiffsSchema, GetBranchSchema, GetCommitDiffSchema, GetCommitSchema, GetFileBlameSchema, GitLabBlameEntrySchema, GetDraftNoteSchema, GetFileContentsSchema, GetIssueLinkSchema, GetIssueSchema, GetLabelSchema, GetMergeRequestDiffsSchema, GetMergeRequestSchema, GetMilestoneBurndownEventsSchema, GetMilestoneIssuesSchema, GetMilestoneMergeRequestsSchema, GetGroupMilestoneSchema, GetGroupMilestoneIssuesSchema, GetGroupMilestoneMergeRequestsSchema, GetGroupMilestoneBurndownEventsSchema, GetDeploymentSchema, GetEnvironmentSchema, GetNamespaceSchema, GitLabCiLintResultSchema, GetPipelineJobOutputSchema, PipelineJobControlSchema, GetPipelineSchema, GetProjectMilestoneSchema, GetProjectSchema, GetRepositoryTreeSchema, GetUsersSchema, GetUserSchema, GitLabUserFullSchema, WhoAmISchema, GitLabCurrentUserSchema, GetWikiPageSchema, GitLabCommitSchema, GitLabCommitStatusSchema, GitLabCompareResultSchema, GitLabContentSchema, GitLabCreateUpdateFileResponseSchema, GitLabDiffSchema,
107
+ import { BulkPublishDraftNotesSchema, CancelPipelineJobSchema, ErasePipelineJobSchema, CancelPipelineSchema, CreateBranchSchema, CreateDraftNoteSchema, CreateIssueLinkSchema, CreateIssueNoteSchema, CreateIssueSchema, CreateIssueEmojiReactionSchema, CreateIssueNoteEmojiReactionSchema, ListIssueEmojiReactionsSchema, ListIssueNoteEmojiReactionsSchema, CreateLabelSchema, // Added
108
+ CreateMergeRequestNoteSchema, CreateMergeRequestDiscussionNoteSchema, CreateMergeRequestEmojiReactionSchema, CreateMergeRequestNoteEmojiReactionSchema, ListMergeRequestEmojiReactionsSchema, ListMergeRequestNoteEmojiReactionsSchema, CreateMergeRequestSchema, CreateMergeRequestThreadSchema, CreateNoteSchema, CreateCommitStatusSchema, CreateOrUpdateFileSchema, CreatePipelineSchema, CreateProjectMilestoneSchema, CreateGroupMilestoneSchema, CreateRepositorySchema, CreateGroupSchema, CreateWikiPageSchema, CreateGroupWikiPageSchema, DeleteBranchSchema, GetProtectedBranchSchema, ListProtectedBranchesSchema, ProtectBranchSchema, UnprotectBranchSchema, UpdateDefaultBranchSchema, DeleteDraftNoteSchema, DeleteGroupMilestoneSchema, DeleteGroupWikiPageSchema, DeleteIssueLinkSchema, DeleteIssueSchema, DeleteIssueEmojiReactionSchema, DeleteIssueNoteEmojiReactionSchema, DeleteLabelSchema, DeleteProjectMilestoneSchema, DeleteWikiPageSchema, DeleteMergeRequestNoteSchema, DeleteMergeRequestEmojiReactionSchema, DeleteMergeRequestNoteEmojiReactionSchema, EditProjectMilestoneSchema, EditGroupMilestoneSchema, ForkRepositorySchema, GetBranchDiffsSchema, GetBranchSchema, GetCommitDiffSchema, GetCommitSchema, GetFileBlameSchema, GitLabBlameEntrySchema, GetDraftNoteSchema, GetFileContentsSchema, GetIssueLinkSchema, GetIssueSchema, GetLabelSchema, GetMergeRequestDiffsSchema, GetMergeRequestSchema, GetMilestoneBurndownEventsSchema, GetMilestoneIssuesSchema, GetMilestoneMergeRequestsSchema, GetGroupMilestoneSchema, GetGroupMilestoneIssuesSchema, GetGroupMilestoneMergeRequestsSchema, GetGroupMilestoneBurndownEventsSchema, GetDeploymentSchema, CreateDeploymentSchema, UpdateDeploymentSchema, DeploymentApprovalSchema, ListDeploymentMergeRequestsSchema, GetEnvironmentSchema, UpdateEnvironmentSchema, StopEnvironmentSchema, StopStaleEnvironmentsSchema, DeleteReviewAppEnvironmentsSchema, PipelineTriggerIdSchema, ListPipelineTriggersSchema, CreatePipelineTriggerSchema, UpdatePipelineTriggerSchema, TriggerPipelineSchema, GetNamespaceSchema, GitLabCiLintResultSchema, GetPipelineJobOutputSchema, PipelineJobControlSchema, GetPipelineSchema, GetPipelineVariablesSchema, UpdatePipelineMetadataSchema, DeletePipelineSchema, PipelineReportSchema, WaitForPipelineSchema, WaitForPipelineJobSchema, PlayPipelineJobsSchema, GetProjectMilestoneSchema, GetProjectSchema, GetRepositoryTreeSchema, GetUsersSchema, GetUserSchema, GitLabUserFullSchema, WhoAmISchema, GitLabCurrentUserSchema, GetWikiPageSchema, GitLabCommitSchema, GitLabCommitStatusSchema, GitLabCompareResultSchema, GitLabContentSchema, GitLabCreateUpdateFileResponseSchema, GitLabDiffSchema,
109
109
  // Discussion Schemas
110
110
  GitLabDiscussionNoteSchema, // Added
111
111
  GitLabDiscussionSchema,
112
112
  // Draft Notes Schemas
113
113
  GitLabDraftNoteSchema, GitLabForkSchema, GitLabBranchSchema, GitLabProtectedBranchSchema, GitLabGroupSchema, GitLabIssueLinkSchema, GitLabIssueSchema, GitLabIssueWithLinkDetailsSchema, GitLabMarkdownUploadSchema, GitLabMergeRequestPipelineSchema, GitLabMergeRequestSchema, GitLabMilestonesSchema, GitLabGroupMilestonesSchema, GitLabNamespaceExistsResponseSchema, GitLabNamespaceSchema, GitLabPipelineJobSchema, GitLabDeploymentSchema, GitLabEnvironmentSchema, GitLabPipelineSchema, GitLabPipelineScheduleSchema, GitLabPipelineScheduleVariableSchema, GitLabPipelineSchedulePlayResultSchema, ListPipelineSchedulesSchema, GetPipelineScheduleSchema, ListPipelineSchedulePipelinesSchema, CreatePipelineScheduleSchema, UpdatePipelineScheduleSchema, DeletePipelineScheduleSchema, PlayPipelineScheduleSchema, TakeOwnershipPipelineScheduleSchema, GetPipelineScheduleVariableSchema, CreatePipelineScheduleVariableSchema, UpdatePipelineScheduleVariableSchema, DeletePipelineScheduleVariableSchema, GitLabPipelineTriggerJobSchema, GitLabProjectMemberSchema, GitLabProjectSchema, GitLabTodoSchema, GitLabReferenceSchema, GitLabRepositorySchema, GitLabSearchBlobResultSchema, GitLabSearchResponseSchema, GitLabTreeItemSchema, GitLabUserSchema, GitLabUsersResponseSchema, GitLabWikiPageSchema, GroupIteration, ListCommitStatusesSchema, ListBranchesSchema, ListCommitsSchema, ListDraftNotesSchema, ListGroupIterationsSchema, ListGroupProjectsSchema, GitLabCiVariableSchema, ListProjectVariablesSchema, GetProjectVariableSchema, CreateProjectVariableSchema, UpdateProjectVariableSchema, DeleteProjectVariableSchema, ListGroupVariablesSchema, GetGroupVariableSchema, CreateGroupVariableSchema, UpdateGroupVariableSchema, DeleteGroupVariableSchema, GitLabDependencyProxySchema, GitLabDependencyProxyBlobSchema, GetDependencyProxySettingsSchema, UpdateDependencyProxySettingsSchema, ListDependencyProxyBlobsSchema, PurgeDependencyProxyCacheSchema, ListProjectVulnerabilitiesSchema, GetVulnerabilitySchema, DismissVulnerabilitySchema, ConfirmVulnerabilitySchema, ListIssueDiscussionsSchema, ListIssueLinksSchema, ListIssuesSchema, ListTodosSchema, ListLabelsSchema, ListMergeRequestDiffsSchema, // Added
114
- GetMergeRequestFileDiffSchema, ListMergeRequestChangedFilesSchema, ListMergeRequestDiscussionsSchema, ListMergeRequestPipelinesSchema, ListMergeRequestsSchema, ListGroupMergeRequestsSchema, ListMergeRequestVersionsSchema, GetMergeRequestVersionSchema, GitLabMergeRequestVersionSchema, GitLabMergeRequestVersionDetailSchema, ListNamespacesSchema, ListPipelineJobsSchema, ListPipelinesSchema, ListDeploymentsSchema, ListEnvironmentsSchema, ListPipelineTriggerJobsSchema, ValidateCiLintSchema, ValidateProjectCiLintSchema, ListCiCatalogResourcesSchema, GetCiCatalogResourceSchema, ListProjectMembersSchema, ListGroupMembersSchema, ListProjectMilestonesSchema, ListGroupMilestonesSchema, ListProjectsSchema, ListWikiPagesSchema, GetGroupWikiPageSchema, ListGroupWikiPagesSchema, UpdateGroupWikiPageSchema, MarkdownUploadSchema, MarkdownUploadRemoteSchema, 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, UpdateIssueDescriptionPatchSchema, UpdateLabelSchema, UpdateProjectSchema, 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, CreateWebhookSchema, UpdateWebhookSchema, DeleteWebhookSchema, ListWebhookEventsSchema, GetWebhookEventSchema, HealthCheckSchema, } from "./schemas.js";
114
+ GetMergeRequestFileDiffSchema, ListMergeRequestChangedFilesSchema, ListMergeRequestDiscussionsSchema, ListMergeRequestPipelinesSchema, ListMergeRequestsSchema, ListGroupMergeRequestsSchema, ListMergeRequestVersionsSchema, GetMergeRequestVersionSchema, GitLabMergeRequestVersionSchema, GitLabMergeRequestVersionDetailSchema, ListNamespacesSchema, ListPipelineJobsSchema, ListPipelinesSchema, ListDeploymentsSchema, ListEnvironmentsSchema, ListPipelineTriggerJobsSchema, ValidateCiLintSchema, ValidateProjectCiLintSchema, ListCiCatalogResourcesSchema, GetCiCatalogResourceSchema, ListProjectMembersSchema, ListGroupMembersSchema, ListProjectMilestonesSchema, ListGroupMilestonesSchema, ListProjectsSchema, ListWikiPagesSchema, GetGroupWikiPageSchema, ListGroupWikiPagesSchema, UpdateGroupWikiPageSchema, MarkdownUploadSchema, MarkdownUploadRemoteSchema, DownloadAttachmentSchema, DownloadJobArtifactsSchema, GetJobArtifactFileSchema, GitLabArtifactEntrySchema, ListJobArtifactsSchema, MergeMergeRequestSchema, ApproveMergeRequestSchema, UnapproveMergeRequestSchema, GetMergeRequestApprovalStateSchema, GetMergeRequestConflictsSchema, GitLabMergeRequestApprovalsResponseSchema, GitLabMergeRequestApprovalStateSchema, MyIssuesSchema, OrbitQuerySchema, OrbitSchemaSchema, OrbitStatusSchema, OrbitToolsSchema, MarkAllTodosDoneSchema, MarkTodoDoneSchema, PaginatedDiscussionsResponseSchema, PromoteProjectMilestoneSchema, PublishDraftNoteSchema, PlayPipelineJobSchema, PushFilesSchema, RetryPipelineJobSchema, RetryPipelineSchema, SearchCodeSchema, SearchGroupCodeSchema, SearchProjectCodeSchema, SearchRepositoriesSchema, UpdateDraftNoteSchema, UpdateIssueNoteSchema, UpdateIssueSchema, UpdateIssueDescriptionPatchSchema, UpdateLabelSchema, UpdateProjectSchema, 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, CreateWebhookSchema, UpdateWebhookSchema, DeleteWebhookSchema, ListWebhookEventsSchema, GetWebhookEventSchema, HealthCheckSchema, } from "./schemas.js";
115
115
  import { randomUUID, timingSafeEqual, } from "node:crypto";
116
116
  import { createLogger } from "./utils/logger.js";
117
117
  const logger = createLogger();
@@ -5184,11 +5184,12 @@ async function listPipelines(projectId, options = {}) {
5184
5184
  * @param {number} pipelineId - The ID of the pipeline
5185
5185
  * @returns {Promise<GitLabPipeline>} Pipeline details
5186
5186
  */
5187
- async function getPipeline(projectId, pipelineId) {
5187
+ async function getPipeline(projectId, pipelineId, signal) {
5188
5188
  projectId = decodeURIComponent(projectId); // Decode project ID
5189
5189
  const url = new URL(`${getEffectiveApiUrl()}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/pipelines/${encodeGitLabPathSegment(pipelineId)}`);
5190
5190
  const response = await fetch(url.toString(), {
5191
5191
  ...getFetchConfig(),
5192
+ signal,
5192
5193
  });
5193
5194
  if (response.status === 404) {
5194
5195
  throw new Error(`Pipeline not found`);
@@ -5197,6 +5198,41 @@ async function getPipeline(projectId, pipelineId) {
5197
5198
  const data = await response.json();
5198
5199
  return GitLabPipelineSchema.parse(data);
5199
5200
  }
5201
+ async function getPipelineVariables(projectId, pipelineId, page, perPage) {
5202
+ projectId = decodeURIComponent(projectId);
5203
+ const url = new URL(`${getEffectiveApiUrl()}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/pipelines/${encodeGitLabPathSegment(pipelineId)}/variables`);
5204
+ if (page !== undefined)
5205
+ url.searchParams.set("page", String(page));
5206
+ if (perPage !== undefined)
5207
+ url.searchParams.set("per_page", String(perPage));
5208
+ const response = await fetch(url.toString(), { ...getFetchConfig() });
5209
+ await handleGitLabError(response);
5210
+ return response.json();
5211
+ }
5212
+ async function getPipelineReport(projectId, pipelineId, summary = false, page, perPage) {
5213
+ projectId = decodeURIComponent(projectId);
5214
+ const endpoint = summary ? "test_report_summary" : "test_report";
5215
+ const url = new URL(`${getEffectiveApiUrl()}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/pipelines/${encodeGitLabPathSegment(pipelineId)}/${endpoint}`);
5216
+ if (page !== undefined)
5217
+ url.searchParams.set("page", String(page));
5218
+ if (perPage !== undefined)
5219
+ url.searchParams.set("per_page", String(perPage));
5220
+ const response = await fetch(url.toString(), { ...getFetchConfig() });
5221
+ await handleGitLabError(response);
5222
+ return response.json();
5223
+ }
5224
+ async function deletePipeline(projectId, pipelineId) {
5225
+ projectId = decodeURIComponent(projectId);
5226
+ const response = await fetch(`${getEffectiveApiUrl()}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/pipelines/${encodeGitLabPathSegment(pipelineId)}`, { ...getFetchConfig(), method: "DELETE" });
5227
+ await handleGitLabError(response);
5228
+ return response.status === 204 ? { deleted: true } : response.json();
5229
+ }
5230
+ async function updatePipelineMetadata(projectId, pipelineId, name) {
5231
+ projectId = decodeURIComponent(projectId);
5232
+ const response = await fetch(`${getEffectiveApiUrl()}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/pipelines/${encodeGitLabPathSegment(pipelineId)}/metadata`, { ...getFetchConfig(), method: "PUT", body: JSON.stringify({ name }) });
5233
+ await handleGitLabError(response);
5234
+ return response.json();
5235
+ }
5200
5236
  /**
5201
5237
  * List deployments in a GitLab project
5202
5238
  *
@@ -5228,7 +5264,7 @@ async function listDeployments(projectId, options = {}) {
5228
5264
  */
5229
5265
  async function getDeployment(projectId, deploymentId) {
5230
5266
  projectId = decodeURIComponent(projectId);
5231
- const url = new URL(`${getEffectiveApiUrl()}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/deployments/${deploymentId}`);
5267
+ const url = new URL(`${getEffectiveApiUrl()}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/deployments/${encodeGitLabPathSegment(deploymentId)}`);
5232
5268
  const response = await fetch(url.toString(), {
5233
5269
  ...getFetchConfig(),
5234
5270
  });
@@ -5239,6 +5275,20 @@ async function getDeployment(projectId, deploymentId) {
5239
5275
  const data = await response.json();
5240
5276
  return GitLabDeploymentSchema.parse(data);
5241
5277
  }
5278
+ async function deploymentRequest(projectId, path = "", method = "GET", body, query) {
5279
+ projectId = decodeURIComponent(projectId);
5280
+ const url = new URL(`${getEffectiveApiUrl()}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/deployments${path}`);
5281
+ for (const [key, value] of Object.entries(query ?? {})) {
5282
+ if (value !== undefined)
5283
+ url.searchParams.set(key, String(value));
5284
+ }
5285
+ const response = await fetch(url.toString(), {
5286
+ ...getFetchConfig(), method,
5287
+ body: body === undefined ? undefined : JSON.stringify(body),
5288
+ });
5289
+ await handleGitLabError(response);
5290
+ return response.status === 204 ? { success: true } : response.json();
5291
+ }
5242
5292
  /**
5243
5293
  * List environments in a GitLab project
5244
5294
  *
@@ -5270,7 +5320,7 @@ async function listEnvironments(projectId, options = {}) {
5270
5320
  */
5271
5321
  async function getEnvironment(projectId, environmentId) {
5272
5322
  projectId = decodeURIComponent(projectId);
5273
- const url = new URL(`${getEffectiveApiUrl()}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/environments/${environmentId}`);
5323
+ const url = new URL(`${getEffectiveApiUrl()}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/environments/${encodeGitLabPathSegment(environmentId)}`);
5274
5324
  const response = await fetch(url.toString(), {
5275
5325
  ...getFetchConfig(),
5276
5326
  });
@@ -5281,6 +5331,36 @@ async function getEnvironment(projectId, environmentId) {
5281
5331
  const data = await response.json();
5282
5332
  return GitLabEnvironmentSchema.parse(data);
5283
5333
  }
5334
+ async function environmentRequest(projectId, path, method, body, query) {
5335
+ projectId = decodeURIComponent(projectId);
5336
+ const url = new URL(`${getEffectiveApiUrl()}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/environments${path}`);
5337
+ for (const [key, value] of Object.entries(query ?? {}))
5338
+ if (value !== undefined)
5339
+ url.searchParams.set(key, String(value));
5340
+ const response = await fetch(url.toString(), { ...getFetchConfig(), method, body: body === undefined ? undefined : JSON.stringify(body) });
5341
+ await handleGitLabError(response);
5342
+ return response.status === 204 ? { success: true } : response.json();
5343
+ }
5344
+ async function pipelineTriggerRequest(projectId, path = "", method = "GET", body) {
5345
+ projectId = decodeURIComponent(projectId);
5346
+ const response = await fetch(`${getEffectiveApiUrl()}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/triggers${path}`, { ...getFetchConfig(), method, body: body === undefined ? undefined : JSON.stringify(body) });
5347
+ await handleGitLabError(response);
5348
+ return response.status === 204 ? { success: true } : response.json();
5349
+ }
5350
+ async function triggerPipeline(projectId, token, ref, variables, inputs) {
5351
+ projectId = decodeURIComponent(projectId);
5352
+ const url = new URL(`${getEffectiveApiUrl()}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/trigger/pipeline`);
5353
+ url.searchParams.set("token", token);
5354
+ url.searchParams.set("ref", ref);
5355
+ const body = {};
5356
+ if (variables)
5357
+ body.variables = variables;
5358
+ if (inputs)
5359
+ body.inputs = inputs;
5360
+ const response = await fetch(url.toString(), { ...getFetchConfig(), method: "POST", body: Object.keys(body).length ? JSON.stringify(body) : undefined });
5361
+ await handleGitLabError(response);
5362
+ return response.json();
5363
+ }
5284
5364
  /**
5285
5365
  * List all jobs in a specific pipeline
5286
5366
  *
@@ -5345,11 +5425,12 @@ async function listPipelineTriggerJobs(projectId, pipelineId, options = {}) {
5345
5425
  const data = await response.json();
5346
5426
  return z.array(GitLabPipelineTriggerJobSchema).parse(data);
5347
5427
  }
5348
- async function getPipelineJob(projectId, jobId) {
5428
+ async function getPipelineJob(projectId, jobId, signal) {
5349
5429
  projectId = decodeURIComponent(projectId); // Decode project ID
5350
5430
  const url = new URL(`${getEffectiveApiUrl()}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/jobs/${encodeGitLabPathSegment(jobId)}`);
5351
5431
  const response = await fetch(url.toString(), {
5352
5432
  ...getFetchConfig(),
5433
+ signal,
5353
5434
  });
5354
5435
  if (response.status === 404) {
5355
5436
  throw new Error(`Job not found`);
@@ -5819,13 +5900,15 @@ async function deletePipelineScheduleVariable(projectId, pipelineScheduleId, key
5819
5900
  * @param {Object} variables - Optional job variables
5820
5901
  * @returns {Promise<GitLabPipelineJob>} The run job
5821
5902
  */
5822
- async function playPipelineJob(projectId, jobId, variables) {
5903
+ async function playPipelineJob(projectId, jobId, variables, jobInputs) {
5823
5904
  projectId = decodeURIComponent(projectId);
5824
5905
  const url = new URL(`${getEffectiveApiUrl()}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/jobs/${encodeGitLabPathSegment(jobId)}/play`);
5825
5906
  const body = {};
5826
5907
  if (variables && variables.length > 0) {
5827
5908
  body.job_variables_attributes = variables;
5828
5909
  }
5910
+ if (jobInputs)
5911
+ body.job_inputs = jobInputs;
5829
5912
  const response = await fetch(url.toString(), {
5830
5913
  ...getFetchConfig(),
5831
5914
  method: "POST",
@@ -5835,6 +5918,15 @@ async function playPipelineJob(projectId, jobId, variables) {
5835
5918
  const data = await response.json();
5836
5919
  return GitLabPipelineJobSchema.parse(data);
5837
5920
  }
5921
+ async function playPipelineJobs(projectId, jobIds, variables, timeoutSeconds = 300, pollIntervalSeconds = 5) {
5922
+ const jobs = [];
5923
+ for (const jobId of jobIds) {
5924
+ const played = await playPipelineJob(projectId, jobId, variables);
5925
+ const completed = await waitForStatus(signal => getPipelineJob(projectId, played.id, signal), TERMINAL_JOB_STATUSES, timeoutSeconds, pollIntervalSeconds);
5926
+ jobs.push(completed);
5927
+ }
5928
+ return jobs;
5929
+ }
5838
5930
  /**
5839
5931
  * Retry a job
5840
5932
  *
@@ -5842,17 +5934,46 @@ async function playPipelineJob(projectId, jobId, variables) {
5842
5934
  * @param {number} jobId - The ID of the job to retry
5843
5935
  * @returns {Promise<GitLabPipelineJob>} The retried job
5844
5936
  */
5845
- async function retryPipelineJob(projectId, jobId) {
5937
+ async function retryPipelineJob(projectId, jobId, jobInputs) {
5846
5938
  projectId = decodeURIComponent(projectId);
5847
5939
  const url = new URL(`${getEffectiveApiUrl()}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/jobs/${encodeGitLabPathSegment(jobId)}/retry`);
5848
5940
  const response = await fetch(url.toString(), {
5849
5941
  ...getFetchConfig(),
5850
5942
  method: "POST",
5943
+ body: jobInputs ? JSON.stringify({ job_inputs: jobInputs }) : undefined,
5851
5944
  });
5852
5945
  await handleGitLabError(response);
5853
5946
  const data = await response.json();
5854
5947
  return GitLabPipelineJobSchema.parse(data);
5855
5948
  }
5949
+ async function erasePipelineJob(projectId, jobId) {
5950
+ projectId = decodeURIComponent(projectId);
5951
+ const response = await fetch(`${getEffectiveApiUrl()}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/jobs/${encodeGitLabPathSegment(jobId)}/erase`, { ...getFetchConfig(), method: "POST" });
5952
+ await handleGitLabError(response);
5953
+ return response.status === 204 ? { erased: true } : response.json();
5954
+ }
5955
+ const TERMINAL_PIPELINE_STATUSES = new Set(["success", "failed", "canceled", "skipped", "manual"]);
5956
+ const TERMINAL_JOB_STATUSES = new Set(["success", "failed", "canceled", "skipped", "manual"]);
5957
+ async function waitForStatus(fetchStatus, terminalStatuses, timeoutSeconds = 300, pollIntervalSeconds = 5) {
5958
+ const deadline = Date.now() + timeoutSeconds * 1000;
5959
+ const fetchBeforeDeadline = async () => {
5960
+ const remaining = deadline - Date.now();
5961
+ if (remaining <= 0)
5962
+ throw new Error("Timed out waiting for terminal status");
5963
+ return fetchStatus(AbortSignal.timeout(remaining));
5964
+ };
5965
+ let value = await fetchBeforeDeadline();
5966
+ while (!terminalStatuses.has(value.status)) {
5967
+ const remaining = deadline - Date.now();
5968
+ if (remaining <= 0)
5969
+ break;
5970
+ await new Promise(resolve => setTimeout(resolve, Math.min(pollIntervalSeconds * 1000, remaining)));
5971
+ value = await fetchBeforeDeadline();
5972
+ }
5973
+ if (!terminalStatuses.has(value.status))
5974
+ throw new Error(`Timed out waiting for terminal status; last status: ${value.status}`);
5975
+ return value;
5976
+ }
5856
5977
  /**
5857
5978
  * Cancel a job
5858
5979
  *
@@ -7024,6 +7145,47 @@ async function listProjectVulnerabilities(projectId, options = {}) {
7024
7145
  pageInfo: data.project.vulnerabilities.pageInfo,
7025
7146
  };
7026
7147
  }
7148
+ /**
7149
+ * Execute a GitLab Orbit graph query.
7150
+ * Note: the `llm` format returns compact plain text, not JSON.
7151
+ */
7152
+ async function orbitQuery(query, format) {
7153
+ const url = new URL(`${getEffectiveApiUrl()}/orbit/query`);
7154
+ const response = await fetch(url.toString(), {
7155
+ ...getFetchConfig(),
7156
+ method: "POST",
7157
+ body: JSON.stringify({ query, format }),
7158
+ });
7159
+ await handleGitLabError(response);
7160
+ if (format === "raw") {
7161
+ return response.json();
7162
+ }
7163
+ return response.text();
7164
+ }
7165
+ async function orbitGetSchema() {
7166
+ const url = new URL(`${getEffectiveApiUrl()}/orbit/schema`);
7167
+ const response = await fetch(url.toString(), {
7168
+ ...getFetchConfig(),
7169
+ });
7170
+ await handleGitLabError(response);
7171
+ return response.json();
7172
+ }
7173
+ async function orbitGetStatus() {
7174
+ const url = new URL(`${getEffectiveApiUrl()}/orbit/status`);
7175
+ const response = await fetch(url.toString(), {
7176
+ ...getFetchConfig(),
7177
+ });
7178
+ await handleGitLabError(response);
7179
+ return response.json();
7180
+ }
7181
+ async function orbitListTools() {
7182
+ const url = new URL(`${getEffectiveApiUrl()}/orbit/tools`);
7183
+ const response = await fetch(url.toString(), {
7184
+ ...getFetchConfig(),
7185
+ });
7186
+ await handleGitLabError(response);
7187
+ return response.json();
7188
+ }
7027
7189
  async function getVulnerability(vulnerabilityId) {
7028
7190
  const data = await executeGraphQL(`query getVulnerability($id: VulnerabilityID!) {
7029
7191
  vulnerability(id: $id) {
@@ -8795,6 +8957,26 @@ async function handleToolCall(params) {
8795
8957
  ],
8796
8958
  };
8797
8959
  }
8960
+ case "get_pipeline_variables": {
8961
+ const { project_id, pipeline_id, page, per_page } = GetPipelineVariablesSchema.parse(params.arguments);
8962
+ return { content: [{ type: "text", text: JSON.stringify(await getPipelineVariables(project_id, pipeline_id, page, per_page)) }] };
8963
+ }
8964
+ case "get_pipeline_test_report": {
8965
+ const { project_id, pipeline_id, page, per_page } = PipelineReportSchema.parse(params.arguments);
8966
+ return { content: [{ type: "text", text: JSON.stringify(await getPipelineReport(project_id, pipeline_id, false, page, per_page)) }] };
8967
+ }
8968
+ case "get_pipeline_test_report_summary": {
8969
+ const { project_id, pipeline_id, page, per_page } = PipelineReportSchema.parse(params.arguments);
8970
+ return { content: [{ type: "text", text: JSON.stringify(await getPipelineReport(project_id, pipeline_id, true, page, per_page)) }] };
8971
+ }
8972
+ case "delete_pipeline": {
8973
+ const { project_id, pipeline_id } = DeletePipelineSchema.parse(params.arguments);
8974
+ return { content: [{ type: "text", text: JSON.stringify(await deletePipeline(project_id, pipeline_id)) }] };
8975
+ }
8976
+ case "update_pipeline_metadata": {
8977
+ const { project_id, pipeline_id, name } = UpdatePipelineMetadataSchema.parse(params.arguments);
8978
+ return { content: [{ type: "text", text: JSON.stringify(await updatePipelineMetadata(project_id, pipeline_id, name)) }] };
8979
+ }
8798
8980
  case "list_deployments": {
8799
8981
  const args = ListDeploymentsSchema.parse(params.arguments);
8800
8982
  const { project_id, ...options } = args;
@@ -8810,6 +8992,26 @@ async function handleToolCall(params) {
8810
8992
  content: [{ type: "text", text: JSON.stringify(deployment) }],
8811
8993
  };
8812
8994
  }
8995
+ case "create_deployment": {
8996
+ const { project_id, ...body } = CreateDeploymentSchema.parse(params.arguments);
8997
+ return { content: [{ type: "text", text: JSON.stringify(await deploymentRequest(project_id, "", "POST", body)) }] };
8998
+ }
8999
+ case "update_deployment": {
9000
+ const { project_id, deployment_id, ...body } = UpdateDeploymentSchema.parse(params.arguments);
9001
+ return { content: [{ type: "text", text: JSON.stringify(await deploymentRequest(project_id, `/${encodeGitLabPathSegment(deployment_id)}`, "PUT", body)) }] };
9002
+ }
9003
+ case "delete_deployment": {
9004
+ const { project_id, deployment_id } = GetDeploymentSchema.parse(params.arguments);
9005
+ return { content: [{ type: "text", text: JSON.stringify(await deploymentRequest(project_id, `/${encodeGitLabPathSegment(deployment_id)}`, "DELETE")) }] };
9006
+ }
9007
+ case "list_deployment_merge_requests": {
9008
+ const { project_id, deployment_id, ...query } = ListDeploymentMergeRequestsSchema.parse(params.arguments);
9009
+ return { content: [{ type: "text", text: JSON.stringify(await deploymentRequest(project_id, `/${encodeGitLabPathSegment(deployment_id)}/merge_requests`, "GET", undefined, query)) }] };
9010
+ }
9011
+ case "approve_deployment": {
9012
+ const { project_id, deployment_id, ...body } = DeploymentApprovalSchema.parse(params.arguments);
9013
+ return { content: [{ type: "text", text: JSON.stringify(await deploymentRequest(project_id, `/${encodeGitLabPathSegment(deployment_id)}/approval`, "POST", body)) }] };
9014
+ }
8813
9015
  case "list_environments": {
8814
9016
  const args = ListEnvironmentsSchema.parse(params.arguments);
8815
9017
  const { project_id, ...options } = args;
@@ -8825,6 +9027,50 @@ async function handleToolCall(params) {
8825
9027
  content: [{ type: "text", text: JSON.stringify(environment) }],
8826
9028
  };
8827
9029
  }
9030
+ case "update_environment": {
9031
+ const { project_id, environment_id, ...body } = UpdateEnvironmentSchema.parse(params.arguments);
9032
+ return { content: [{ type: "text", text: JSON.stringify(await environmentRequest(project_id, `/${encodeGitLabPathSegment(environment_id)}`, "PUT", body)) }] };
9033
+ }
9034
+ case "delete_environment": {
9035
+ const { project_id, environment_id } = GetEnvironmentSchema.parse(params.arguments);
9036
+ return { content: [{ type: "text", text: JSON.stringify(await environmentRequest(project_id, `/${encodeGitLabPathSegment(environment_id)}`, "DELETE")) }] };
9037
+ }
9038
+ case "stop_environment": {
9039
+ const { project_id, environment_id, force } = StopEnvironmentSchema.parse(params.arguments);
9040
+ return { content: [{ type: "text", text: JSON.stringify(await environmentRequest(project_id, `/${encodeGitLabPathSegment(environment_id)}/stop`, "POST", undefined, { force })) }] };
9041
+ }
9042
+ case "stop_stale_environments": {
9043
+ const { project_id, before } = StopStaleEnvironmentsSchema.parse(params.arguments);
9044
+ return { content: [{ type: "text", text: JSON.stringify(await environmentRequest(project_id, "/stop_stale", "POST", undefined, { before })) }] };
9045
+ }
9046
+ case "delete_review_app_environments": {
9047
+ const { project_id, ...query } = DeleteReviewAppEnvironmentsSchema.parse(params.arguments);
9048
+ return { content: [{ type: "text", text: JSON.stringify(await environmentRequest(project_id, "/review_apps", "DELETE", undefined, query)) }] };
9049
+ }
9050
+ case "list_pipeline_triggers": {
9051
+ const { project_id } = ListPipelineTriggersSchema.parse(params.arguments);
9052
+ return { content: [{ type: "text", text: JSON.stringify(redactSensitiveGitLabFields(await pipelineTriggerRequest(project_id))) }] };
9053
+ }
9054
+ case "get_pipeline_trigger": {
9055
+ const { project_id, trigger_id } = PipelineTriggerIdSchema.parse(params.arguments);
9056
+ return { content: [{ type: "text", text: JSON.stringify(redactSensitiveGitLabFields(await pipelineTriggerRequest(project_id, `/${encodeGitLabPathSegment(trigger_id)}`))) }] };
9057
+ }
9058
+ case "create_pipeline_trigger": {
9059
+ const { project_id, ...body } = CreatePipelineTriggerSchema.parse(params.arguments);
9060
+ return { content: [{ type: "text", text: JSON.stringify(await pipelineTriggerRequest(project_id, "", "POST", body)) }] };
9061
+ }
9062
+ case "update_pipeline_trigger": {
9063
+ const { project_id, trigger_id, ...body } = UpdatePipelineTriggerSchema.parse(params.arguments);
9064
+ return { content: [{ type: "text", text: JSON.stringify(redactSensitiveGitLabFields(await pipelineTriggerRequest(project_id, `/${encodeGitLabPathSegment(trigger_id)}`, "PUT", body))) }] };
9065
+ }
9066
+ case "delete_pipeline_trigger": {
9067
+ const { project_id, trigger_id } = PipelineTriggerIdSchema.parse(params.arguments);
9068
+ return { content: [{ type: "text", text: JSON.stringify(await pipelineTriggerRequest(project_id, `/${encodeGitLabPathSegment(trigger_id)}`, "DELETE")) }] };
9069
+ }
9070
+ case "trigger_pipeline": {
9071
+ const { project_id, token, ref, variables, inputs } = TriggerPipelineSchema.parse(params.arguments);
9072
+ return { content: [{ type: "text", text: JSON.stringify(await triggerPipeline(project_id, token, ref, variables, inputs)) }] };
9073
+ }
8828
9074
  case "list_pipeline_jobs": {
8829
9075
  const { project_id, pipeline_id, ...options } = ListPipelineJobsSchema.parse(params.arguments);
8830
9076
  const jobs = await listPipelineJobs(project_id, pipeline_id, options);
@@ -9178,8 +9424,8 @@ async function handleToolCall(params) {
9178
9424
  };
9179
9425
  }
9180
9426
  case "play_pipeline_job": {
9181
- const { project_id, job_id, job_variables_attributes } = PlayPipelineJobSchema.parse(params.arguments);
9182
- const job = await playPipelineJob(project_id, job_id, job_variables_attributes);
9427
+ const { project_id, job_id, job_variables_attributes, job_inputs } = PlayPipelineJobSchema.parse(params.arguments);
9428
+ const job = await playPipelineJob(project_id, job_id, job_variables_attributes, job_inputs);
9183
9429
  return {
9184
9430
  content: [
9185
9431
  {
@@ -9189,9 +9435,14 @@ async function handleToolCall(params) {
9189
9435
  ],
9190
9436
  };
9191
9437
  }
9438
+ case "play_pipeline_jobs": {
9439
+ const { project_id, job_ids, job_variables_attributes, timeout_seconds, poll_interval_seconds } = PlayPipelineJobsSchema.parse(params.arguments);
9440
+ const jobs = await playPipelineJobs(project_id, job_ids, job_variables_attributes, timeout_seconds, poll_interval_seconds);
9441
+ return { content: [{ type: "text", text: JSON.stringify(jobs) }] };
9442
+ }
9192
9443
  case "retry_pipeline_job": {
9193
- const { project_id, job_id } = RetryPipelineJobSchema.parse(params.arguments);
9194
- const job = await retryPipelineJob(project_id, job_id);
9444
+ const { project_id, job_id, job_inputs } = RetryPipelineJobSchema.parse(params.arguments);
9445
+ const job = await retryPipelineJob(project_id, job_id, job_inputs);
9195
9446
  return {
9196
9447
  content: [
9197
9448
  {
@@ -9213,6 +9464,20 @@ async function handleToolCall(params) {
9213
9464
  ],
9214
9465
  };
9215
9466
  }
9467
+ case "erase_pipeline_job": {
9468
+ const { project_id, job_id } = ErasePipelineJobSchema.parse(params.arguments);
9469
+ return { content: [{ type: "text", text: JSON.stringify(await erasePipelineJob(project_id, job_id)) }] };
9470
+ }
9471
+ case "wait_for_pipeline": {
9472
+ const { project_id, pipeline_id, timeout_seconds, poll_interval_seconds } = WaitForPipelineSchema.parse(params.arguments);
9473
+ const pipeline = await waitForStatus(signal => getPipeline(project_id, pipeline_id, signal), TERMINAL_PIPELINE_STATUSES, timeout_seconds, poll_interval_seconds);
9474
+ return { content: [{ type: "text", text: JSON.stringify(pipeline) }] };
9475
+ }
9476
+ case "wait_for_job": {
9477
+ const { project_id, job_id, timeout_seconds, poll_interval_seconds } = WaitForPipelineJobSchema.parse(params.arguments);
9478
+ const job = await waitForStatus(signal => getPipelineJob(project_id, job_id, signal), TERMINAL_JOB_STATUSES, timeout_seconds, poll_interval_seconds);
9479
+ return { content: [{ type: "text", text: JSON.stringify(job) }] };
9480
+ }
9216
9481
  case "list_job_artifacts": {
9217
9482
  const { project_id, job_id, ...options } = ListJobArtifactsSchema.parse(params.arguments);
9218
9483
  const artifacts = await listJobArtifacts(project_id, job_id, options);
@@ -9683,6 +9948,31 @@ async function handleToolCall(params) {
9683
9948
  const result = await confirmVulnerability(args.vulnerability_id, args.comment);
9684
9949
  return { content: [{ type: "text", text: JSON.stringify(result) }] };
9685
9950
  }
9951
+ case "orbit_query": {
9952
+ rejectIfStrictProjectScope("orbit_query");
9953
+ const args = OrbitQuerySchema.parse(params.arguments);
9954
+ const result = await orbitQuery(args.query, args.format);
9955
+ const text = typeof result === "string" ? result : JSON.stringify(result);
9956
+ return { content: [{ type: "text", text }] };
9957
+ }
9958
+ case "orbit_get_schema": {
9959
+ rejectIfStrictProjectScope("orbit_get_schema");
9960
+ OrbitSchemaSchema.parse(params.arguments);
9961
+ const result = await orbitGetSchema();
9962
+ return { content: [{ type: "text", text: JSON.stringify(result) }] };
9963
+ }
9964
+ case "orbit_get_status": {
9965
+ rejectIfStrictProjectScope("orbit_get_status");
9966
+ OrbitStatusSchema.parse(params.arguments);
9967
+ const result = await orbitGetStatus();
9968
+ return { content: [{ type: "text", text: JSON.stringify(result) }] };
9969
+ }
9970
+ case "orbit_list_tools": {
9971
+ rejectIfStrictProjectScope("orbit_list_tools");
9972
+ OrbitToolsSchema.parse(params.arguments);
9973
+ const result = await orbitListTools();
9974
+ return { content: [{ type: "text", text: JSON.stringify(result) }] };
9975
+ }
9686
9976
  case "upload_markdown": {
9687
9977
  if (IS_REMOTE) {
9688
9978
  const args = MarkdownUploadRemoteSchema.parse(params.arguments);