@zereight/mcp-gitlab 2.1.58 → 2.1.59
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.ko.md +13 -1
- package/README.md +13 -1
- package/README.zh-CN.md +13 -1
- package/build/index.js +236 -12
- package/build/schemas.js +137 -3
- package/build/scripts/check-skill-sync.js +5 -0
- package/build/test/test-deployment-tools.js +84 -1
- package/build/test/test-permission-mode.js +1 -0
- package/build/test/test-toolset-filtering.js +1 -1
- package/build/tools/registry.js +106 -2
- package/build/tools/tool-descriptions.js +2 -0
- package/build/utils/redact-sensitive.js +11 -4
- package/package.json +1 -1
package/README.ko.md
CHANGED
|
@@ -96,9 +96,21 @@ npm으로 설치할 수도 있습니다:
|
|
|
96
96
|
npm install -g @zereight/mcp-gitlab
|
|
97
97
|
```
|
|
98
98
|
|
|
99
|
+
또는 Nix를 사용해 이 플레이크를 자신의 플레이크에 추가할 수 있습니다:
|
|
100
|
+
|
|
101
|
+
```nix
|
|
102
|
+
# flake.nix
|
|
103
|
+
inputs.gitlab-mcp.url = "github:zereight/gitlab-mcp";
|
|
104
|
+
|
|
105
|
+
# wherever you configure your MCP client:
|
|
106
|
+
command = lib.getExe inputs.gitlab-mcp.packages.${system}.default;
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
스토어 경로는 lock 파일에 고정되며, `nix flake update gitlab-mcp`로 업데이트합니다.
|
|
110
|
+
|
|
99
111
|
예시는 기존 `mcp-gitlab`보다 충돌 가능성이 낮은 `zereight-mcp-gitlab` 별칭을 사용합니다. MCP 클라이언트가 찾지 못하면 `which zereight-mcp-gitlab`의 절대 경로를 사용하세요.
|
|
100
112
|
|
|
101
|
-
전역 설치를 쓰지 않으려면 `npx -y @zereight/mcp-gitlab@2.1.
|
|
113
|
+
전역 설치를 쓰지 않으려면 `npx -y @zereight/mcp-gitlab@2.1.58`처럼 직전 안정 버전(문서가 권장하는 버전)으로 고정하세요. 항상 최신 버전을 원하면 `npx -y @zereight/mcp-gitlab@latest`를 사용하세요. 새 버전이 나오면 서버가 시작 시 stderr로 알려줍니다(`GITLAB_DISABLE_VERSION_CHECK=true`로 비활성화 가능).
|
|
102
114
|
|
|
103
115
|
#### CLI 인자 사용하기(환경 변수 문제가 있는 클라이언트용)
|
|
104
116
|
|
package/README.md
CHANGED
|
@@ -101,9 +101,21 @@ Or with npm:
|
|
|
101
101
|
npm install -g @zereight/mcp-gitlab
|
|
102
102
|
```
|
|
103
103
|
|
|
104
|
+
Or with Nix, by adding this flake to your own:
|
|
105
|
+
|
|
106
|
+
```nix
|
|
107
|
+
# flake.nix
|
|
108
|
+
inputs.gitlab-mcp.url = "github:zereight/gitlab-mcp";
|
|
109
|
+
|
|
110
|
+
# wherever you configure your MCP client:
|
|
111
|
+
command = lib.getExe inputs.gitlab-mcp.packages.${system}.default;
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
The store path is pinned by your lock file; update it with `nix flake update gitlab-mcp`.
|
|
115
|
+
|
|
104
116
|
The examples use `zereight-mcp-gitlab`, a less collision-prone alias for the legacy `mcp-gitlab` binary. If your MCP client cannot find it, use the absolute path from `which zereight-mcp-gitlab`.
|
|
105
117
|
|
|
106
|
-
No global install? Pin `npx` to the previous stable release (the version these docs recommend), for example `npx -y @zereight/mcp-gitlab@2.1.
|
|
118
|
+
No global install? Pin `npx` to the previous stable release (the version these docs recommend), for example `npx -y @zereight/mcp-gitlab@2.1.58`. If you always want the newest release, use `npx -y @zereight/mcp-gitlab@latest` instead. The server prints a notice to stderr on startup when a newer version is available (disable with `GITLAB_DISABLE_VERSION_CHECK=true`).
|
|
107
119
|
|
|
108
120
|
#### Using CLI Arguments (for clients with env var issues)
|
|
109
121
|
|
package/README.zh-CN.md
CHANGED
|
@@ -96,9 +96,21 @@ brew install zereight/gitlab-mcp/zereight-mcp-gitlab
|
|
|
96
96
|
npm install -g @zereight/mcp-gitlab
|
|
97
97
|
```
|
|
98
98
|
|
|
99
|
+
也可以使用 Nix,把此 flake 添加到你自己的 flake 中:
|
|
100
|
+
|
|
101
|
+
```nix
|
|
102
|
+
# flake.nix
|
|
103
|
+
inputs.gitlab-mcp.url = "github:zereight/gitlab-mcp";
|
|
104
|
+
|
|
105
|
+
# wherever you configure your MCP client:
|
|
106
|
+
command = lib.getExe inputs.gitlab-mcp.packages.${system}.default;
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
存储路径由你的 lock 文件固定,使用 `nix flake update gitlab-mcp` 更新。
|
|
110
|
+
|
|
99
111
|
示例使用 `zereight-mcp-gitlab`,这是比旧的 `mcp-gitlab` 更不容易冲突的别名。如果 MCP 客户端找不到它,请使用 `which zereight-mcp-gitlab` 输出的绝对路径。
|
|
100
112
|
|
|
101
|
-
如果不想全局安装,请将 `npx` 固定到上一个稳定版本(即文档推荐的版本),例如 `npx -y @zereight/mcp-gitlab@2.1.
|
|
113
|
+
如果不想全局安装,请将 `npx` 固定到上一个稳定版本(即文档推荐的版本),例如 `npx -y @zereight/mcp-gitlab@2.1.58`。如果始终想使用最新版本,请改用 `npx -y @zereight/mcp-gitlab@latest`。有新版本发布时,服务器会在启动时通过 stderr 提示(可用 `GITLAB_DISABLE_VERSION_CHECK=true` 关闭)。
|
|
102
114
|
|
|
103
115
|
#### 使用 CLI 参数(适用于环境变量有问题的客户端)
|
|
104
116
|
|
package/build/index.js
CHANGED
|
@@ -104,8 +104,8 @@ 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,
|
|
@@ -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
|
*
|
|
@@ -8795,6 +8916,26 @@ async function handleToolCall(params) {
|
|
|
8795
8916
|
],
|
|
8796
8917
|
};
|
|
8797
8918
|
}
|
|
8919
|
+
case "get_pipeline_variables": {
|
|
8920
|
+
const { project_id, pipeline_id, page, per_page } = GetPipelineVariablesSchema.parse(params.arguments);
|
|
8921
|
+
return { content: [{ type: "text", text: JSON.stringify(await getPipelineVariables(project_id, pipeline_id, page, per_page)) }] };
|
|
8922
|
+
}
|
|
8923
|
+
case "get_pipeline_test_report": {
|
|
8924
|
+
const { project_id, pipeline_id, page, per_page } = PipelineReportSchema.parse(params.arguments);
|
|
8925
|
+
return { content: [{ type: "text", text: JSON.stringify(await getPipelineReport(project_id, pipeline_id, false, page, per_page)) }] };
|
|
8926
|
+
}
|
|
8927
|
+
case "get_pipeline_test_report_summary": {
|
|
8928
|
+
const { project_id, pipeline_id, page, per_page } = PipelineReportSchema.parse(params.arguments);
|
|
8929
|
+
return { content: [{ type: "text", text: JSON.stringify(await getPipelineReport(project_id, pipeline_id, true, page, per_page)) }] };
|
|
8930
|
+
}
|
|
8931
|
+
case "delete_pipeline": {
|
|
8932
|
+
const { project_id, pipeline_id } = DeletePipelineSchema.parse(params.arguments);
|
|
8933
|
+
return { content: [{ type: "text", text: JSON.stringify(await deletePipeline(project_id, pipeline_id)) }] };
|
|
8934
|
+
}
|
|
8935
|
+
case "update_pipeline_metadata": {
|
|
8936
|
+
const { project_id, pipeline_id, name } = UpdatePipelineMetadataSchema.parse(params.arguments);
|
|
8937
|
+
return { content: [{ type: "text", text: JSON.stringify(await updatePipelineMetadata(project_id, pipeline_id, name)) }] };
|
|
8938
|
+
}
|
|
8798
8939
|
case "list_deployments": {
|
|
8799
8940
|
const args = ListDeploymentsSchema.parse(params.arguments);
|
|
8800
8941
|
const { project_id, ...options } = args;
|
|
@@ -8810,6 +8951,26 @@ async function handleToolCall(params) {
|
|
|
8810
8951
|
content: [{ type: "text", text: JSON.stringify(deployment) }],
|
|
8811
8952
|
};
|
|
8812
8953
|
}
|
|
8954
|
+
case "create_deployment": {
|
|
8955
|
+
const { project_id, ...body } = CreateDeploymentSchema.parse(params.arguments);
|
|
8956
|
+
return { content: [{ type: "text", text: JSON.stringify(await deploymentRequest(project_id, "", "POST", body)) }] };
|
|
8957
|
+
}
|
|
8958
|
+
case "update_deployment": {
|
|
8959
|
+
const { project_id, deployment_id, ...body } = UpdateDeploymentSchema.parse(params.arguments);
|
|
8960
|
+
return { content: [{ type: "text", text: JSON.stringify(await deploymentRequest(project_id, `/${encodeGitLabPathSegment(deployment_id)}`, "PUT", body)) }] };
|
|
8961
|
+
}
|
|
8962
|
+
case "delete_deployment": {
|
|
8963
|
+
const { project_id, deployment_id } = GetDeploymentSchema.parse(params.arguments);
|
|
8964
|
+
return { content: [{ type: "text", text: JSON.stringify(await deploymentRequest(project_id, `/${encodeGitLabPathSegment(deployment_id)}`, "DELETE")) }] };
|
|
8965
|
+
}
|
|
8966
|
+
case "list_deployment_merge_requests": {
|
|
8967
|
+
const { project_id, deployment_id, ...query } = ListDeploymentMergeRequestsSchema.parse(params.arguments);
|
|
8968
|
+
return { content: [{ type: "text", text: JSON.stringify(await deploymentRequest(project_id, `/${encodeGitLabPathSegment(deployment_id)}/merge_requests`, "GET", undefined, query)) }] };
|
|
8969
|
+
}
|
|
8970
|
+
case "approve_deployment": {
|
|
8971
|
+
const { project_id, deployment_id, ...body } = DeploymentApprovalSchema.parse(params.arguments);
|
|
8972
|
+
return { content: [{ type: "text", text: JSON.stringify(await deploymentRequest(project_id, `/${encodeGitLabPathSegment(deployment_id)}/approval`, "POST", body)) }] };
|
|
8973
|
+
}
|
|
8813
8974
|
case "list_environments": {
|
|
8814
8975
|
const args = ListEnvironmentsSchema.parse(params.arguments);
|
|
8815
8976
|
const { project_id, ...options } = args;
|
|
@@ -8825,6 +8986,50 @@ async function handleToolCall(params) {
|
|
|
8825
8986
|
content: [{ type: "text", text: JSON.stringify(environment) }],
|
|
8826
8987
|
};
|
|
8827
8988
|
}
|
|
8989
|
+
case "update_environment": {
|
|
8990
|
+
const { project_id, environment_id, ...body } = UpdateEnvironmentSchema.parse(params.arguments);
|
|
8991
|
+
return { content: [{ type: "text", text: JSON.stringify(await environmentRequest(project_id, `/${encodeGitLabPathSegment(environment_id)}`, "PUT", body)) }] };
|
|
8992
|
+
}
|
|
8993
|
+
case "delete_environment": {
|
|
8994
|
+
const { project_id, environment_id } = GetEnvironmentSchema.parse(params.arguments);
|
|
8995
|
+
return { content: [{ type: "text", text: JSON.stringify(await environmentRequest(project_id, `/${encodeGitLabPathSegment(environment_id)}`, "DELETE")) }] };
|
|
8996
|
+
}
|
|
8997
|
+
case "stop_environment": {
|
|
8998
|
+
const { project_id, environment_id, force } = StopEnvironmentSchema.parse(params.arguments);
|
|
8999
|
+
return { content: [{ type: "text", text: JSON.stringify(await environmentRequest(project_id, `/${encodeGitLabPathSegment(environment_id)}/stop`, "POST", undefined, { force })) }] };
|
|
9000
|
+
}
|
|
9001
|
+
case "stop_stale_environments": {
|
|
9002
|
+
const { project_id, before } = StopStaleEnvironmentsSchema.parse(params.arguments);
|
|
9003
|
+
return { content: [{ type: "text", text: JSON.stringify(await environmentRequest(project_id, "/stop_stale", "POST", undefined, { before })) }] };
|
|
9004
|
+
}
|
|
9005
|
+
case "delete_review_app_environments": {
|
|
9006
|
+
const { project_id, ...query } = DeleteReviewAppEnvironmentsSchema.parse(params.arguments);
|
|
9007
|
+
return { content: [{ type: "text", text: JSON.stringify(await environmentRequest(project_id, "/review_apps", "DELETE", undefined, query)) }] };
|
|
9008
|
+
}
|
|
9009
|
+
case "list_pipeline_triggers": {
|
|
9010
|
+
const { project_id } = ListPipelineTriggersSchema.parse(params.arguments);
|
|
9011
|
+
return { content: [{ type: "text", text: JSON.stringify(redactSensitiveGitLabFields(await pipelineTriggerRequest(project_id))) }] };
|
|
9012
|
+
}
|
|
9013
|
+
case "get_pipeline_trigger": {
|
|
9014
|
+
const { project_id, trigger_id } = PipelineTriggerIdSchema.parse(params.arguments);
|
|
9015
|
+
return { content: [{ type: "text", text: JSON.stringify(redactSensitiveGitLabFields(await pipelineTriggerRequest(project_id, `/${encodeGitLabPathSegment(trigger_id)}`))) }] };
|
|
9016
|
+
}
|
|
9017
|
+
case "create_pipeline_trigger": {
|
|
9018
|
+
const { project_id, ...body } = CreatePipelineTriggerSchema.parse(params.arguments);
|
|
9019
|
+
return { content: [{ type: "text", text: JSON.stringify(await pipelineTriggerRequest(project_id, "", "POST", body)) }] };
|
|
9020
|
+
}
|
|
9021
|
+
case "update_pipeline_trigger": {
|
|
9022
|
+
const { project_id, trigger_id, ...body } = UpdatePipelineTriggerSchema.parse(params.arguments);
|
|
9023
|
+
return { content: [{ type: "text", text: JSON.stringify(redactSensitiveGitLabFields(await pipelineTriggerRequest(project_id, `/${encodeGitLabPathSegment(trigger_id)}`, "PUT", body))) }] };
|
|
9024
|
+
}
|
|
9025
|
+
case "delete_pipeline_trigger": {
|
|
9026
|
+
const { project_id, trigger_id } = PipelineTriggerIdSchema.parse(params.arguments);
|
|
9027
|
+
return { content: [{ type: "text", text: JSON.stringify(await pipelineTriggerRequest(project_id, `/${encodeGitLabPathSegment(trigger_id)}`, "DELETE")) }] };
|
|
9028
|
+
}
|
|
9029
|
+
case "trigger_pipeline": {
|
|
9030
|
+
const { project_id, token, ref, variables, inputs } = TriggerPipelineSchema.parse(params.arguments);
|
|
9031
|
+
return { content: [{ type: "text", text: JSON.stringify(await triggerPipeline(project_id, token, ref, variables, inputs)) }] };
|
|
9032
|
+
}
|
|
8828
9033
|
case "list_pipeline_jobs": {
|
|
8829
9034
|
const { project_id, pipeline_id, ...options } = ListPipelineJobsSchema.parse(params.arguments);
|
|
8830
9035
|
const jobs = await listPipelineJobs(project_id, pipeline_id, options);
|
|
@@ -9178,8 +9383,8 @@ async function handleToolCall(params) {
|
|
|
9178
9383
|
};
|
|
9179
9384
|
}
|
|
9180
9385
|
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);
|
|
9386
|
+
const { project_id, job_id, job_variables_attributes, job_inputs } = PlayPipelineJobSchema.parse(params.arguments);
|
|
9387
|
+
const job = await playPipelineJob(project_id, job_id, job_variables_attributes, job_inputs);
|
|
9183
9388
|
return {
|
|
9184
9389
|
content: [
|
|
9185
9390
|
{
|
|
@@ -9189,9 +9394,14 @@ async function handleToolCall(params) {
|
|
|
9189
9394
|
],
|
|
9190
9395
|
};
|
|
9191
9396
|
}
|
|
9397
|
+
case "play_pipeline_jobs": {
|
|
9398
|
+
const { project_id, job_ids, job_variables_attributes, timeout_seconds, poll_interval_seconds } = PlayPipelineJobsSchema.parse(params.arguments);
|
|
9399
|
+
const jobs = await playPipelineJobs(project_id, job_ids, job_variables_attributes, timeout_seconds, poll_interval_seconds);
|
|
9400
|
+
return { content: [{ type: "text", text: JSON.stringify(jobs) }] };
|
|
9401
|
+
}
|
|
9192
9402
|
case "retry_pipeline_job": {
|
|
9193
|
-
const { project_id, job_id } = RetryPipelineJobSchema.parse(params.arguments);
|
|
9194
|
-
const job = await retryPipelineJob(project_id, job_id);
|
|
9403
|
+
const { project_id, job_id, job_inputs } = RetryPipelineJobSchema.parse(params.arguments);
|
|
9404
|
+
const job = await retryPipelineJob(project_id, job_id, job_inputs);
|
|
9195
9405
|
return {
|
|
9196
9406
|
content: [
|
|
9197
9407
|
{
|
|
@@ -9213,6 +9423,20 @@ async function handleToolCall(params) {
|
|
|
9213
9423
|
],
|
|
9214
9424
|
};
|
|
9215
9425
|
}
|
|
9426
|
+
case "erase_pipeline_job": {
|
|
9427
|
+
const { project_id, job_id } = ErasePipelineJobSchema.parse(params.arguments);
|
|
9428
|
+
return { content: [{ type: "text", text: JSON.stringify(await erasePipelineJob(project_id, job_id)) }] };
|
|
9429
|
+
}
|
|
9430
|
+
case "wait_for_pipeline": {
|
|
9431
|
+
const { project_id, pipeline_id, timeout_seconds, poll_interval_seconds } = WaitForPipelineSchema.parse(params.arguments);
|
|
9432
|
+
const pipeline = await waitForStatus(signal => getPipeline(project_id, pipeline_id, signal), TERMINAL_PIPELINE_STATUSES, timeout_seconds, poll_interval_seconds);
|
|
9433
|
+
return { content: [{ type: "text", text: JSON.stringify(pipeline) }] };
|
|
9434
|
+
}
|
|
9435
|
+
case "wait_for_job": {
|
|
9436
|
+
const { project_id, job_id, timeout_seconds, poll_interval_seconds } = WaitForPipelineJobSchema.parse(params.arguments);
|
|
9437
|
+
const job = await waitForStatus(signal => getPipelineJob(project_id, job_id, signal), TERMINAL_JOB_STATUSES, timeout_seconds, poll_interval_seconds);
|
|
9438
|
+
return { content: [{ type: "text", text: JSON.stringify(job) }] };
|
|
9439
|
+
}
|
|
9216
9440
|
case "list_job_artifacts": {
|
|
9217
9441
|
const { project_id, job_id, ...options } = ListJobArtifactsSchema.parse(params.arguments);
|
|
9218
9442
|
const artifacts = await listJobArtifacts(project_id, job_id, options);
|
package/build/schemas.js
CHANGED
|
@@ -119,6 +119,8 @@ export const GitLabPipelineJobSchema = z.object({
|
|
|
119
119
|
web_url: z.string().optional(),
|
|
120
120
|
allow_failure: z.coerce.boolean().optional(),
|
|
121
121
|
retried: z.coerce.boolean().optional(),
|
|
122
|
+
when: z.string().optional(),
|
|
123
|
+
needs: z.array(z.unknown()).optional(),
|
|
122
124
|
tag_list: z.array(z.string()).optional(),
|
|
123
125
|
runner: z
|
|
124
126
|
.object({
|
|
@@ -257,6 +259,38 @@ export const GetPipelineSchema = z.object({
|
|
|
257
259
|
project_id: z.coerce.string().describe("Project ID or URL-encoded path"),
|
|
258
260
|
pipeline_id: z.coerce.string().describe("The ID of the pipeline"),
|
|
259
261
|
});
|
|
262
|
+
export const GetPipelineVariablesSchema = GetPipelineSchema.merge(PaginationOptionsSchema);
|
|
263
|
+
export const UpdatePipelineMetadataSchema = GetPipelineSchema.extend({
|
|
264
|
+
name: z.string().min(1).describe("New pipeline name"),
|
|
265
|
+
});
|
|
266
|
+
export const DeletePipelineSchema = GetPipelineSchema;
|
|
267
|
+
export const PipelineReportSchema = GetPipelineSchema.merge(PaginationOptionsSchema);
|
|
268
|
+
export const PlayPipelineJobsSchema = z.object({
|
|
269
|
+
project_id: z.coerce.string().describe("Project ID or URL-encoded path"),
|
|
270
|
+
job_ids: z
|
|
271
|
+
.array(z.coerce.string())
|
|
272
|
+
.min(1)
|
|
273
|
+
.refine((jobIds) => new Set(jobIds).size === jobIds.length, "job_ids must not contain duplicates")
|
|
274
|
+
.describe("Job IDs to play, in dependency order"),
|
|
275
|
+
job_variables_attributes: z
|
|
276
|
+
.array(z.object({ key: z.string(), value: z.string() }))
|
|
277
|
+
.optional()
|
|
278
|
+
.describe("Custom job variables to use when running each job"),
|
|
279
|
+
timeout_seconds: z.coerce
|
|
280
|
+
.number()
|
|
281
|
+
.int()
|
|
282
|
+
.min(1)
|
|
283
|
+
.max(600)
|
|
284
|
+
.optional()
|
|
285
|
+
.describe("Maximum seconds to wait for each job to reach a terminal status (applied per job; total duration scales with the batch size)"),
|
|
286
|
+
poll_interval_seconds: z.coerce
|
|
287
|
+
.number()
|
|
288
|
+
.int()
|
|
289
|
+
.min(1)
|
|
290
|
+
.max(30)
|
|
291
|
+
.optional()
|
|
292
|
+
.describe("Seconds between status polls while waiting for each job"),
|
|
293
|
+
});
|
|
260
294
|
export const GitLabMergeRequestPipelineSchema = z.object({
|
|
261
295
|
id: z.coerce.string(),
|
|
262
296
|
sha: z.string(),
|
|
@@ -380,6 +414,28 @@ export const GetCiCatalogResourceSchema = z.union([
|
|
|
380
414
|
message: "Provide exactly one of id or full_path",
|
|
381
415
|
});
|
|
382
416
|
// Deployment related schemas
|
|
417
|
+
const GitLabDeploymentApprovalUserSchema = z.object({
|
|
418
|
+
id: z.coerce.string().optional(),
|
|
419
|
+
username: z.string().optional(),
|
|
420
|
+
name: z.string().optional(),
|
|
421
|
+
state: z.string().optional(),
|
|
422
|
+
avatar_url: z.string().nullable().optional(),
|
|
423
|
+
web_url: z.string().optional(),
|
|
424
|
+
});
|
|
425
|
+
const GitLabDeploymentApprovalSchema = z.object({
|
|
426
|
+
user: GitLabDeploymentApprovalUserSchema.optional(),
|
|
427
|
+
status: z.string().optional(),
|
|
428
|
+
created_at: z.string().optional(),
|
|
429
|
+
comment: z.string().nullable().optional(),
|
|
430
|
+
});
|
|
431
|
+
const GitLabDeploymentApprovalRuleSchema = z.object({
|
|
432
|
+
user_id: z.coerce.string().nullable().optional(),
|
|
433
|
+
group_id: z.coerce.string().nullable().optional(),
|
|
434
|
+
access_level: z.coerce.number().nullable().optional(),
|
|
435
|
+
access_level_description: z.string().nullable().optional(),
|
|
436
|
+
required_approvals: z.coerce.number().optional(),
|
|
437
|
+
deployment_approvals: z.array(GitLabDeploymentApprovalSchema).optional(),
|
|
438
|
+
});
|
|
383
439
|
export const GitLabDeploymentSchema = z.object({
|
|
384
440
|
id: z.coerce.string(),
|
|
385
441
|
iid: z.coerce.string().optional(),
|
|
@@ -427,6 +483,11 @@ export const GitLabDeploymentSchema = z.object({
|
|
|
427
483
|
})
|
|
428
484
|
.optional(),
|
|
429
485
|
web_url: z.string().optional(),
|
|
486
|
+
pending_approval_count: z.coerce.number().optional(),
|
|
487
|
+
approvals: z.array(GitLabDeploymentApprovalSchema).optional(),
|
|
488
|
+
approval_summary: z
|
|
489
|
+
.object({ rules: z.array(GitLabDeploymentApprovalRuleSchema).optional() })
|
|
490
|
+
.optional(),
|
|
430
491
|
});
|
|
431
492
|
export const ListDeploymentsSchema = z
|
|
432
493
|
.object({
|
|
@@ -457,6 +518,19 @@ export const GetDeploymentSchema = z.object({
|
|
|
457
518
|
project_id: z.coerce.string().describe("Project ID or URL-encoded path"),
|
|
458
519
|
deployment_id: z.coerce.string().describe("The ID of the deployment"),
|
|
459
520
|
});
|
|
521
|
+
export const CreateDeploymentSchema = z.object({
|
|
522
|
+
project_id: z.coerce.string(), environment: z.string(), sha: z.string(), ref: z.string(),
|
|
523
|
+
tag: z.boolean(), status: z.enum(["running", "success", "failed", "canceled"]),
|
|
524
|
+
});
|
|
525
|
+
export const UpdateDeploymentSchema = GetDeploymentSchema.extend({
|
|
526
|
+
status: z.enum(["running", "success", "failed", "canceled"]),
|
|
527
|
+
});
|
|
528
|
+
export const DeploymentApprovalSchema = GetDeploymentSchema.extend({
|
|
529
|
+
status: z.enum(["approved", "rejected"]),
|
|
530
|
+
comment: z.string().optional(),
|
|
531
|
+
represented_as: z.string().optional(),
|
|
532
|
+
});
|
|
533
|
+
export const ListDeploymentMergeRequestsSchema = GetDeploymentSchema.merge(PaginationOptionsSchema);
|
|
460
534
|
// Environment related schemas
|
|
461
535
|
const GitLabEnvironmentLastDeploymentSchema = z.object({
|
|
462
536
|
id: z.coerce.string().optional(),
|
|
@@ -496,6 +570,31 @@ export const GetEnvironmentSchema = z.object({
|
|
|
496
570
|
project_id: z.coerce.string().describe("Project ID or URL-encoded path"),
|
|
497
571
|
environment_id: z.coerce.string().describe("The ID of the environment"),
|
|
498
572
|
});
|
|
573
|
+
export const UpdateEnvironmentSchema = GetEnvironmentSchema.extend({
|
|
574
|
+
external_url: z.string().url().nullable().optional(),
|
|
575
|
+
tier: z.enum(["production", "staging", "testing", "development", "other"]).optional(),
|
|
576
|
+
auto_stop_setting: z.enum(["always", "with_action"]).optional(),
|
|
577
|
+
});
|
|
578
|
+
export const StopEnvironmentSchema = GetEnvironmentSchema.extend({ force: coerceBooleanString.optional() });
|
|
579
|
+
export const StopStaleEnvironmentsSchema = z.object({ project_id: z.coerce.string(), before: z.string() });
|
|
580
|
+
export const DeleteReviewAppEnvironmentsSchema = z.object({
|
|
581
|
+
project_id: z.coerce.string(), before: z.string().optional(), limit: z.coerce.number().optional(),
|
|
582
|
+
dry_run: coerceBooleanString
|
|
583
|
+
.optional()
|
|
584
|
+
.describe("Preview the cleanup when true (default); set to false to schedule deletion one week later"),
|
|
585
|
+
});
|
|
586
|
+
export const PipelineTriggerIdSchema = z.object({ project_id: z.coerce.string(), trigger_id: z.coerce.string() });
|
|
587
|
+
export const ListPipelineTriggersSchema = z.object({ project_id: z.coerce.string() });
|
|
588
|
+
export const CreatePipelineTriggerSchema = z.object({ project_id: z.coerce.string(), description: z.string() });
|
|
589
|
+
export const UpdatePipelineTriggerSchema = PipelineTriggerIdSchema.extend({ description: z.string() });
|
|
590
|
+
export const TriggerPipelineSchema = z.object({
|
|
591
|
+
project_id: z.coerce.string(), token: z.string(), ref: z.string(),
|
|
592
|
+
variables: z.record(z.string()).optional(),
|
|
593
|
+
inputs: z
|
|
594
|
+
.record(z.unknown())
|
|
595
|
+
.optional()
|
|
596
|
+
.describe("Structured pipeline inputs; supported from GitLab 17.10 behind a feature flag and generally available from GitLab 18.1. Omit on older GitLab versions."),
|
|
597
|
+
});
|
|
499
598
|
// Schema for creating a new pipeline
|
|
500
599
|
export const CreatePipelineSchema = z.object({
|
|
501
600
|
project_id: z.coerce.string().describe("Project ID or URL-encoded path"),
|
|
@@ -771,15 +870,51 @@ export const PlayPipelineJobSchema = z.object({
|
|
|
771
870
|
}))
|
|
772
871
|
.optional()
|
|
773
872
|
.describe("Custom job variables to use when running the job"),
|
|
873
|
+
job_inputs: z.record(z.unknown()).optional().describe("Typed job input values"),
|
|
774
874
|
});
|
|
775
875
|
// Schema for retrying a job
|
|
776
|
-
export const RetryPipelineJobSchema = PipelineJobControlSchema
|
|
876
|
+
export const RetryPipelineJobSchema = PipelineJobControlSchema.extend({
|
|
877
|
+
job_inputs: z.record(z.unknown()).optional().describe("Typed job input values"),
|
|
878
|
+
});
|
|
777
879
|
// Schema for canceling a job
|
|
778
880
|
export const CancelPipelineJobSchema = z.object({
|
|
779
881
|
project_id: z.coerce.string().describe("Project ID or URL-encoded path"),
|
|
780
882
|
job_id: z.coerce.string().describe("The ID of the job"),
|
|
781
883
|
force: z.coerce.boolean().optional().describe("Force cancellation of the job"),
|
|
782
884
|
});
|
|
885
|
+
export const ErasePipelineJobSchema = PipelineJobControlSchema;
|
|
886
|
+
export const WaitForPipelineSchema = GetPipelineSchema.extend({
|
|
887
|
+
timeout_seconds: z.coerce
|
|
888
|
+
.number()
|
|
889
|
+
.int()
|
|
890
|
+
.min(1)
|
|
891
|
+
.max(600)
|
|
892
|
+
.optional()
|
|
893
|
+
.describe("Maximum seconds to wait for this pipeline to reach a terminal status"),
|
|
894
|
+
poll_interval_seconds: z.coerce
|
|
895
|
+
.number()
|
|
896
|
+
.int()
|
|
897
|
+
.min(1)
|
|
898
|
+
.max(30)
|
|
899
|
+
.optional()
|
|
900
|
+
.describe("Seconds between status polls while waiting for this pipeline"),
|
|
901
|
+
});
|
|
902
|
+
export const WaitForPipelineJobSchema = PipelineJobControlSchema.extend({
|
|
903
|
+
timeout_seconds: z.coerce
|
|
904
|
+
.number()
|
|
905
|
+
.int()
|
|
906
|
+
.min(1)
|
|
907
|
+
.max(600)
|
|
908
|
+
.optional()
|
|
909
|
+
.describe("Maximum seconds to wait for this job to reach a terminal status"),
|
|
910
|
+
poll_interval_seconds: z.coerce
|
|
911
|
+
.number()
|
|
912
|
+
.int()
|
|
913
|
+
.min(1)
|
|
914
|
+
.max(30)
|
|
915
|
+
.optional()
|
|
916
|
+
.describe("Seconds between status polls while waiting for this job"),
|
|
917
|
+
});
|
|
783
918
|
// User schemas
|
|
784
919
|
export const GitLabUserSchema = z.object({
|
|
785
920
|
username: z.string().optional(), // Changed from login to match GitLab API
|
|
@@ -2360,8 +2495,7 @@ export const ListGroupMergeRequestsSchema = ListMergeRequestsSchema.omit({
|
|
|
2360
2495
|
project_id: true,
|
|
2361
2496
|
}).extend({
|
|
2362
2497
|
group_id: z.coerce.string().describe("Group ID or URL-encoded path"),
|
|
2363
|
-
non_archived:
|
|
2364
|
-
.boolean()
|
|
2498
|
+
non_archived: coerceBooleanString
|
|
2365
2499
|
.optional()
|
|
2366
2500
|
.describe("Return merge requests from non-archived projects only. Defaults to true."),
|
|
2367
2501
|
source_project_id: z.coerce
|
|
@@ -62,7 +62,7 @@ async function callTool(toolName, args, env) {
|
|
|
62
62
|
env: {
|
|
63
63
|
...process.env,
|
|
64
64
|
...env,
|
|
65
|
-
GITLAB_READ_ONLY_MODE: "true",
|
|
65
|
+
GITLAB_READ_ONLY_MODE: env.GITLAB_READ_ONLY_MODE ?? "true",
|
|
66
66
|
USE_PIPELINE: "true",
|
|
67
67
|
},
|
|
68
68
|
});
|
|
@@ -238,8 +238,62 @@ describe("deployment and environment tools", () => {
|
|
|
238
238
|
stage: "deploy",
|
|
239
239
|
pipeline: { id: "190349", status: "success", ref: "master", sha: "abc123" },
|
|
240
240
|
},
|
|
241
|
+
pending_approval_count: 1,
|
|
242
|
+
approvals: [
|
|
243
|
+
{
|
|
244
|
+
user: {
|
|
245
|
+
id: "100",
|
|
246
|
+
username: "security-user-1",
|
|
247
|
+
name: "Security User",
|
|
248
|
+
state: "active",
|
|
249
|
+
web_url: "https://gitlab.example.com/security-user-1",
|
|
250
|
+
},
|
|
251
|
+
status: "approved",
|
|
252
|
+
created_at: "2026-02-20T16:33:00.000Z",
|
|
253
|
+
comment: "Looks good to me",
|
|
254
|
+
},
|
|
255
|
+
],
|
|
256
|
+
approval_summary: {
|
|
257
|
+
rules: [
|
|
258
|
+
{
|
|
259
|
+
group_id: "134",
|
|
260
|
+
access_level: null,
|
|
261
|
+
access_level_description: "security-group",
|
|
262
|
+
required_approvals: 2,
|
|
263
|
+
deployment_approvals: [
|
|
264
|
+
{
|
|
265
|
+
user: {
|
|
266
|
+
id: "100",
|
|
267
|
+
username: "security-user-1",
|
|
268
|
+
name: "Security User",
|
|
269
|
+
state: "active",
|
|
270
|
+
web_url: "https://gitlab.example.com/security-user-1",
|
|
271
|
+
},
|
|
272
|
+
status: "approved",
|
|
273
|
+
created_at: "2026-02-20T16:33:00.000Z",
|
|
274
|
+
comment: "Looks good to me",
|
|
275
|
+
},
|
|
276
|
+
],
|
|
277
|
+
},
|
|
278
|
+
],
|
|
279
|
+
},
|
|
241
280
|
});
|
|
242
281
|
});
|
|
282
|
+
mockGitLab.addMockHandler("post", `/projects/${TEST_PROJECT_ID}/deployments`, (_req, res) => {
|
|
283
|
+
res.status(201).json({ id: "created-deployment", status: "created" });
|
|
284
|
+
});
|
|
285
|
+
mockGitLab.addMockHandler("put", `/projects/${TEST_PROJECT_ID}/deployments/${TEST_DEPLOYMENT_ID}`, (_req, res) => {
|
|
286
|
+
res.json({ id: TEST_DEPLOYMENT_ID, status: "success" });
|
|
287
|
+
});
|
|
288
|
+
mockGitLab.addMockHandler("delete", `/projects/${TEST_PROJECT_ID}/deployments/${TEST_DEPLOYMENT_ID}`, (_req, res) => {
|
|
289
|
+
res.status(204).send();
|
|
290
|
+
});
|
|
291
|
+
mockGitLab.addMockHandler("get", `/projects/${TEST_PROJECT_ID}/deployments/${TEST_DEPLOYMENT_ID}/merge_requests`, (_req, res) => {
|
|
292
|
+
res.json([{ iid: TEST_MERGE_REQUEST_IID, title: "Shipped change" }]);
|
|
293
|
+
});
|
|
294
|
+
mockGitLab.addMockHandler("post", `/projects/${TEST_PROJECT_ID}/deployments/${TEST_DEPLOYMENT_ID}/approval`, (_req, res) => {
|
|
295
|
+
res.json({ id: TEST_DEPLOYMENT_ID, status: "approved" });
|
|
296
|
+
});
|
|
243
297
|
mockGitLab.addMockHandler("get", `/projects/${TEST_PROJECT_ID}/environments`, (req, res) => {
|
|
244
298
|
res.json([
|
|
245
299
|
{
|
|
@@ -298,6 +352,35 @@ describe("deployment and environment tools", () => {
|
|
|
298
352
|
assert.strictEqual(result.id, TEST_DEPLOYMENT_ID);
|
|
299
353
|
assert.strictEqual(result.ref, "master");
|
|
300
354
|
assert.strictEqual(result.status, "success");
|
|
355
|
+
assert.strictEqual(result.pending_approval_count, 1);
|
|
356
|
+
assert.strictEqual(result.approvals[0].status, "approved");
|
|
357
|
+
assert.strictEqual(result.approvals[0].user.username, "security-user-1");
|
|
358
|
+
assert.strictEqual(result.approval_summary.rules[0].group_id, "134");
|
|
359
|
+
assert.strictEqual(result.approval_summary.rules[0].deployment_approvals[0].comment, "Looks good to me");
|
|
360
|
+
});
|
|
361
|
+
test("supports deployment lifecycle and approval operations", async () => {
|
|
362
|
+
const env = {
|
|
363
|
+
GITLAB_API_URL: `${mockGitLabUrl}/api/v4`,
|
|
364
|
+
GITLAB_PERSONAL_ACCESS_TOKEN: MOCK_TOKEN,
|
|
365
|
+
GITLAB_READ_ONLY_MODE: "false",
|
|
366
|
+
};
|
|
367
|
+
const created = await callTool("create_deployment", {
|
|
368
|
+
project_id: TEST_PROJECT_ID,
|
|
369
|
+
environment: "stage",
|
|
370
|
+
sha: "abc123",
|
|
371
|
+
ref: "master",
|
|
372
|
+
tag: false,
|
|
373
|
+
status: "running",
|
|
374
|
+
}, env);
|
|
375
|
+
assert.strictEqual(created.id, "created-deployment");
|
|
376
|
+
const updated = await callTool("update_deployment", { project_id: TEST_PROJECT_ID, deployment_id: TEST_DEPLOYMENT_ID, status: "success" }, env);
|
|
377
|
+
assert.strictEqual(updated.status, "success");
|
|
378
|
+
const mergeRequests = await callTool("list_deployment_merge_requests", { project_id: TEST_PROJECT_ID, deployment_id: TEST_DEPLOYMENT_ID }, env);
|
|
379
|
+
assert.strictEqual(mergeRequests[0].iid, TEST_MERGE_REQUEST_IID);
|
|
380
|
+
const approval = await callTool("approve_deployment", { project_id: TEST_PROJECT_ID, deployment_id: TEST_DEPLOYMENT_ID, status: "approved" }, env);
|
|
381
|
+
assert.strictEqual(approval.status, "approved");
|
|
382
|
+
const deleted = await callTool("delete_deployment", { project_id: TEST_PROJECT_ID, deployment_id: TEST_DEPLOYMENT_ID }, env);
|
|
383
|
+
assert.deepStrictEqual(deleted, { success: true });
|
|
301
384
|
});
|
|
302
385
|
test("list_environments returns environment list", async () => {
|
|
303
386
|
const result = await callTool("list_environments", { project_id: TEST_PROJECT_ID }, {
|
|
@@ -67,6 +67,7 @@ const MODIFY_SAMPLE_TOOLS = [
|
|
|
67
67
|
"create_branch",
|
|
68
68
|
"push_files",
|
|
69
69
|
"merge_merge_request",
|
|
70
|
+
"stop_stale_environments",
|
|
70
71
|
];
|
|
71
72
|
const READ_SAMPLE_TOOLS = ["list_issues", "get_project", "list_merge_requests"];
|
|
72
73
|
describe("Permission Mode", { concurrency: 1 }, () => {
|
package/build/tools/registry.js
CHANGED
|
@@ -2,7 +2,7 @@ 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, SSE, STREAMABLE_HTTP, } from "../config.js";
|
|
4
4
|
import { getToolDescription } from "./tool-descriptions.js";
|
|
5
|
-
import { ApproveMergeRequestSchema, BulkPublishDraftNotesSchema, CancelPipelineJobSchema, CancelPipelineSchema, ConvertWorkItemTypeSchema, CreateBranchSchema, CreateDraftNoteSchema, CreateGroupSchema, 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, CreateGroupMilestoneSchema, CreateReleaseEvidenceSchema, CreateReleaseSchema, CreateRepositorySchema, CreateTagSchema, CreateTimelineEventSchema, CreateWebhookSchema, CreateWikiPageSchema, CreateWorkItemNoteSchema, CreateWorkItemEmojiReactionSchema, CreateWorkItemNoteEmojiReactionSchema, ListWorkItemEmojiReactionsSchema, ListWorkItemNoteEmojiReactionsSchema, CreateWorkItemSchema, DeleteBranchSchema, GetProtectedBranchSchema, ListProtectedBranchesSchema, ProtectBranchSchema, UnprotectBranchSchema, UpdateDefaultBranchSchema, DeleteDraftNoteSchema, DeleteGroupMilestoneSchema, DeleteGroupWikiPageSchema, DeleteIssueLinkSchema, DeleteIssueSchema, DeleteIssueEmojiReactionSchema, DeleteIssueNoteEmojiReactionSchema, DeleteLabelSchema, DeleteMergeRequestDiscussionNoteSchema, DeleteMergeRequestNoteSchema, DeleteMergeRequestEmojiReactionSchema, DeleteMergeRequestNoteEmojiReactionSchema, DeleteProjectMilestoneSchema, DeleteReleaseSchema, DeleteTagSchema, DeleteWebhookSchema, DeleteWikiPageSchema, DeleteWorkItemEmojiReactionSchema, DeleteWorkItemNoteEmojiReactionSchema, DownloadAttachmentSchema, DownloadAttachmentRemoteSchema, DownloadJobArtifactsSchema, DownloadJobArtifactsRemoteSchema, DownloadReleaseAssetSchema, EditProjectMilestoneSchema, EditGroupMilestoneSchema, ExecuteGraphQLSchema, ForkRepositorySchema, HealthCheckSchema, GetBranchSchema, GetBranchDiffsSchema, GetCommitDiffSchema, GetCommitSchema, GetFileBlameSchema, GetDeploymentSchema, GetDraftNoteSchema, GetEnvironmentSchema, GetFileContentsSchema, GetGroupWikiPageSchema, GetIssueLinkSchema, GetIssueSchema, GetJobArtifactFileSchema, GetLabelSchema, GetMergeRequestApprovalStateSchema, GetMergeRequestConflictsSchema, GetMergeRequestDiffsSchema, GetMergeRequestFileDiffSchema, GetMergeRequestNoteSchema, GetMergeRequestNotesSchema, GetMergeRequestSchema, GetMergeRequestVersionSchema, GetMilestoneBurndownEventsSchema, GetMilestoneIssuesSchema, GetMilestoneMergeRequestsSchema, GetGroupMilestoneSchema, GetGroupMilestoneIssuesSchema, GetGroupMilestoneMergeRequestsSchema, GetGroupMilestoneBurndownEventsSchema, GetNamespaceSchema, GetPipelineJobOutputSchema, PipelineJobControlSchema, GetPipelineSchema, GetProjectEventsSchema, GetProjectMilestoneSchema, GetProjectSchema, GetReleaseSchema, GetRepositoryTreeSchema, GetTagSchema, GetTagSignatureSchema, GetTimelineEventsSchema, GetUsersSchema, GetUserSchema, WhoAmISchema, GetWebhookEventSchema, GetWikiPageSchema, GetWorkItemSchema, ListBranchesSchema, ListCommitsSchema, ListCommitStatusesSchema, ListCustomFieldDefinitionsSchema, ListDeploymentsSchema, ListDraftNotesSchema, ListEnvironmentsSchema, ListEventsSchema, ListGroupIterationsSchema, ListGroupMilestonesSchema, ListGroupProjectsSchema, ListGroupWikiPagesSchema, ListIssueDiscussionsSchema, ListIssueLinksSchema, ListIssuesSchema, ListJobArtifactsSchema, ListLabelsSchema, ListMergeRequestChangedFilesSchema, ListMergeRequestDiffsSchema, ListMergeRequestDiscussionsSchema, ListMergeRequestPipelinesSchema, ListMergeRequestVersionsSchema, ListMergeRequestsSchema, ListGroupMergeRequestsSchema, ListNamespacesSchema, ListPipelineJobsSchema, ListPipelineTriggerJobsSchema, ValidateCiLintSchema, ValidateProjectCiLintSchema, ListCiCatalogResourcesSchema, GetCiCatalogResourceSchema, ListPipelinesSchema, ListPipelineSchedulesSchema, GetPipelineScheduleSchema, ListPipelineSchedulePipelinesSchema, CreatePipelineScheduleSchema, UpdatePipelineScheduleSchema, DeletePipelineScheduleSchema, PlayPipelineScheduleSchema, TakeOwnershipPipelineScheduleSchema, GetPipelineScheduleVariableSchema, CreatePipelineScheduleVariableSchema, UpdatePipelineScheduleVariableSchema, DeletePipelineScheduleVariableSchema, ListGroupMembersSchema, ListProjectMembersSchema, ListProjectMilestonesSchema, ListProjectsSchema, ListReleasesSchema, ListTagsSchema, ListWebhookEventsSchema, ListWebhooksSchema, ListWikiPagesSchema, ListWorkItemNotesSchema, ListWorkItemStatusesSchema, ListWorkItemsSchema, MarkdownUploadSchema, MarkdownUploadRemoteSchema, MergeMergeRequestSchema, MoveWorkItemSchema, MyIssuesSchema, PlayPipelineJobSchema, PromoteProjectMilestoneSchema, PublishDraftNoteSchema, PushFilesSchema, ResolveMergeRequestThreadSchema, RetryPipelineJobSchema, RetryPipelineSchema, SearchCodeSchema, SearchGroupCodeSchema, SearchProjectCodeSchema, SearchRepositoriesSchema, UnapproveMergeRequestSchema, UpdateDraftNoteSchema, UpdateGroupWikiPageSchema, UpdateIssueNoteSchema, UpdateIssueSchema, UpdateIssueDescriptionPatchSchema, UpdateLabelSchema, UpdateProjectSchema, UpdateMergeRequestDiscussionNoteSchema, UpdateMergeRequestNoteSchema, UpdateMergeRequestSchema, UpdateReleaseSchema, UpdateWebhookSchema, UpdateWikiPageSchema, UpdateWorkItemSchema, VerifyNamespaceSchema, ListProjectVariablesSchema, GetProjectVariableSchema, CreateProjectVariableSchema, UpdateProjectVariableSchema, DeleteProjectVariableSchema, ListGroupVariablesSchema, GetGroupVariableSchema, CreateGroupVariableSchema, UpdateGroupVariableSchema, DeleteGroupVariableSchema, GetDependencyProxySettingsSchema, UpdateDependencyProxySettingsSchema, ListDependencyProxyBlobsSchema, PurgeDependencyProxyCacheSchema, ListProjectVulnerabilitiesSchema, GetVulnerabilitySchema, DismissVulnerabilitySchema, ConfirmVulnerabilitySchema, } from "../schemas.js";
|
|
5
|
+
import { ApproveMergeRequestSchema, BulkPublishDraftNotesSchema, CancelPipelineJobSchema, ErasePipelineJobSchema, CancelPipelineSchema, ConvertWorkItemTypeSchema, CreateBranchSchema, CreateDraftNoteSchema, CreateGroupSchema, 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, CreateGroupMilestoneSchema, CreateReleaseEvidenceSchema, CreateReleaseSchema, CreateRepositorySchema, CreateTagSchema, CreateTimelineEventSchema, CreateWebhookSchema, CreateWikiPageSchema, CreateWorkItemNoteSchema, CreateWorkItemEmojiReactionSchema, CreateWorkItemNoteEmojiReactionSchema, ListWorkItemEmojiReactionsSchema, ListWorkItemNoteEmojiReactionsSchema, CreateWorkItemSchema, DeleteBranchSchema, GetProtectedBranchSchema, ListProtectedBranchesSchema, ProtectBranchSchema, UnprotectBranchSchema, UpdateDefaultBranchSchema, DeleteDraftNoteSchema, DeleteGroupMilestoneSchema, DeleteGroupWikiPageSchema, DeleteIssueLinkSchema, DeleteIssueSchema, DeleteIssueEmojiReactionSchema, DeleteIssueNoteEmojiReactionSchema, DeleteLabelSchema, DeleteMergeRequestDiscussionNoteSchema, DeleteMergeRequestNoteSchema, DeleteMergeRequestEmojiReactionSchema, DeleteMergeRequestNoteEmojiReactionSchema, DeleteProjectMilestoneSchema, DeleteReleaseSchema, DeleteTagSchema, DeleteWebhookSchema, DeleteWikiPageSchema, DeleteWorkItemEmojiReactionSchema, DeleteWorkItemNoteEmojiReactionSchema, DownloadAttachmentSchema, DownloadAttachmentRemoteSchema, DownloadJobArtifactsSchema, DownloadJobArtifactsRemoteSchema, DownloadReleaseAssetSchema, EditProjectMilestoneSchema, EditGroupMilestoneSchema, ExecuteGraphQLSchema, ForkRepositorySchema, HealthCheckSchema, GetBranchSchema, GetBranchDiffsSchema, GetCommitDiffSchema, GetCommitSchema, GetFileBlameSchema, GetDeploymentSchema, CreateDeploymentSchema, UpdateDeploymentSchema, DeploymentApprovalSchema, ListDeploymentMergeRequestsSchema, GetDraftNoteSchema, GetEnvironmentSchema, UpdateEnvironmentSchema, StopEnvironmentSchema, StopStaleEnvironmentsSchema, DeleteReviewAppEnvironmentsSchema, PipelineTriggerIdSchema, ListPipelineTriggersSchema, CreatePipelineTriggerSchema, UpdatePipelineTriggerSchema, TriggerPipelineSchema, GetFileContentsSchema, GetGroupWikiPageSchema, GetIssueLinkSchema, GetIssueSchema, GetJobArtifactFileSchema, GetLabelSchema, GetMergeRequestApprovalStateSchema, GetMergeRequestConflictsSchema, GetMergeRequestDiffsSchema, GetMergeRequestFileDiffSchema, GetMergeRequestNoteSchema, GetMergeRequestNotesSchema, GetMergeRequestSchema, GetMergeRequestVersionSchema, GetMilestoneBurndownEventsSchema, GetMilestoneIssuesSchema, GetMilestoneMergeRequestsSchema, GetGroupMilestoneSchema, GetGroupMilestoneIssuesSchema, GetGroupMilestoneMergeRequestsSchema, GetGroupMilestoneBurndownEventsSchema, GetNamespaceSchema, GetPipelineJobOutputSchema, PipelineJobControlSchema, GetPipelineSchema, GetPipelineVariablesSchema, UpdatePipelineMetadataSchema, DeletePipelineSchema, PipelineReportSchema, WaitForPipelineSchema, WaitForPipelineJobSchema, PlayPipelineJobsSchema, GetProjectEventsSchema, GetProjectMilestoneSchema, GetProjectSchema, GetReleaseSchema, GetRepositoryTreeSchema, GetTagSchema, GetTagSignatureSchema, GetTimelineEventsSchema, GetUsersSchema, GetUserSchema, WhoAmISchema, GetWebhookEventSchema, GetWikiPageSchema, GetWorkItemSchema, ListBranchesSchema, ListCommitsSchema, ListCommitStatusesSchema, ListCustomFieldDefinitionsSchema, ListDeploymentsSchema, ListDraftNotesSchema, ListEnvironmentsSchema, ListEventsSchema, ListGroupIterationsSchema, ListGroupMilestonesSchema, ListGroupProjectsSchema, ListGroupWikiPagesSchema, ListIssueDiscussionsSchema, ListIssueLinksSchema, ListIssuesSchema, ListJobArtifactsSchema, ListLabelsSchema, ListMergeRequestChangedFilesSchema, ListMergeRequestDiffsSchema, ListMergeRequestDiscussionsSchema, ListMergeRequestPipelinesSchema, ListMergeRequestVersionsSchema, ListMergeRequestsSchema, ListGroupMergeRequestsSchema, ListNamespacesSchema, ListPipelineJobsSchema, ListPipelineTriggerJobsSchema, ValidateCiLintSchema, ValidateProjectCiLintSchema, ListCiCatalogResourcesSchema, GetCiCatalogResourceSchema, ListPipelinesSchema, ListPipelineSchedulesSchema, GetPipelineScheduleSchema, ListPipelineSchedulePipelinesSchema, CreatePipelineScheduleSchema, UpdatePipelineScheduleSchema, DeletePipelineScheduleSchema, PlayPipelineScheduleSchema, TakeOwnershipPipelineScheduleSchema, GetPipelineScheduleVariableSchema, CreatePipelineScheduleVariableSchema, UpdatePipelineScheduleVariableSchema, DeletePipelineScheduleVariableSchema, ListGroupMembersSchema, ListProjectMembersSchema, ListProjectMilestonesSchema, ListProjectsSchema, ListReleasesSchema, ListTagsSchema, ListWebhookEventsSchema, ListWebhooksSchema, ListWikiPagesSchema, ListWorkItemNotesSchema, ListWorkItemStatusesSchema, ListWorkItemsSchema, MarkdownUploadSchema, MarkdownUploadRemoteSchema, MergeMergeRequestSchema, MoveWorkItemSchema, MyIssuesSchema, PlayPipelineJobSchema, PromoteProjectMilestoneSchema, PublishDraftNoteSchema, PushFilesSchema, ResolveMergeRequestThreadSchema, RetryPipelineJobSchema, RetryPipelineSchema, SearchCodeSchema, SearchGroupCodeSchema, SearchProjectCodeSchema, SearchRepositoriesSchema, UnapproveMergeRequestSchema, UpdateDraftNoteSchema, UpdateGroupWikiPageSchema, UpdateIssueNoteSchema, UpdateIssueSchema, UpdateIssueDescriptionPatchSchema, UpdateLabelSchema, UpdateProjectSchema, UpdateMergeRequestDiscussionNoteSchema, UpdateMergeRequestNoteSchema, UpdateMergeRequestSchema, UpdateReleaseSchema, UpdateWebhookSchema, UpdateWikiPageSchema, UpdateWorkItemSchema, VerifyNamespaceSchema, ListProjectVariablesSchema, GetProjectVariableSchema, CreateProjectVariableSchema, UpdateProjectVariableSchema, DeleteProjectVariableSchema, ListGroupVariablesSchema, GetGroupVariableSchema, CreateGroupVariableSchema, UpdateGroupVariableSchema, DeleteGroupVariableSchema, GetDependencyProxySettingsSchema, UpdateDependencyProxySettingsSchema, ListDependencyProxyBlobsSchema, PurgeDependencyProxyCacheSchema, ListProjectVulnerabilitiesSchema, GetVulnerabilitySchema, DismissVulnerabilitySchema, ConfirmVulnerabilitySchema, } from "../schemas.js";
|
|
6
6
|
const IS_REMOTE = SSE || STREAMABLE_HTTP;
|
|
7
7
|
// Define all available tools
|
|
8
8
|
export const allTools = [
|
|
@@ -550,6 +550,15 @@ export const allTools = [
|
|
|
550
550
|
description: "Get details of a specific pipeline",
|
|
551
551
|
inputSchema: toJSONSchema(GetPipelineSchema),
|
|
552
552
|
},
|
|
553
|
+
{
|
|
554
|
+
name: "get_pipeline_variables",
|
|
555
|
+
description: "Get variables configured for a pipeline",
|
|
556
|
+
inputSchema: toJSONSchema(GetPipelineVariablesSchema),
|
|
557
|
+
},
|
|
558
|
+
{ name: "get_pipeline_test_report", description: "Get pipeline test report", inputSchema: toJSONSchema(PipelineReportSchema) },
|
|
559
|
+
{ name: "get_pipeline_test_report_summary", description: "Get pipeline test report summary", inputSchema: toJSONSchema(PipelineReportSchema) },
|
|
560
|
+
{ name: "delete_pipeline", description: "Delete a pipeline. Requires the project Owner role, cannot be undone, and does not automatically delete child pipelines.", inputSchema: toJSONSchema(DeletePipelineSchema) },
|
|
561
|
+
{ name: "update_pipeline_metadata", description: "Update pipeline metadata", inputSchema: toJSONSchema(UpdatePipelineMetadataSchema) },
|
|
553
562
|
{
|
|
554
563
|
name: "list_deployments",
|
|
555
564
|
description: "List deployments with filtering options",
|
|
@@ -557,9 +566,14 @@ export const allTools = [
|
|
|
557
566
|
},
|
|
558
567
|
{
|
|
559
568
|
name: "get_deployment",
|
|
560
|
-
description: "Get details
|
|
569
|
+
description: "Get deployment details, including approval_summary, approvals, and pending_approval_count when GitLab provides them",
|
|
561
570
|
inputSchema: toJSONSchema(GetDeploymentSchema),
|
|
562
571
|
},
|
|
572
|
+
{ name: "create_deployment", description: "Create a deployment", inputSchema: toJSONSchema(CreateDeploymentSchema) },
|
|
573
|
+
{ name: "update_deployment", description: "Update a deployment status", inputSchema: toJSONSchema(UpdateDeploymentSchema) },
|
|
574
|
+
{ name: "delete_deployment", description: "Delete a deployment", inputSchema: toJSONSchema(GetDeploymentSchema) },
|
|
575
|
+
{ name: "list_deployment_merge_requests", description: "List merge requests shipped with a deployment", inputSchema: toJSONSchema(ListDeploymentMergeRequestsSchema) },
|
|
576
|
+
{ name: "approve_deployment", description: "Approve or reject a protected-environment deployment", inputSchema: toJSONSchema(DeploymentApprovalSchema) },
|
|
563
577
|
{
|
|
564
578
|
name: "list_environments",
|
|
565
579
|
description: "List environments in a project",
|
|
@@ -570,6 +584,17 @@ export const allTools = [
|
|
|
570
584
|
description: "Get details of a specific environment",
|
|
571
585
|
inputSchema: toJSONSchema(GetEnvironmentSchema),
|
|
572
586
|
},
|
|
587
|
+
{ name: "update_environment", description: "Update an environment", inputSchema: toJSONSchema(UpdateEnvironmentSchema) },
|
|
588
|
+
{ name: "delete_environment", description: "Delete a stopped environment", inputSchema: toJSONSchema(GetEnvironmentSchema) },
|
|
589
|
+
{ name: "stop_environment", description: "Stop an environment", inputSchema: toJSONSchema(StopEnvironmentSchema) },
|
|
590
|
+
{ name: "stop_stale_environments", description: "Stop eligible stale environments; protected environments are excluded and environments are stopped, not deleted", inputSchema: toJSONSchema(StopStaleEnvironmentsSchema) },
|
|
591
|
+
{ name: "delete_review_app_environments", description: "Schedule deletion of stopped review-app environments one week later; dry_run defaults to true and actual scheduling requires dry_run=false", inputSchema: toJSONSchema(DeleteReviewAppEnvironmentsSchema) },
|
|
592
|
+
{ name: "list_pipeline_triggers", description: "List project pipeline trigger tokens", inputSchema: toJSONSchema(ListPipelineTriggersSchema) },
|
|
593
|
+
{ name: "get_pipeline_trigger", description: "Get a project pipeline trigger", inputSchema: toJSONSchema(PipelineTriggerIdSchema) },
|
|
594
|
+
{ name: "create_pipeline_trigger", description: "Create a project pipeline trigger", inputSchema: toJSONSchema(CreatePipelineTriggerSchema) },
|
|
595
|
+
{ name: "update_pipeline_trigger", description: "Update a project pipeline trigger", inputSchema: toJSONSchema(UpdatePipelineTriggerSchema) },
|
|
596
|
+
{ name: "delete_pipeline_trigger", description: "Delete a project pipeline trigger", inputSchema: toJSONSchema(PipelineTriggerIdSchema) },
|
|
597
|
+
{ name: "trigger_pipeline", description: "Trigger a pipeline with a pipeline trigger token", inputSchema: toJSONSchema(TriggerPipelineSchema) },
|
|
573
598
|
{
|
|
574
599
|
name: "list_pipeline_jobs",
|
|
575
600
|
description: "List all jobs in a specific pipeline",
|
|
@@ -690,6 +715,11 @@ export const allTools = [
|
|
|
690
715
|
description: "Run a manual pipeline job",
|
|
691
716
|
inputSchema: toJSONSchema(PlayPipelineJobSchema),
|
|
692
717
|
},
|
|
718
|
+
{
|
|
719
|
+
name: "play_pipeline_jobs",
|
|
720
|
+
description: "Play multiple manual pipeline jobs sequentially",
|
|
721
|
+
inputSchema: toJSONSchema(PlayPipelineJobsSchema),
|
|
722
|
+
},
|
|
693
723
|
{
|
|
694
724
|
name: "retry_pipeline_job",
|
|
695
725
|
description: "Retry a failed or canceled pipeline job",
|
|
@@ -700,6 +730,9 @@ export const allTools = [
|
|
|
700
730
|
description: "Cancel a running pipeline job",
|
|
701
731
|
inputSchema: toJSONSchema(CancelPipelineJobSchema),
|
|
702
732
|
},
|
|
733
|
+
{ name: "erase_pipeline_job", description: "Erase a pipeline job log and artifacts", inputSchema: toJSONSchema(ErasePipelineJobSchema) },
|
|
734
|
+
{ name: "wait_for_pipeline", description: "Wait for a pipeline to reach a terminal status", inputSchema: toJSONSchema(WaitForPipelineSchema) },
|
|
735
|
+
{ name: "wait_for_job", description: "Wait for a job to reach a terminal status", inputSchema: toJSONSchema(WaitForPipelineJobSchema) },
|
|
703
736
|
{
|
|
704
737
|
name: "list_job_artifacts",
|
|
705
738
|
description: "List artifact files in a job's archive",
|
|
@@ -1250,6 +1283,9 @@ export const readOnlyTools = new Set([
|
|
|
1250
1283
|
"list_project_members",
|
|
1251
1284
|
"list_group_members",
|
|
1252
1285
|
"get_pipeline",
|
|
1286
|
+
"get_pipeline_variables",
|
|
1287
|
+
"get_pipeline_test_report",
|
|
1288
|
+
"get_pipeline_test_report_summary",
|
|
1253
1289
|
"list_pipelines",
|
|
1254
1290
|
"list_pipeline_schedules",
|
|
1255
1291
|
"get_pipeline_schedule",
|
|
@@ -1257,12 +1293,17 @@ export const readOnlyTools = new Set([
|
|
|
1257
1293
|
"get_pipeline_schedule_variable",
|
|
1258
1294
|
"list_deployments",
|
|
1259
1295
|
"get_deployment",
|
|
1296
|
+
"list_deployment_merge_requests",
|
|
1260
1297
|
"list_environments",
|
|
1261
1298
|
"get_environment",
|
|
1299
|
+
"list_pipeline_triggers",
|
|
1300
|
+
"get_pipeline_trigger",
|
|
1262
1301
|
"list_pipeline_jobs",
|
|
1263
1302
|
"list_pipeline_trigger_jobs",
|
|
1264
1303
|
"get_pipeline_job",
|
|
1265
1304
|
"get_pipeline_job_output",
|
|
1305
|
+
"wait_for_pipeline",
|
|
1306
|
+
"wait_for_job",
|
|
1266
1307
|
"validate_ci_lint",
|
|
1267
1308
|
"validate_project_ci_lint",
|
|
1268
1309
|
"list_ci_catalog_resources",
|
|
@@ -1335,6 +1376,13 @@ export const readOnlyTools = new Set([
|
|
|
1335
1376
|
]);
|
|
1336
1377
|
// Define which tools are destructive (data loss potential)
|
|
1337
1378
|
export const destructiveTools = new Set([
|
|
1379
|
+
"delete_pipeline",
|
|
1380
|
+
"erase_pipeline_job",
|
|
1381
|
+
"delete_deployment",
|
|
1382
|
+
"approve_deployment",
|
|
1383
|
+
"delete_environment",
|
|
1384
|
+
"delete_review_app_environments",
|
|
1385
|
+
"delete_pipeline_trigger",
|
|
1338
1386
|
"delete_issue",
|
|
1339
1387
|
"delete_issue_link",
|
|
1340
1388
|
"delete_label",
|
|
@@ -1369,6 +1417,12 @@ export const destructiveTools = new Set([
|
|
|
1369
1417
|
// Tools that permanently delete resources — blocked in "modify" permission mode.
|
|
1370
1418
|
// Narrower than destructiveTools: merge/protect/push are modifications, not deletions.
|
|
1371
1419
|
export const deleteTools = new Set([
|
|
1420
|
+
"delete_pipeline",
|
|
1421
|
+
"erase_pipeline_job",
|
|
1422
|
+
"delete_deployment",
|
|
1423
|
+
"delete_environment",
|
|
1424
|
+
"delete_review_app_environments",
|
|
1425
|
+
"delete_pipeline_trigger",
|
|
1372
1426
|
"delete_branch",
|
|
1373
1427
|
"delete_draft_note",
|
|
1374
1428
|
"delete_group_variable",
|
|
@@ -1433,14 +1487,39 @@ export const milestoneToolNames = new Set([
|
|
|
1433
1487
|
export const pipelineToolNames = new Set([
|
|
1434
1488
|
"list_pipelines",
|
|
1435
1489
|
"get_pipeline",
|
|
1490
|
+
"get_pipeline_variables",
|
|
1491
|
+
"get_pipeline_test_report",
|
|
1492
|
+
"get_pipeline_test_report_summary",
|
|
1493
|
+
"delete_pipeline",
|
|
1494
|
+
"update_pipeline_metadata",
|
|
1436
1495
|
"list_deployments",
|
|
1437
1496
|
"get_deployment",
|
|
1497
|
+
"create_deployment",
|
|
1498
|
+
"update_deployment",
|
|
1499
|
+
"delete_deployment",
|
|
1500
|
+
"list_deployment_merge_requests",
|
|
1501
|
+
"approve_deployment",
|
|
1438
1502
|
"list_environments",
|
|
1439
1503
|
"get_environment",
|
|
1504
|
+
"update_environment",
|
|
1505
|
+
"delete_environment",
|
|
1506
|
+
"stop_environment",
|
|
1507
|
+
"stop_stale_environments",
|
|
1508
|
+
"delete_review_app_environments",
|
|
1509
|
+
"list_pipeline_triggers",
|
|
1510
|
+
"get_pipeline_trigger",
|
|
1511
|
+
"create_pipeline_trigger",
|
|
1512
|
+
"update_pipeline_trigger",
|
|
1513
|
+
"delete_pipeline_trigger",
|
|
1514
|
+
"trigger_pipeline",
|
|
1440
1515
|
"list_pipeline_jobs",
|
|
1441
1516
|
"list_pipeline_trigger_jobs",
|
|
1442
1517
|
"get_pipeline_job",
|
|
1443
1518
|
"get_pipeline_job_output",
|
|
1519
|
+
"play_pipeline_jobs",
|
|
1520
|
+
"erase_pipeline_job",
|
|
1521
|
+
"wait_for_pipeline",
|
|
1522
|
+
"wait_for_job",
|
|
1444
1523
|
"validate_ci_lint",
|
|
1445
1524
|
"validate_project_ci_lint",
|
|
1446
1525
|
"create_pipeline",
|
|
@@ -1629,10 +1708,31 @@ export const TOOLSET_DEFINITIONS = [
|
|
|
1629
1708
|
tools: new Set([
|
|
1630
1709
|
"list_pipelines",
|
|
1631
1710
|
"get_pipeline",
|
|
1711
|
+
"get_pipeline_variables",
|
|
1712
|
+
"get_pipeline_test_report",
|
|
1713
|
+
"get_pipeline_test_report_summary",
|
|
1714
|
+
"delete_pipeline",
|
|
1715
|
+
"update_pipeline_metadata",
|
|
1632
1716
|
"list_deployments",
|
|
1633
1717
|
"get_deployment",
|
|
1718
|
+
"create_deployment",
|
|
1719
|
+
"update_deployment",
|
|
1720
|
+
"delete_deployment",
|
|
1721
|
+
"list_deployment_merge_requests",
|
|
1722
|
+
"approve_deployment",
|
|
1634
1723
|
"list_environments",
|
|
1635
1724
|
"get_environment",
|
|
1725
|
+
"update_environment",
|
|
1726
|
+
"delete_environment",
|
|
1727
|
+
"stop_environment",
|
|
1728
|
+
"stop_stale_environments",
|
|
1729
|
+
"delete_review_app_environments",
|
|
1730
|
+
"list_pipeline_triggers",
|
|
1731
|
+
"get_pipeline_trigger",
|
|
1732
|
+
"create_pipeline_trigger",
|
|
1733
|
+
"update_pipeline_trigger",
|
|
1734
|
+
"delete_pipeline_trigger",
|
|
1735
|
+
"trigger_pipeline",
|
|
1636
1736
|
"list_pipeline_jobs",
|
|
1637
1737
|
"list_pipeline_trigger_jobs",
|
|
1638
1738
|
"get_pipeline_job",
|
|
@@ -1653,8 +1753,12 @@ export const TOOLSET_DEFINITIONS = [
|
|
|
1653
1753
|
"update_pipeline_schedule_variable",
|
|
1654
1754
|
"delete_pipeline_schedule_variable",
|
|
1655
1755
|
"play_pipeline_job",
|
|
1756
|
+
"play_pipeline_jobs",
|
|
1656
1757
|
"retry_pipeline_job",
|
|
1657
1758
|
"cancel_pipeline_job",
|
|
1759
|
+
"erase_pipeline_job",
|
|
1760
|
+
"wait_for_pipeline",
|
|
1761
|
+
"wait_for_job",
|
|
1658
1762
|
"list_job_artifacts",
|
|
1659
1763
|
"download_job_artifacts",
|
|
1660
1764
|
"get_job_artifact_file",
|
|
@@ -46,6 +46,8 @@ const TOOL_GUIDANCE = {
|
|
|
46
46
|
create_pipeline_schedule_variable: "Use this to attach a new variable to a pipeline schedule so its scheduled pipelines receive it; use `update_pipeline_schedule_variable` when the key already exists and `create_project_variable` for a project-wide variable. `variable_type` defaults to `env_var` and `key` is limited to 255 characters matching /[a-zA-Z0-9_]+/. It creates remote CI configuration, requires the Developer, Maintainer, or Owner role and ownership of the schedule, and returns the new variable or a validation, duplicate-key, or permission error.",
|
|
47
47
|
update_pipeline_schedule_variable: "Use this to change the value or type of an existing pipeline schedule variable; use `create_pipeline_schedule_variable` when the key does not exist yet. It changes remote CI configuration that scheduled pipelines consume, requires the Developer, Maintainer, or Owner role and ownership of the schedule, and returns the updated variable or a missing-key, validation, or permission error.",
|
|
48
48
|
delete_pipeline_schedule_variable: "Use this only after confirming the key with `get_pipeline_schedule` or `get_pipeline_schedule_variable`; use `update_pipeline_schedule_variable` to change a value without removing it. The operation permanently removes the variable from the schedule so later scheduled pipelines no longer receive it, requires the Developer, Maintainer, or Owner role and ownership of the schedule, and returns a confirmation or a missing-key or permission error.",
|
|
49
|
+
stop_stale_environments: "Use this to stop eligible stale environments in a project. GitLab excludes protected environments, and this operation stops environments without deleting them. It requires the necessary project permission and returns the result or a validation, permission, or rate-limit error.",
|
|
50
|
+
delete_review_app_environments: "Use this to clean up stopped review-app environments after verifying the scope. GitLab schedules deletion one week later rather than deleting environments immediately; `dry_run` defaults to `true`, so actual scheduling requires `dry_run: false`. It requires the necessary project permission and returns the cleanup result or a validation, permission, or rate-limit error.",
|
|
49
51
|
};
|
|
50
52
|
const PARAMETER_GUIDANCE = "When `project_id` or `group_id` is accepted, provide the numeric ID or complete URL-encoded path described by the schema; use required identifiers and pagination fields exactly as documented.";
|
|
51
53
|
function ensureSentence(text) {
|
|
@@ -3,16 +3,23 @@
|
|
|
3
3
|
* MCP tool results become part of the AI conversation context, so these must
|
|
4
4
|
* never be forwarded to the model.
|
|
5
5
|
*/
|
|
6
|
-
const SENSITIVE_GITLAB_FIELDS = ["runners_token", "import_url"];
|
|
6
|
+
const SENSITIVE_GITLAB_FIELDS = ["runners_token", "import_url", "token"];
|
|
7
7
|
/**
|
|
8
8
|
* Strip known sensitive fields from a GitLab API response object before it is
|
|
9
9
|
* returned as an MCP tool result. Mutates and returns the same object.
|
|
10
|
+
* Recurses into arrays (e.g. list responses) since those hold one object per item.
|
|
10
11
|
*
|
|
11
|
-
* Used for raw passthrough responses (get_project / update_project
|
|
12
|
-
* go through a Zod schema, since Zod
|
|
12
|
+
* Used for raw passthrough responses (get_project / update_project,
|
|
13
|
+
* list/get_pipeline_trigger) that do not go through a Zod schema, since Zod
|
|
14
|
+
* would otherwise strip unknown keys for us. Do NOT apply to
|
|
15
|
+
* create_pipeline_trigger: its response carries the newly issued token once.
|
|
13
16
|
*/
|
|
14
17
|
export function redactSensitiveGitLabFields(data) {
|
|
15
|
-
if (data
|
|
18
|
+
if (Array.isArray(data)) {
|
|
19
|
+
for (const item of data)
|
|
20
|
+
redactSensitiveGitLabFields(item);
|
|
21
|
+
}
|
|
22
|
+
else if (data && typeof data === "object") {
|
|
16
23
|
for (const key of SENSITIVE_GITLAB_FIELDS) {
|
|
17
24
|
delete data[key];
|
|
18
25
|
}
|
package/package.json
CHANGED