@zereight/mcp-gitlab 2.3.0 → 2.3.2
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 +7 -1
- package/README.md +7 -1
- package/README.pt-BR.md +7 -1
- package/README.zh-CN.md +7 -1
- package/build/index.js +21 -5
- package/build/schemas.js +99 -146
- package/build/tools/tool-descriptions.js +1 -1
- package/build/utils/schema.js +7 -0
- package/package.json +2 -1
package/README.ko.md
CHANGED
|
@@ -138,7 +138,13 @@ command = lib.getExe inputs.gitlab-mcp.packages.${system}.default;
|
|
|
138
138
|
|
|
139
139
|
예시는 기존 `mcp-gitlab`보다 충돌 가능성이 낮은 `zereight-mcp-gitlab` 별칭을 사용합니다. MCP 클라이언트가 찾지 못하면 `which zereight-mcp-gitlab`의 절대 경로를 사용하세요.
|
|
140
140
|
|
|
141
|
-
전역 설치를 쓰지 않으려면 `npx -y @zereight/mcp-gitlab@2.
|
|
141
|
+
전역 설치를 쓰지 않으려면 `npx -y @zereight/mcp-gitlab@2.3.1`처럼 직전 안정 버전(문서가 권장하는 버전)으로 고정하세요. 항상 최신 버전을 원하면 `npx -y @zereight/mcp-gitlab@latest`를 사용하세요. 새 버전이 나오면 서버가 시작 시 stderr로 알려줍니다(`GITLAB_DISABLE_VERSION_CHECK=true`로 비활성화 가능).
|
|
142
|
+
|
|
143
|
+
#### Claude Desktop 원클릭 설치(MCP Bundle)
|
|
144
|
+
|
|
145
|
+
v2.3.1 이후의 GitHub 릴리스마다 `gitlab-mcp.mcpb` [MCP Bundle](https://github.com/modelcontextprotocol/mcpb)이 첨부됩니다. [최신 번들](https://github.com/zereight/gitlab-mcp/releases/latest/download/gitlab-mcp.mcpb)을 내려받아 Claude Desktop으로 열거나 **Settings → Extensions**에 끌어다 놓으세요. Claude Desktop이 Personal Access Token을 입력받아 민감 정보로 저장하고, `GITLAB_API_URL`, `GITLAB_PERMISSION_MODE`, `GITLAB_TOOLSETS`, `GITLAB_MASKING_ENABLED`를 설정할 수 있게 합니다. Node.js나 npm을 따로 설치할 필요가 없습니다.
|
|
146
|
+
|
|
147
|
+
소스에서 번들을 만들려면 `npm run pack:mcpb`를 실행하세요(`gitlab-mcp.mcpb` 생성).
|
|
142
148
|
|
|
143
149
|
#### CLI 인자 사용하기(환경 변수 문제가 있는 클라이언트용)
|
|
144
150
|
|
package/README.md
CHANGED
|
@@ -143,7 +143,13 @@ The store path is pinned by your lock file; update it with `nix flake update git
|
|
|
143
143
|
|
|
144
144
|
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`.
|
|
145
145
|
|
|
146
|
-
No global install? Pin `npx` to the previous stable release (the version these docs recommend), for example `npx -y @zereight/mcp-gitlab@2.
|
|
146
|
+
No global install? Pin `npx` to the previous stable release (the version these docs recommend), for example `npx -y @zereight/mcp-gitlab@2.3.1`. 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`).
|
|
147
|
+
|
|
148
|
+
#### Claude Desktop one-click install (MCP Bundle)
|
|
149
|
+
|
|
150
|
+
Every GitHub release after v2.3.1 ships a `gitlab-mcp.mcpb` [MCP Bundle](https://github.com/modelcontextprotocol/mcpb). Download the [latest bundle](https://github.com/zereight/gitlab-mcp/releases/latest/download/gitlab-mcp.mcpb) and open it with Claude Desktop (or drag it into **Settings → Extensions**). Claude Desktop asks for your Personal Access Token (stored as a sensitive value) and lets you set `GITLAB_API_URL`, `GITLAB_PERMISSION_MODE`, `GITLAB_TOOLSETS`, and `GITLAB_MASKING_ENABLED`. No separate Node.js or npm install is needed.
|
|
151
|
+
|
|
152
|
+
To build the bundle from source, run `npm run pack:mcpb` (writes `gitlab-mcp.mcpb`).
|
|
147
153
|
|
|
148
154
|
#### Using CLI Arguments (for clients with env var issues)
|
|
149
155
|
|
package/README.pt-BR.md
CHANGED
|
@@ -138,7 +138,13 @@ O caminho no store é fixado pelo seu lock file; atualize-o com `nix flake updat
|
|
|
138
138
|
|
|
139
139
|
Os exemplos usam `zereight-mcp-gitlab`, um alias com menor chance de conflito que o binário legado `mcp-gitlab`. Se o seu cliente MCP não o encontrar, use o caminho absoluto retornado por `which zereight-mcp-gitlab`.
|
|
140
140
|
|
|
141
|
-
Não quer instalar globalmente? Fixe o `npx` na versão estável anterior (a versão recomendada por esta documentação), por exemplo `npx -y @zereight/mcp-gitlab@2.
|
|
141
|
+
Não quer instalar globalmente? Fixe o `npx` na versão estável anterior (a versão recomendada por esta documentação), por exemplo `npx -y @zereight/mcp-gitlab@2.3.1`. Se quiser sempre a versão mais recente, use `npx -y @zereight/mcp-gitlab@latest`. O servidor exibe um aviso no stderr durante a inicialização quando existe uma versão mais nova disponível (desative com `GITLAB_DISABLE_VERSION_CHECK=true`).
|
|
142
|
+
|
|
143
|
+
#### Instalação com um clique no Claude Desktop (MCP Bundle)
|
|
144
|
+
|
|
145
|
+
Cada release no GitHub posterior à v2.3.1 inclui um [MCP Bundle](https://github.com/modelcontextprotocol/mcpb) `gitlab-mcp.mcpb`. Baixe o [bundle mais recente](https://github.com/zereight/gitlab-mcp/releases/latest/download/gitlab-mcp.mcpb) e abra-o com o Claude Desktop (ou arraste-o para **Settings → Extensions**). O Claude Desktop pede seu Personal Access Token (armazenado como valor sensível) e permite definir `GITLAB_API_URL`, `GITLAB_PERMISSION_MODE`, `GITLAB_TOOLSETS` e `GITLAB_MASKING_ENABLED`. Não é preciso instalar Node.js ou npm separadamente.
|
|
146
|
+
|
|
147
|
+
Para gerar o bundle a partir do código-fonte, execute `npm run pack:mcpb` (gera `gitlab-mcp.mcpb`).
|
|
142
148
|
|
|
143
149
|
#### Usando argumentos de CLI (para clientes com problemas com variáveis de ambiente)
|
|
144
150
|
|
package/README.zh-CN.md
CHANGED
|
@@ -138,7 +138,13 @@ command = lib.getExe inputs.gitlab-mcp.packages.${system}.default;
|
|
|
138
138
|
|
|
139
139
|
示例使用 `zereight-mcp-gitlab`,这是比旧的 `mcp-gitlab` 更不容易冲突的别名。如果 MCP 客户端找不到它,请使用 `which zereight-mcp-gitlab` 输出的绝对路径。
|
|
140
140
|
|
|
141
|
-
如果不想全局安装,请将 `npx` 固定到上一个稳定版本(即文档推荐的版本),例如 `npx -y @zereight/mcp-gitlab@2.
|
|
141
|
+
如果不想全局安装,请将 `npx` 固定到上一个稳定版本(即文档推荐的版本),例如 `npx -y @zereight/mcp-gitlab@2.3.1`。如果始终想使用最新版本,请改用 `npx -y @zereight/mcp-gitlab@latest`。有新版本发布时,服务器会在启动时通过 stderr 提示(可用 `GITLAB_DISABLE_VERSION_CHECK=true` 关闭)。
|
|
142
|
+
|
|
143
|
+
#### Claude Desktop 一键安装(MCP Bundle)
|
|
144
|
+
|
|
145
|
+
v2.3.1 之后的每个 GitHub Release 都附带 `gitlab-mcp.mcpb` [MCP Bundle](https://github.com/modelcontextprotocol/mcpb)。下载[最新的 bundle](https://github.com/zereight/gitlab-mcp/releases/latest/download/gitlab-mcp.mcpb),用 Claude Desktop 打开(或拖到 **Settings → Extensions** 中)。Claude Desktop 会要求输入 Personal Access Token(作为敏感值保存),并可设置 `GITLAB_API_URL`、`GITLAB_PERMISSION_MODE`、`GITLAB_TOOLSETS` 和 `GITLAB_MASKING_ENABLED`。无需另外安装 Node.js 或 npm。
|
|
146
|
+
|
|
147
|
+
如需从源码构建 bundle,运行 `npm run pack:mcpb`(生成 `gitlab-mcp.mcpb`)。
|
|
142
148
|
|
|
143
149
|
#### 使用 CLI 参数(适用于环境变量有问题的客户端)
|
|
144
150
|
|
package/build/index.js
CHANGED
|
@@ -109,6 +109,7 @@ import { buildBulkPublishDraftNotesBody, needsGitLab19_2BulkPublish, } from "./u
|
|
|
109
109
|
import { appendFilterParam, appendFilterParams, cleanMutuallyExclusiveIdUsernameOptions, dropBlankArrayEntries, isBlankFilterValue, LIST_MERGE_REQUESTS_ID_USERNAME_PAIRS, sanitizeToolArguments, } from "./utils/tool-args.js";
|
|
110
110
|
import { applyJmespathToToolResult, getJmespathSyntaxError, JMESPATH_TOOL_ARGUMENT, JMESPATH_TOOL_ARGUMENT_DESCRIPTION, omitJmespathArgument, readJmespathExpression, } from "./utils/jmespath-tool-result.js";
|
|
111
111
|
import { parseSearchReplaceBlocks, applySearchReplace, applyUnifiedDiff, } from "./utils/patch-helper.js";
|
|
112
|
+
import { zodSchemaFor } from "./utils/schema.js";
|
|
112
113
|
import { GitLabClientPool } from "./gitlab-client-pool.js";
|
|
113
114
|
import { advertisesReadOnly, allTools, readOnlyTools, destructiveTools, deleteTools, parseEnabledToolsets, parseIndividualTools, buildFeatureFlagOverrides, isToolInEnabledToolset, findSmallestToolsetForTool, isExplicitOnlyToolsetId, isExplicitToolsetOnlyTool, isToolsetFullyActive, listDiscoverableCategories, TOOLSET_DEFINITIONS, DISCOVERABLE_TOOLSET_IDS, } from "./tools/registry.js";
|
|
114
115
|
import { executeGitLabApiRequestAsync, GitLabApiRequestHttpError, GitLabApiRequestInputError, } from "./tools/gitlab-api-request.js";
|
|
@@ -8764,12 +8765,19 @@ async function handleToolCall(params) {
|
|
|
8764
8765
|
}
|
|
8765
8766
|
case "rebase_merge_request": {
|
|
8766
8767
|
const { project_id, merge_request_iid, skip_ci, wait, timeout_seconds, poll_interval_seconds, } = RebaseMergeRequestSchema.parse(params.arguments);
|
|
8767
|
-
const enqueued = await rebaseMergeRequest(project_id, merge_request_iid, skip_ci);
|
|
8768
8768
|
if (!wait) {
|
|
8769
|
+
const enqueued = await rebaseMergeRequest(project_id, merge_request_iid, skip_ci);
|
|
8769
8770
|
return { content: [{ type: "text", text: JSON.stringify(enqueued) }] };
|
|
8770
8771
|
}
|
|
8772
|
+
const { mergeRequest: previous } = await getMergeRequestRebaseStatus(project_id, merge_request_iid);
|
|
8773
|
+
await rebaseMergeRequest(project_id, merge_request_iid, skip_ci);
|
|
8771
8774
|
const { mergeRequest } = await waitForStatus(signal => getMergeRequestRebaseStatus(project_id, merge_request_iid, signal), TERMINAL_REBASE_STATUSES, timeout_seconds, poll_interval_seconds);
|
|
8772
|
-
|
|
8775
|
+
const rebaseResult = {
|
|
8776
|
+
...mergeRequest,
|
|
8777
|
+
previous_sha: previous.sha,
|
|
8778
|
+
head_changed: mergeRequest.sha !== previous.sha,
|
|
8779
|
+
};
|
|
8780
|
+
return { content: [{ type: "text", text: JSON.stringify(rebaseResult) }] };
|
|
8773
8781
|
}
|
|
8774
8782
|
case "get_merge_request_approval_state": {
|
|
8775
8783
|
const args = GetMergeRequestApprovalStateSchema.parse(params.arguments);
|
|
@@ -11328,9 +11336,17 @@ async function handleToolCall(params) {
|
|
|
11328
11336
|
// Sensitive fields are also covered by REDACT_PATHS if arguments are logged elsewhere.
|
|
11329
11337
|
logger.debug({ tool: params.name }, "Tool call failed");
|
|
11330
11338
|
if (error instanceof z.ZodError) {
|
|
11331
|
-
|
|
11332
|
-
.map(e => `${e.path.join(".")}: ${e.message}`)
|
|
11333
|
-
.join("
|
|
11339
|
+
const detail = error.issues
|
|
11340
|
+
.map(e => (e.path.length > 0 ? `${e.path.join(".")}: ${e.message}` : e.message))
|
|
11341
|
+
.join("; ");
|
|
11342
|
+
// Response schemas throw ZodError too. If the arguments pass the tool's own
|
|
11343
|
+
// schema, the failure came from parsing a GitLab response.
|
|
11344
|
+
const argsSchema = zodSchemaFor(allTools.find(tool => tool.name === params.name)?.inputSchema);
|
|
11345
|
+
if (argsSchema?.safeParse(params.arguments).success) {
|
|
11346
|
+
throw new Error(`Unexpected GitLab response for ${params.name}: ${detail}`);
|
|
11347
|
+
}
|
|
11348
|
+
// ToolInputError is returned as an isError tool result, so the model can fix and retry.
|
|
11349
|
+
throw new ToolInputError(`Invalid arguments for ${params.name}: ${detail}`);
|
|
11334
11350
|
}
|
|
11335
11351
|
throw error;
|
|
11336
11352
|
}
|
package/build/schemas.js
CHANGED
|
@@ -15,16 +15,25 @@ const coerceStringArray = z.preprocess(val => {
|
|
|
15
15
|
}
|
|
16
16
|
return val;
|
|
17
17
|
}, z.array(z.string()));
|
|
18
|
-
|
|
18
|
+
// Helper: boolean tool argument that also accepts "true"/"false" and 1/0 (string or number).
|
|
19
|
+
// Use this instead of z.coerce.boolean() for tool inputs: Boolean("false") === true.
|
|
20
|
+
const parseBooleanString = (val) => {
|
|
19
21
|
if (typeof val === "string") {
|
|
20
22
|
const normalized = val.trim().toLowerCase();
|
|
21
|
-
if (normalized === "true")
|
|
23
|
+
if (normalized === "true" || normalized === "1")
|
|
22
24
|
return true;
|
|
23
|
-
if (normalized === "false")
|
|
25
|
+
if (normalized === "false" || normalized === "0")
|
|
24
26
|
return false;
|
|
25
27
|
}
|
|
28
|
+
if (val === 1)
|
|
29
|
+
return true;
|
|
30
|
+
if (val === 0)
|
|
31
|
+
return false;
|
|
26
32
|
return val;
|
|
27
|
-
}
|
|
33
|
+
};
|
|
34
|
+
const coerceBooleanString = z.preprocess(parseBooleanString, z.boolean());
|
|
35
|
+
// Same as coerceBooleanString with a default; the default stays visible in the tool's JSON schema.
|
|
36
|
+
const coerceBooleanStringDefault = (value) => z.preprocess(parseBooleanString, z.boolean().default(value));
|
|
28
37
|
// Base schemas for common types
|
|
29
38
|
export const GitLabAuthorSchema = z.object({
|
|
30
39
|
name: z.string(),
|
|
@@ -234,8 +243,7 @@ export const ListPipelinesSchema = z
|
|
|
234
243
|
.describe("The status of pipelines"),
|
|
235
244
|
ref: z.string().optional().describe("The ref of pipelines"),
|
|
236
245
|
sha: z.string().optional().describe("The SHA of pipelines"),
|
|
237
|
-
yaml_errors:
|
|
238
|
-
.boolean()
|
|
246
|
+
yaml_errors: coerceBooleanString
|
|
239
247
|
.optional()
|
|
240
248
|
.describe("Returns pipelines with invalid configurations"),
|
|
241
249
|
username: z.string().optional().describe("The username of the user who triggered pipelines"),
|
|
@@ -341,7 +349,7 @@ export const ListPipelineJobsSchema = z
|
|
|
341
349
|
.enum(["created", "pending", "running", "failed", "success", "canceled", "skipped", "manual"])
|
|
342
350
|
.optional()
|
|
343
351
|
.describe("The scope of jobs to show"),
|
|
344
|
-
include_retried:
|
|
352
|
+
include_retried: coerceBooleanString.optional().describe("Whether to include retried jobs"),
|
|
345
353
|
})
|
|
346
354
|
.merge(PaginationOptionsSchema);
|
|
347
355
|
// Schema for listing trigger jobs (bridges) in a pipeline
|
|
@@ -382,8 +390,8 @@ export const GitLabCiLintResultSchema = z.object({
|
|
|
382
390
|
export const ValidateCiLintSchema = z.object({
|
|
383
391
|
project_id: z.coerce.string().describe("Project ID or URL-encoded path"),
|
|
384
392
|
content: z.string().describe("GitLab CI/CD YAML content to validate"),
|
|
385
|
-
dry_run:
|
|
386
|
-
include_jobs:
|
|
393
|
+
dry_run: coerceBooleanString.optional().describe("Run pipeline creation simulation"),
|
|
394
|
+
include_jobs: coerceBooleanString.optional().describe("Include jobs in the lint response"),
|
|
387
395
|
ref: z.string().optional().describe("Branch or tag context for dry_run validation"),
|
|
388
396
|
});
|
|
389
397
|
export const ValidateProjectCiLintSchema = z.object({
|
|
@@ -392,9 +400,9 @@ export const ValidateProjectCiLintSchema = z.object({
|
|
|
392
400
|
.string()
|
|
393
401
|
.optional()
|
|
394
402
|
.describe("Commit SHA, branch, or tag to read the existing CI config from"),
|
|
395
|
-
dry_run:
|
|
403
|
+
dry_run: coerceBooleanString.optional().describe("Run pipeline creation simulation"),
|
|
396
404
|
dry_run_ref: z.string().optional().describe("Branch or tag context for dry_run validation"),
|
|
397
|
-
include_jobs:
|
|
405
|
+
include_jobs: coerceBooleanString.optional().describe("Include jobs in the lint response"),
|
|
398
406
|
});
|
|
399
407
|
const CiCatalogResourceSortSchema = z.enum([
|
|
400
408
|
"CREATED_ASC",
|
|
@@ -429,7 +437,7 @@ const GetCiCatalogResourceOptionsSchema = z.object({
|
|
|
429
437
|
version_limit: z.coerce.number().int().min(1).max(20).optional().describe("Number of versions to include (default: 5, max: 20)"),
|
|
430
438
|
component_limit: z.coerce.number().int().min(1).max(50).optional().describe("Number of components per version to include (default: 20, max: 50)"),
|
|
431
439
|
component_name: z.string().optional().describe("Filter returned components by component name"),
|
|
432
|
-
include_readme:
|
|
440
|
+
include_readme: coerceBooleanString.optional().describe("Include version README content"),
|
|
433
441
|
});
|
|
434
442
|
export const GetCiCatalogResourceSchema = z.union([
|
|
435
443
|
GetCiCatalogResourceOptionsSchema.extend({
|
|
@@ -912,7 +920,7 @@ export const RetryPipelineJobSchema = PipelineJobControlSchema.extend({
|
|
|
912
920
|
export const CancelPipelineJobSchema = z.object({
|
|
913
921
|
project_id: z.coerce.string().describe("Project ID or URL-encoded path"),
|
|
914
922
|
job_id: z.coerce.string().describe("The ID of the job"),
|
|
915
|
-
force:
|
|
923
|
+
force: coerceBooleanString.optional().describe("Force cancellation of the job"),
|
|
916
924
|
});
|
|
917
925
|
export const ErasePipelineJobSchema = PipelineJobControlSchema;
|
|
918
926
|
export const WaitForPipelineSchema = GetPipelineSchema.extend({
|
|
@@ -1259,7 +1267,7 @@ export const GetRepositoryTreeSchema = z.object({
|
|
|
1259
1267
|
.string()
|
|
1260
1268
|
.optional()
|
|
1261
1269
|
.describe("The name of a repository branch or tag. Defaults to the default branch."),
|
|
1262
|
-
recursive:
|
|
1270
|
+
recursive: coerceBooleanString.optional().describe("Boolean value to get a recursive tree"),
|
|
1263
1271
|
per_page: z.coerce.number().optional().describe("Number of results to show per page"),
|
|
1264
1272
|
page_token: z
|
|
1265
1273
|
.string()
|
|
@@ -1362,7 +1370,7 @@ export const CreateRepositoryOptionsSchema = z.object({
|
|
|
1362
1370
|
namespace_id: z.preprocess(val => (val === "" ? undefined : val), z.coerce.number().int().min(1).optional()),
|
|
1363
1371
|
description: z.string().optional(),
|
|
1364
1372
|
visibility: z.enum(["private", "internal", "public"]).optional(), // Changed from private to match GitLab API
|
|
1365
|
-
initialize_with_readme:
|
|
1373
|
+
initialize_with_readme: coerceBooleanString.optional(), // Changed from auto_init to match GitLab API
|
|
1366
1374
|
});
|
|
1367
1375
|
export const CreateIssueOptionsSchema = z.object({
|
|
1368
1376
|
title: z.string(),
|
|
@@ -1784,7 +1792,7 @@ export const UpdateMergeRequestDiscussionNoteSchema = ProjectParamsSchema.extend
|
|
|
1784
1792
|
discussion_id: z.coerce.string().describe("The ID of a thread"),
|
|
1785
1793
|
note_id: z.coerce.string().describe("The ID of a thread note"),
|
|
1786
1794
|
body: z.string().optional().describe("The content of the note or reply"),
|
|
1787
|
-
resolved:
|
|
1795
|
+
resolved: coerceBooleanString.optional().describe("Resolve or unresolve the note"),
|
|
1788
1796
|
})
|
|
1789
1797
|
.refine(data => data.body !== undefined || data.resolved !== undefined, {
|
|
1790
1798
|
message: "At least one of 'body' or 'resolved' must be provided",
|
|
@@ -1805,7 +1813,7 @@ export const UpdateIssueNoteSchema = ProjectParamsSchema.extend({
|
|
|
1805
1813
|
discussion_id: z.coerce.string().describe("The ID of a thread"),
|
|
1806
1814
|
note_id: z.coerce.string().describe("The ID of a thread note"),
|
|
1807
1815
|
body: z.string().optional().describe("The content of the note or reply"),
|
|
1808
|
-
resolved:
|
|
1816
|
+
resolved: coerceBooleanString.optional().describe("Resolve or unresolve the note"),
|
|
1809
1817
|
})
|
|
1810
1818
|
.refine(data => data.body !== undefined || data.resolved !== undefined, {
|
|
1811
1819
|
message: "At least one of 'body' or 'resolved' must be provided",
|
|
@@ -1860,7 +1868,7 @@ export const CreateRepositorySchema = z.object({
|
|
|
1860
1868
|
.enum(["private", "internal", "public"])
|
|
1861
1869
|
.optional()
|
|
1862
1870
|
.describe("Repository visibility level"),
|
|
1863
|
-
initialize_with_readme:
|
|
1871
|
+
initialize_with_readme: coerceBooleanString.optional().describe("Initialize with README.md"),
|
|
1864
1872
|
});
|
|
1865
1873
|
export const GetFileContentsSchema = z
|
|
1866
1874
|
.object({
|
|
@@ -2011,18 +2019,15 @@ const MergeRequestOptionsSchema = {
|
|
|
2011
2019
|
.optional()
|
|
2012
2020
|
.describe("The ID of the users to assign as reviewers of the MR"),
|
|
2013
2021
|
labels: coerceStringArray.optional().describe("Labels for the MR"),
|
|
2014
|
-
draft:
|
|
2015
|
-
allow_collaboration:
|
|
2016
|
-
.boolean()
|
|
2022
|
+
draft: coerceBooleanString.optional().describe("Create as draft merge request"),
|
|
2023
|
+
allow_collaboration: coerceBooleanString
|
|
2017
2024
|
.optional()
|
|
2018
2025
|
.describe("Allow commits from upstream members"),
|
|
2019
|
-
remove_source_branch:
|
|
2020
|
-
.boolean()
|
|
2026
|
+
remove_source_branch: coerceBooleanString
|
|
2021
2027
|
.nullable()
|
|
2022
2028
|
.optional()
|
|
2023
2029
|
.describe("Flag indicating if a merge request should remove the source branch when merging."),
|
|
2024
|
-
squash:
|
|
2025
|
-
.boolean()
|
|
2030
|
+
squash: coerceBooleanString
|
|
2026
2031
|
.nullable()
|
|
2027
2032
|
.optional()
|
|
2028
2033
|
.describe("If true, squash all commits into a single commit on merge."),
|
|
@@ -2145,8 +2150,7 @@ export const GitLabBranchSchema = z.object({
|
|
|
2145
2150
|
export const GetBranchDiffsSchema = ProjectParamsSchema.extend({
|
|
2146
2151
|
from: z.string().describe("The base branch or commit SHA to compare from"),
|
|
2147
2152
|
to: z.string().describe("The target branch or commit SHA to compare to"),
|
|
2148
|
-
straight:
|
|
2149
|
-
.boolean()
|
|
2153
|
+
straight: coerceBooleanString
|
|
2150
2154
|
.optional()
|
|
2151
2155
|
.describe("Comparison method: false for '...' (default), true for '--'"),
|
|
2152
2156
|
excluded_file_patterns: z
|
|
@@ -2196,15 +2200,13 @@ export const UpdateMergeRequestSchema = MergeRequestParamsSchema.extend({
|
|
|
2196
2200
|
.enum(["close", "reopen"])
|
|
2197
2201
|
.optional()
|
|
2198
2202
|
.describe("New state (close/reopen) for the MR"),
|
|
2199
|
-
remove_source_branch:
|
|
2200
|
-
.boolean()
|
|
2203
|
+
remove_source_branch: coerceBooleanString
|
|
2201
2204
|
.optional()
|
|
2202
2205
|
.describe("Flag indicating if the source branch should be removed"),
|
|
2203
|
-
squash:
|
|
2204
|
-
.boolean()
|
|
2206
|
+
squash: coerceBooleanString
|
|
2205
2207
|
.optional()
|
|
2206
2208
|
.describe("Squash commits into a single commit when merging"),
|
|
2207
|
-
draft:
|
|
2209
|
+
draft: coerceBooleanString.optional().describe("Work in progress merge request"),
|
|
2208
2210
|
milestone_id: z
|
|
2209
2211
|
.preprocess(val => (val === null ? undefined : val), z.coerce.string().optional())
|
|
2210
2212
|
.describe("Milestone ID to assign. Set to 0 to unassign. Null is treated as omitted."),
|
|
@@ -2215,27 +2217,15 @@ export const MergeMergeRequestSchema = ProjectParamsSchema.extend({
|
|
|
2215
2217
|
.string()
|
|
2216
2218
|
.optional()
|
|
2217
2219
|
.describe("SHA of the source-branch HEAD from get_merge_request (`sha` or `diff_refs.head_sha`). If provided, GitLab merges only when HEAD still matches. GitLab 19.2+ groups may require this (Require a commit SHA on the merge requests API)."),
|
|
2218
|
-
auto_merge:
|
|
2219
|
-
.boolean()
|
|
2220
|
-
.optional()
|
|
2221
|
-
.default(false)
|
|
2220
|
+
auto_merge: coerceBooleanStringDefault(false)
|
|
2222
2221
|
.describe("If true, the merge request merges when the pipeline succeeds."),
|
|
2223
2222
|
merge_commit_message: z.string().optional().describe("Custom merge commit message"),
|
|
2224
|
-
merge_when_pipeline_succeeds:
|
|
2225
|
-
.boolean()
|
|
2226
|
-
.optional()
|
|
2227
|
-
.default(false)
|
|
2223
|
+
merge_when_pipeline_succeeds: coerceBooleanStringDefault(false)
|
|
2228
2224
|
.describe("If true, the merge request merges when the pipeline succeeds. Deprecated in GitLab 17.11. Use `auto_merge` instead."),
|
|
2229
|
-
should_remove_source_branch:
|
|
2230
|
-
.boolean()
|
|
2231
|
-
.optional()
|
|
2232
|
-
.default(false)
|
|
2225
|
+
should_remove_source_branch: coerceBooleanStringDefault(false)
|
|
2233
2226
|
.describe("Remove source branch after merge"),
|
|
2234
2227
|
squash_commit_message: z.string().optional().describe("Custom squash commit message"),
|
|
2235
|
-
squash:
|
|
2236
|
-
.boolean()
|
|
2237
|
-
.optional()
|
|
2238
|
-
.default(false)
|
|
2228
|
+
squash: coerceBooleanStringDefault(false)
|
|
2239
2229
|
.describe("Squash commits into a single commit when merging"),
|
|
2240
2230
|
});
|
|
2241
2231
|
// Merge Request Approval schemas
|
|
@@ -2364,8 +2354,7 @@ export const ListMergeRequestDiffsSchema = MergeRequestParamsSchema.extend({
|
|
|
2364
2354
|
.number()
|
|
2365
2355
|
.optional()
|
|
2366
2356
|
.describe("Number of items per page (max: 100, default: 20)"),
|
|
2367
|
-
unidiff:
|
|
2368
|
-
.boolean()
|
|
2357
|
+
unidiff: coerceBooleanString
|
|
2369
2358
|
.optional()
|
|
2370
2359
|
.describe("Present diffs in the unified diff format. Default is false. Introduced in GitLab 16.5."),
|
|
2371
2360
|
});
|
|
@@ -2380,8 +2369,7 @@ export const GetMergeRequestFileDiffSchema = MergeRequestParamsSchema.extend({
|
|
|
2380
2369
|
.array(z.string())
|
|
2381
2370
|
.describe("List of file paths to retrieve diffs for (e.g. ['src/api/users.ts', 'src/repo/user.go']). " +
|
|
2382
2371
|
"Call list_merge_request_changed_files first to get the full list of changed paths."),
|
|
2383
|
-
unidiff:
|
|
2384
|
-
.boolean()
|
|
2372
|
+
unidiff: coerceBooleanString
|
|
2385
2373
|
.optional()
|
|
2386
2374
|
.describe("Present diff in the unified diff format. Default is false."),
|
|
2387
2375
|
});
|
|
@@ -2391,8 +2379,7 @@ export const ListMergeRequestVersionsSchema = ProjectParamsSchema.extend({
|
|
|
2391
2379
|
});
|
|
2392
2380
|
export const GetMergeRequestVersionSchema = ListMergeRequestVersionsSchema.extend({
|
|
2393
2381
|
version_id: z.coerce.string().describe("The ID of the merge request diff version"),
|
|
2394
|
-
unidiff:
|
|
2395
|
-
.boolean()
|
|
2382
|
+
unidiff: coerceBooleanString
|
|
2396
2383
|
.optional()
|
|
2397
2384
|
.describe("Present diffs in the unified diff format. Default is false. Introduced in GitLab 16.5."),
|
|
2398
2385
|
});
|
|
@@ -2427,7 +2414,7 @@ export const ListIssuesSchema = z
|
|
|
2427
2414
|
.string()
|
|
2428
2415
|
.optional()
|
|
2429
2416
|
.describe("Return issues created by the given username. Mutually exclusive with author_id."),
|
|
2430
|
-
confidential:
|
|
2417
|
+
confidential: coerceBooleanString.optional().describe("Filter confidential or public issues"),
|
|
2431
2418
|
created_after: z.string().optional().describe("Return issues created after the given time"),
|
|
2432
2419
|
created_before: z.string().optional().describe("Return issues created before the given time"),
|
|
2433
2420
|
due_date: z.string().optional().describe("Return issues that have the due date"),
|
|
@@ -2452,8 +2439,7 @@ export const ListIssuesSchema = z
|
|
|
2452
2439
|
.describe("Return issues with a specific state"),
|
|
2453
2440
|
updated_after: z.string().optional().describe("Return issues updated after the given time"),
|
|
2454
2441
|
updated_before: z.string().optional().describe("Return issues updated before the given time"),
|
|
2455
|
-
with_labels_details:
|
|
2456
|
-
.boolean()
|
|
2442
|
+
with_labels_details: coerceBooleanString
|
|
2457
2443
|
.optional()
|
|
2458
2444
|
.describe("Return more details for each label"),
|
|
2459
2445
|
})
|
|
@@ -2546,8 +2532,7 @@ export const ListMergeRequestsSchema = z
|
|
|
2546
2532
|
.enum(["yes", "no"])
|
|
2547
2533
|
.optional()
|
|
2548
2534
|
.describe("Filter merge requests against their wip status"),
|
|
2549
|
-
with_labels_details:
|
|
2550
|
-
.boolean()
|
|
2535
|
+
with_labels_details: coerceBooleanString
|
|
2551
2536
|
.optional()
|
|
2552
2537
|
.describe("Return more details for each label"),
|
|
2553
2538
|
})
|
|
@@ -2578,8 +2563,8 @@ export const UpdateIssueSchema = z.object({
|
|
|
2578
2563
|
.array(z.coerce.number())
|
|
2579
2564
|
.optional()
|
|
2580
2565
|
.describe("Array of user IDs to assign issue to"),
|
|
2581
|
-
confidential:
|
|
2582
|
-
discussion_locked:
|
|
2566
|
+
confidential: coerceBooleanString.optional().describe("Set the issue to be confidential"),
|
|
2567
|
+
discussion_locked: coerceBooleanString.optional().describe("Flag to lock discussions"),
|
|
2583
2568
|
due_date: z.string().optional().describe("Date the issue is due (YYYY-MM-DD)"),
|
|
2584
2569
|
labels: coerceStringArray.optional().describe("Array of label names"),
|
|
2585
2570
|
milestone_id: z.coerce.string().optional().describe("Milestone ID to assign"),
|
|
@@ -2606,16 +2591,13 @@ export const UpdateIssueDescriptionPatchSchema = z.object({
|
|
|
2606
2591
|
.min(1)
|
|
2607
2592
|
.max(50000)
|
|
2608
2593
|
.describe("The patch content to apply to the issue description"),
|
|
2609
|
-
dry_run:
|
|
2610
|
-
.boolean()
|
|
2594
|
+
dry_run: coerceBooleanString
|
|
2611
2595
|
.optional()
|
|
2612
2596
|
.describe("If true, preview changes without updating the issue"),
|
|
2613
|
-
create_note:
|
|
2614
|
-
.boolean()
|
|
2597
|
+
create_note: coerceBooleanString
|
|
2615
2598
|
.optional()
|
|
2616
2599
|
.describe("If true, add a note summarizing the change after update"),
|
|
2617
|
-
allow_multiple:
|
|
2618
|
-
.boolean()
|
|
2600
|
+
allow_multiple: coerceBooleanString
|
|
2619
2601
|
.optional()
|
|
2620
2602
|
.describe("For search_replace: allow multiple matches to all be replaced (default: false — fail on duplicate)"),
|
|
2621
2603
|
});
|
|
@@ -2653,7 +2635,7 @@ export const DeleteIssueLinkSchema = z.object({
|
|
|
2653
2635
|
export const ListNamespacesSchema = z
|
|
2654
2636
|
.object({
|
|
2655
2637
|
search: z.string().optional().describe("Search term for namespaces"),
|
|
2656
|
-
owned:
|
|
2638
|
+
owned: coerceBooleanString.optional().describe("Filter for namespaces owned by current user"),
|
|
2657
2639
|
})
|
|
2658
2640
|
.merge(PaginationOptionsSchema);
|
|
2659
2641
|
export const GetNamespaceSchema = z.object({
|
|
@@ -2713,17 +2695,15 @@ export const UpdateProjectSchema = ProjectParamsSchema.extend({
|
|
|
2713
2695
|
export const ListProjectsSchema = z
|
|
2714
2696
|
.object({
|
|
2715
2697
|
search: z.string().optional().describe("Search term for projects"),
|
|
2716
|
-
search_namespaces:
|
|
2717
|
-
.boolean()
|
|
2698
|
+
search_namespaces: coerceBooleanString
|
|
2718
2699
|
.optional()
|
|
2719
2700
|
.describe("Needs to be true if search is full path"),
|
|
2720
|
-
owned:
|
|
2721
|
-
membership:
|
|
2722
|
-
.boolean()
|
|
2701
|
+
owned: coerceBooleanString.optional().describe("Filter for projects owned by current user"),
|
|
2702
|
+
membership: coerceBooleanString
|
|
2723
2703
|
.optional()
|
|
2724
2704
|
.describe("Filter for projects where current user is a member"),
|
|
2725
|
-
simple:
|
|
2726
|
-
archived:
|
|
2705
|
+
simple: coerceBooleanString.optional().describe("Return only limited fields"),
|
|
2706
|
+
archived: coerceBooleanString.optional().describe("Filter for archived projects"),
|
|
2727
2707
|
visibility: z
|
|
2728
2708
|
.enum(["public", "internal", "private"])
|
|
2729
2709
|
.optional()
|
|
@@ -2736,12 +2716,10 @@ export const ListProjectsSchema = z
|
|
|
2736
2716
|
.enum(["asc", "desc"])
|
|
2737
2717
|
.optional()
|
|
2738
2718
|
.describe("Return projects sorted in ascending or descending order"),
|
|
2739
|
-
with_issues_enabled:
|
|
2740
|
-
.boolean()
|
|
2719
|
+
with_issues_enabled: coerceBooleanString
|
|
2741
2720
|
.optional()
|
|
2742
2721
|
.describe("Filter projects with issues feature enabled"),
|
|
2743
|
-
with_merge_requests_enabled:
|
|
2744
|
-
.boolean()
|
|
2722
|
+
with_merge_requests_enabled: coerceBooleanString
|
|
2745
2723
|
.optional()
|
|
2746
2724
|
.describe("Filter projects with merge requests feature enabled"),
|
|
2747
2725
|
min_access_level: z.coerce.number().optional().describe("Filter by minimum access level"),
|
|
@@ -2752,18 +2730,17 @@ export const ListProjectsSchema = z
|
|
|
2752
2730
|
export const ListLabelsSchema = z
|
|
2753
2731
|
.object({
|
|
2754
2732
|
project_id: z.coerce.string().describe("Project ID or URL-encoded path"),
|
|
2755
|
-
with_counts:
|
|
2756
|
-
.boolean()
|
|
2733
|
+
with_counts: coerceBooleanString
|
|
2757
2734
|
.optional()
|
|
2758
2735
|
.describe("Whether to include issue and merge request counts"),
|
|
2759
|
-
include_ancestor_groups:
|
|
2736
|
+
include_ancestor_groups: coerceBooleanString.optional().describe("Include ancestor groups"),
|
|
2760
2737
|
search: z.string().optional().describe("Keyword to filter labels by"),
|
|
2761
2738
|
})
|
|
2762
2739
|
.merge(PaginationOptionsSchema);
|
|
2763
2740
|
export const GetLabelSchema = z.object({
|
|
2764
2741
|
project_id: z.coerce.string().describe("Project ID or URL-encoded path"),
|
|
2765
2742
|
label_id: z.coerce.string().describe("The ID or title of a project's label"),
|
|
2766
|
-
include_ancestor_groups:
|
|
2743
|
+
include_ancestor_groups: coerceBooleanString.optional().describe("Include ancestor groups"),
|
|
2767
2744
|
});
|
|
2768
2745
|
export const CreateLabelSchema = z.object({
|
|
2769
2746
|
project_id: z.coerce.string().describe("Project ID or URL-encoded path"),
|
|
@@ -2793,32 +2770,30 @@ export const DeleteLabelSchema = z.object({
|
|
|
2793
2770
|
export const ListGroupProjectsSchema = z
|
|
2794
2771
|
.object({
|
|
2795
2772
|
group_id: z.coerce.string().describe("Group ID or path"),
|
|
2796
|
-
include_subgroups:
|
|
2773
|
+
include_subgroups: coerceBooleanString.optional().describe("Include projects from subgroups"),
|
|
2797
2774
|
search: z.string().optional().describe("Search term to filter projects"),
|
|
2798
2775
|
order_by: z
|
|
2799
2776
|
.enum(["name", "path", "created_at", "updated_at", "last_activity_at"])
|
|
2800
2777
|
.optional()
|
|
2801
2778
|
.describe("Field to sort by"),
|
|
2802
2779
|
sort: z.enum(["asc", "desc"]).optional().describe("Sort direction"),
|
|
2803
|
-
archived:
|
|
2780
|
+
archived: coerceBooleanString.optional().describe("Filter for archived projects"),
|
|
2804
2781
|
visibility: z
|
|
2805
2782
|
.enum(["public", "internal", "private"])
|
|
2806
2783
|
.optional()
|
|
2807
2784
|
.describe("Filter by project visibility"),
|
|
2808
|
-
with_issues_enabled:
|
|
2809
|
-
.boolean()
|
|
2785
|
+
with_issues_enabled: coerceBooleanString
|
|
2810
2786
|
.optional()
|
|
2811
2787
|
.describe("Filter projects with issues feature enabled"),
|
|
2812
|
-
with_merge_requests_enabled:
|
|
2813
|
-
.boolean()
|
|
2788
|
+
with_merge_requests_enabled: coerceBooleanString
|
|
2814
2789
|
.optional()
|
|
2815
2790
|
.describe("Filter projects with merge requests feature enabled"),
|
|
2816
2791
|
min_access_level: z.coerce.number().optional().describe("Filter by minimum access level"),
|
|
2817
2792
|
with_programming_language: z.string().optional().describe("Filter by programming language"),
|
|
2818
|
-
starred:
|
|
2819
|
-
statistics:
|
|
2820
|
-
with_custom_attributes:
|
|
2821
|
-
with_security_reports:
|
|
2793
|
+
starred: coerceBooleanString.optional().describe("Filter by starred projects"),
|
|
2794
|
+
statistics: coerceBooleanString.optional().describe("Include project statistics"),
|
|
2795
|
+
with_custom_attributes: coerceBooleanString.optional().describe("Include custom attributes"),
|
|
2796
|
+
with_security_reports: coerceBooleanString.optional().describe("Include security reports"),
|
|
2822
2797
|
topic: z.string().optional().describe("Filter by topic (projects tagged with this topic)"),
|
|
2823
2798
|
})
|
|
2824
2799
|
.merge(PaginationOptionsSchema);
|
|
@@ -2826,9 +2801,8 @@ export const ListGroupProjectsSchema = z
|
|
|
2826
2801
|
export const ListWikiPagesSchema = z
|
|
2827
2802
|
.object({
|
|
2828
2803
|
project_id: z.coerce.string().describe("Project ID or URL-encoded path"),
|
|
2829
|
-
with_content:
|
|
2830
|
-
render_html:
|
|
2831
|
-
.boolean()
|
|
2804
|
+
with_content: coerceBooleanString.optional().describe("Include content of the wiki pages"),
|
|
2805
|
+
render_html: coerceBooleanString
|
|
2832
2806
|
.optional()
|
|
2833
2807
|
.describe("Return rendered HTML content and include front_matter (e.g., the custom title)"),
|
|
2834
2808
|
})
|
|
@@ -2836,8 +2810,7 @@ export const ListWikiPagesSchema = z
|
|
|
2836
2810
|
export const GetWikiPageSchema = z.object({
|
|
2837
2811
|
project_id: z.coerce.string().describe("Project ID or URL-encoded path"),
|
|
2838
2812
|
slug: z.string().describe("Slug of the wiki page (will be URL-encoded internally)"),
|
|
2839
|
-
render_html:
|
|
2840
|
-
.boolean()
|
|
2813
|
+
render_html: coerceBooleanString
|
|
2841
2814
|
.optional()
|
|
2842
2815
|
.describe("Return rendered HTML content and include front_matter (e.g., the custom title)"),
|
|
2843
2816
|
});
|
|
@@ -2875,9 +2848,8 @@ export const GitLabWikiPageSchema = z.object({
|
|
|
2875
2848
|
export const ListGroupWikiPagesSchema = z
|
|
2876
2849
|
.object({
|
|
2877
2850
|
group_id: z.coerce.string().describe("Group ID or URL-encoded path"),
|
|
2878
|
-
with_content:
|
|
2879
|
-
render_html:
|
|
2880
|
-
.boolean()
|
|
2851
|
+
with_content: coerceBooleanString.optional().describe("Include content of the wiki pages"),
|
|
2852
|
+
render_html: coerceBooleanString
|
|
2881
2853
|
.optional()
|
|
2882
2854
|
.describe("Return rendered HTML content and include front_matter (e.g., the custom title)"),
|
|
2883
2855
|
})
|
|
@@ -2885,8 +2857,7 @@ export const ListGroupWikiPagesSchema = z
|
|
|
2885
2857
|
export const GetGroupWikiPageSchema = z.object({
|
|
2886
2858
|
group_id: z.coerce.string().describe("Group ID or URL-encoded path"),
|
|
2887
2859
|
slug: z.string().describe("Slug of the wiki page (will be URL-encoded internally)"),
|
|
2888
|
-
render_html:
|
|
2889
|
-
.boolean()
|
|
2860
|
+
render_html: coerceBooleanString
|
|
2890
2861
|
.optional()
|
|
2891
2862
|
.describe("Return rendered HTML content and include front_matter (e.g., the custom title)"),
|
|
2892
2863
|
});
|
|
@@ -3072,8 +3043,7 @@ export const CreateDraftNoteSchema = ProjectParamsSchema.extend({
|
|
|
3072
3043
|
.optional()
|
|
3073
3044
|
.describe("The ID of a discussion the draft note replies to"),
|
|
3074
3045
|
position: optionalMergeRequestThreadPosition.describe("Position when creating a diff note"),
|
|
3075
|
-
resolve_discussion:
|
|
3076
|
-
.boolean()
|
|
3046
|
+
resolve_discussion: coerceBooleanString
|
|
3077
3047
|
.optional()
|
|
3078
3048
|
.describe("Whether to resolve the discussion when publishing"),
|
|
3079
3049
|
});
|
|
@@ -3083,8 +3053,7 @@ export const UpdateDraftNoteSchema = ProjectParamsSchema.extend({
|
|
|
3083
3053
|
draft_note_id: z.coerce.string().describe("The ID of the draft note"),
|
|
3084
3054
|
body: z.string().optional().describe("The content of the draft note"),
|
|
3085
3055
|
position: optionalMergeRequestThreadPosition.describe("Position when creating a diff note"),
|
|
3086
|
-
resolve_discussion:
|
|
3087
|
-
.boolean()
|
|
3056
|
+
resolve_discussion: coerceBooleanString
|
|
3088
3057
|
.optional()
|
|
3089
3058
|
.describe("Whether to resolve the discussion when publishing"),
|
|
3090
3059
|
});
|
|
@@ -3109,8 +3078,7 @@ export const BulkPublishDraftNotesSchema = ProjectParamsSchema.extend({
|
|
|
3109
3078
|
.string()
|
|
3110
3079
|
.optional()
|
|
3111
3080
|
.describe("Summary note body to post on the merge request (GitLab 19.2+)"),
|
|
3112
|
-
internal:
|
|
3113
|
-
.boolean()
|
|
3081
|
+
internal: coerceBooleanString
|
|
3114
3082
|
.optional()
|
|
3115
3083
|
.describe("If true, the summary note is internal (GitLab 19.2+, default false)"),
|
|
3116
3084
|
});
|
|
@@ -3124,7 +3092,7 @@ export const CreateMergeRequestThreadSchema = ProjectParamsSchema.extend({
|
|
|
3124
3092
|
export const ResolveMergeRequestThreadSchema = ProjectParamsSchema.extend({
|
|
3125
3093
|
merge_request_iid: z.coerce.string().describe("The IID of a merge request"),
|
|
3126
3094
|
discussion_id: z.coerce.string().describe("The ID of a thread"),
|
|
3127
|
-
resolved:
|
|
3095
|
+
resolved: coerceBooleanString.describe("Whether to resolve the thread"),
|
|
3128
3096
|
});
|
|
3129
3097
|
// Milestone related schemas
|
|
3130
3098
|
// Schema for listing project milestones
|
|
@@ -3145,7 +3113,7 @@ export const ListProjectMilestonesSchema = ProjectParamsSchema.extend({
|
|
|
3145
3113
|
.string()
|
|
3146
3114
|
.optional()
|
|
3147
3115
|
.describe("Return only milestones with a title or description matching the provided string"),
|
|
3148
|
-
include_ancestors:
|
|
3116
|
+
include_ancestors: coerceBooleanString.optional().describe("Include ancestor groups"),
|
|
3149
3117
|
updated_before: z
|
|
3150
3118
|
.string()
|
|
3151
3119
|
.optional()
|
|
@@ -3207,8 +3175,8 @@ export const ListGroupMilestonesSchema = z
|
|
|
3207
3175
|
.string()
|
|
3208
3176
|
.optional()
|
|
3209
3177
|
.describe("Return only milestones with a title or description matching the provided string"),
|
|
3210
|
-
include_ancestors:
|
|
3211
|
-
include_descendants:
|
|
3178
|
+
include_ancestors: coerceBooleanString.optional().describe("Include ancestor groups"),
|
|
3179
|
+
include_descendants: coerceBooleanString.optional().describe("Include descendant groups"),
|
|
3212
3180
|
updated_before: z
|
|
3213
3181
|
.string()
|
|
3214
3182
|
.optional()
|
|
@@ -3261,18 +3229,15 @@ export const ListCommitsSchema = z.object({
|
|
|
3261
3229
|
.describe("Only commits before or on this date are returned in ISO 8601 format YYYY-MM-DDTHH:MM:SSZ"),
|
|
3262
3230
|
path: z.string().optional().describe("The file path"),
|
|
3263
3231
|
author: z.string().optional().describe("Search commits by commit author"),
|
|
3264
|
-
all:
|
|
3265
|
-
with_stats:
|
|
3266
|
-
.boolean()
|
|
3232
|
+
all: coerceBooleanString.optional().describe("Retrieve every commit from the repository"),
|
|
3233
|
+
with_stats: coerceBooleanString
|
|
3267
3234
|
.optional()
|
|
3268
3235
|
.describe("Stats about each commit are added to the response"),
|
|
3269
|
-
first_parent:
|
|
3270
|
-
.boolean()
|
|
3236
|
+
first_parent: coerceBooleanString
|
|
3271
3237
|
.optional()
|
|
3272
3238
|
.describe("Follow only the first parent commit upon seeing a merge commit"),
|
|
3273
3239
|
order: z.enum(["default", "topo"]).optional().describe("List commits in order"),
|
|
3274
|
-
trailers:
|
|
3275
|
-
.boolean()
|
|
3240
|
+
trailers: coerceBooleanString
|
|
3276
3241
|
.optional()
|
|
3277
3242
|
.describe("Parse and include Git trailers for every commit"),
|
|
3278
3243
|
page: z.coerce.number().optional().describe("Page number for pagination (default: 1)"),
|
|
@@ -3284,13 +3249,12 @@ export const ListCommitsSchema = z.object({
|
|
|
3284
3249
|
export const GetCommitSchema = z.object({
|
|
3285
3250
|
project_id: z.coerce.string().describe("Project ID or complete URL-encoded path to project"),
|
|
3286
3251
|
sha: z.string().describe("The commit hash or name of a repository branch or tag"),
|
|
3287
|
-
stats:
|
|
3252
|
+
stats: coerceBooleanString.optional().describe("Include commit stats"),
|
|
3288
3253
|
});
|
|
3289
3254
|
export const GetCommitDiffSchema = z.object({
|
|
3290
3255
|
project_id: z.coerce.string().describe("Project ID or complete URL-encoded path to project"),
|
|
3291
3256
|
sha: z.string().describe("The commit hash or name of a repository branch or tag"),
|
|
3292
|
-
full_diff:
|
|
3293
|
-
.boolean()
|
|
3257
|
+
full_diff: coerceBooleanString
|
|
3294
3258
|
.optional()
|
|
3295
3259
|
.describe("Whether to return the full diff or only first page (default: false)"),
|
|
3296
3260
|
});
|
|
@@ -3410,8 +3374,7 @@ export const ListProjectMembersSchema = z.object({
|
|
|
3410
3374
|
query: z.string().optional().describe("Search for members by name or username"),
|
|
3411
3375
|
user_ids: z.array(z.coerce.number()).optional().describe("Filter by user IDs"),
|
|
3412
3376
|
skip_users: z.array(z.coerce.number()).optional().describe("User IDs to exclude"),
|
|
3413
|
-
include_inheritance:
|
|
3414
|
-
.boolean()
|
|
3377
|
+
include_inheritance: coerceBooleanString
|
|
3415
3378
|
.optional()
|
|
3416
3379
|
.describe("Include inherited members. Defaults to false."),
|
|
3417
3380
|
per_page: z.coerce
|
|
@@ -3426,8 +3389,7 @@ export const ListGroupMembersSchema = z.object({
|
|
|
3426
3389
|
query: z.string().optional().describe("Search for members by name or username"),
|
|
3427
3390
|
user_ids: z.array(z.coerce.number()).optional().describe("Filter by user IDs"),
|
|
3428
3391
|
skip_users: z.array(z.coerce.number()).optional().describe("User IDs to exclude"),
|
|
3429
|
-
include_inheritance:
|
|
3430
|
-
.boolean()
|
|
3392
|
+
include_inheritance: coerceBooleanString
|
|
3431
3393
|
.optional()
|
|
3432
3394
|
.describe("Include inherited members. Defaults to false."),
|
|
3433
3395
|
per_page: z.coerce
|
|
@@ -3510,12 +3472,10 @@ export const ListGroupIterationsSchema = z
|
|
|
3510
3472
|
.array(z.enum(["title", "cadence_title"]))
|
|
3511
3473
|
.optional()
|
|
3512
3474
|
.describe("Fields in which fuzzy search should be performed with the query given in the argument search. The available options are title and cadence_title. Default is [title]."),
|
|
3513
|
-
include_ancestors:
|
|
3514
|
-
.boolean()
|
|
3475
|
+
include_ancestors: coerceBooleanString
|
|
3515
3476
|
.optional()
|
|
3516
3477
|
.describe("Include iterations for group and its ancestors. Defaults to true."),
|
|
3517
|
-
include_descendants:
|
|
3518
|
-
.boolean()
|
|
3478
|
+
include_descendants: coerceBooleanString
|
|
3519
3479
|
.optional()
|
|
3520
3480
|
.describe("Include iterations for group and its descendants. Defaults to false."),
|
|
3521
3481
|
updated_before: z
|
|
@@ -3716,8 +3676,7 @@ export const ListReleasesSchema = z
|
|
|
3716
3676
|
.enum(["desc", "asc"])
|
|
3717
3677
|
.optional()
|
|
3718
3678
|
.describe("The direction of the order. Either desc (default) for descending order or asc for ascending order."),
|
|
3719
|
-
include_html_description:
|
|
3720
|
-
.boolean()
|
|
3679
|
+
include_html_description: coerceBooleanString
|
|
3721
3680
|
.optional()
|
|
3722
3681
|
.describe("If true, a response includes HTML rendered Markdown of the release description."),
|
|
3723
3682
|
})
|
|
@@ -3725,8 +3684,7 @@ export const ListReleasesSchema = z
|
|
|
3725
3684
|
export const GetReleaseSchema = z.object({
|
|
3726
3685
|
project_id: z.coerce.string().describe("Project ID or URL-encoded path"),
|
|
3727
3686
|
tag_name: z.string().describe("The Git tag the release is associated with"),
|
|
3728
|
-
include_html_description:
|
|
3729
|
-
.boolean()
|
|
3687
|
+
include_html_description: coerceBooleanString
|
|
3730
3688
|
.optional()
|
|
3731
3689
|
.describe("If true, a response includes HTML rendered Markdown of the release description."),
|
|
3732
3690
|
});
|
|
@@ -3808,7 +3766,7 @@ export const ListJobArtifactsSchema = z.object({
|
|
|
3808
3766
|
.string()
|
|
3809
3767
|
.optional()
|
|
3810
3768
|
.describe("Directory path within the artifacts archive (defaults to root)"),
|
|
3811
|
-
recursive:
|
|
3769
|
+
recursive: coerceBooleanString.optional().describe("Whether to list artifacts recursively"),
|
|
3812
3770
|
});
|
|
3813
3771
|
export const GitLabArtifactEntrySchema = z.object({
|
|
3814
3772
|
name: z.string(),
|
|
@@ -4244,7 +4202,7 @@ export const CreateWorkItemSchema = z.object({
|
|
|
4244
4202
|
.string()
|
|
4245
4203
|
.optional()
|
|
4246
4204
|
.describe("Iteration ID (e.g. 'gid://gitlab/Iteration/123' or numeric ID). Use list_group_iterations to find available iterations."),
|
|
4247
|
-
confidential:
|
|
4205
|
+
confidential: coerceBooleanString.optional().describe("Set confidentiality"),
|
|
4248
4206
|
});
|
|
4249
4207
|
export const UpdateWorkItemSchema = WorkItemParamsSchema.extend({
|
|
4250
4208
|
title: z.string().optional().describe("New title"),
|
|
@@ -4268,8 +4226,7 @@ export const UpdateWorkItemSchema = WorkItemParamsSchema.extend({
|
|
|
4268
4226
|
.string()
|
|
4269
4227
|
.optional()
|
|
4270
4228
|
.describe("Project ID or path of the parent work item (defaults to same project as the work item)"),
|
|
4271
|
-
remove_parent:
|
|
4272
|
-
.boolean()
|
|
4229
|
+
remove_parent: coerceBooleanString
|
|
4273
4230
|
.optional()
|
|
4274
4231
|
.describe("Set to true to remove the parent from hierarchy"),
|
|
4275
4232
|
children_to_add: z
|
|
@@ -4306,7 +4263,7 @@ export const UpdateWorkItemSchema = WorkItemParamsSchema.extend({
|
|
|
4306
4263
|
.string()
|
|
4307
4264
|
.optional()
|
|
4308
4265
|
.describe("Iteration ID (e.g. 'gid://gitlab/Iteration/123' or numeric ID). Use list_group_iterations to find available iterations."),
|
|
4309
|
-
confidential:
|
|
4266
|
+
confidential: coerceBooleanString.optional().describe("Set confidentiality"),
|
|
4310
4267
|
linked_items_to_add: z
|
|
4311
4268
|
.array(z.object({
|
|
4312
4269
|
project_id: z.coerce
|
|
@@ -4390,10 +4347,7 @@ export const CreateWorkItemNoteSchema = z.object({
|
|
|
4390
4347
|
project_id: NamespaceIdOrPathSchema,
|
|
4391
4348
|
iid: z.coerce.number().describe("The internal ID of the work item"),
|
|
4392
4349
|
body: z.string().describe("Note body (Markdown supported)"),
|
|
4393
|
-
internal:
|
|
4394
|
-
.boolean()
|
|
4395
|
-
.optional()
|
|
4396
|
-
.default(false)
|
|
4350
|
+
internal: coerceBooleanStringDefault(false)
|
|
4397
4351
|
.describe("Create as internal/confidential note (only visible to project members)"),
|
|
4398
4352
|
discussion_id: z
|
|
4399
4353
|
.string()
|
|
@@ -4580,8 +4534,7 @@ export const ListWebhookEventsSchema = z
|
|
|
4580
4534
|
.union([z.coerce.number(), z.string()])
|
|
4581
4535
|
.optional()
|
|
4582
4536
|
.describe("Filter by response status code (e.g. 200, 500) or category: successful, client_failure, server_failure"),
|
|
4583
|
-
summary:
|
|
4584
|
-
.boolean()
|
|
4537
|
+
summary: coerceBooleanString
|
|
4585
4538
|
.optional()
|
|
4586
4539
|
.describe("If true, return only summary fields (id, url, trigger, response_status, execution_duration) without full request/response payloads. Recommended for overview queries to avoid huge responses."),
|
|
4587
4540
|
per_page: z.number().max(20).optional().default(20).describe("Number of events per page"),
|
|
@@ -2,7 +2,7 @@ const TOOL_GUIDANCE = {
|
|
|
2
2
|
merge_merge_request: "Use this only after checking the merge request approval, conflict, and pipeline state; use `approve_merge_request` to approve rather than merge. The operation changes repository state and may squash commits, schedule auto-merge, or delete the source branch, so it requires merge permission and returns GitLab's merge result or a mergeability error. Pass `sha` from `get_merge_request` (`sha` or `diff_refs.head_sha`); GitLab 19.2+ groups may reject merges without it.",
|
|
3
3
|
approve_merge_request: "Use this to record an approval on an existing merge request; it does not merge the request or change its source branch. The operation changes review state, may require re-authentication or approval permission, and returns the updated approval result or a permission/state error.",
|
|
4
4
|
unapprove_merge_request: "Use this to remove the current user's approval from an existing merge request; use `merge_merge_request` only when you intend to merge. The operation changes review state and requires approval permission, and GitLab returns the updated result or an error when the request or approval is unavailable.",
|
|
5
|
-
rebase_merge_request: "Use this when the source branch is behind its target branch; use `get_merge_request_conflicts` to inspect conflicts and `merge_merge_request` to merge. The operation rewrites the source branch history with a force push and requires permission to push to that branch. With `wait` true (default), it polls until the rebase ends and returns the merge request
|
|
5
|
+
rebase_merge_request: "Use this when the source branch is behind its target branch; use `get_merge_request_conflicts` to inspect conflicts and `merge_merge_request` to merge. The operation rewrites the source branch history with a force push and requires permission to push to that branch. With `wait` true (default), it polls until the rebase ends and returns the merge request plus `previous_sha` (its `sha` before the rebase) and `head_changed`. `head_changed: false` means that the head did not move; `merge_error` gives the reason when GitLab sends one. `merge_error` can keep a message from an earlier attempt, so it alone does not prove that this attempt failed. If the rebase still runs after `timeout_seconds`, it returns a timeout error while GitLab continues the rebase. With `wait` false, it returns GitLab's enqueue response (`rebase_in_progress` true) at once. Set `skip_ci` to skip the CI pipeline for the rebased branch.",
|
|
6
6
|
get_merge_request_approval_state: "Use this to inspect approval rules and approvers before deciding whether a merge request can be merged; use `approve_merge_request` to change approval state. It is read-only and returns the approval-state response, while missing requests, unsupported GitLab versions, and permission failures are reported as errors.",
|
|
7
7
|
get_merge_request_conflicts: "Use this to inspect merge conflicts before attempting `merge_merge_request`; it reports conflicts and does not resolve them. It is read-only, requires access to the project and merge request, and returns GitLab's conflict data or an error when the request cannot be evaluated.",
|
|
8
8
|
list_merge_request_pipelines: "Use this to inspect pipelines associated with one merge request; use `list_pipelines` for project-wide pipeline filtering. It is read-only and paginated, requires project access, and returns pipeline records or GitLab errors for invalid identifiers, missing resources, or rate limits.",
|
package/build/utils/schema.js
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
// JSON Schema produced by toJSONSchema -> the Zod schema it came from.
|
|
3
|
+
const zodSchemaByJsonSchema = new WeakMap();
|
|
4
|
+
/**
|
|
5
|
+
* Returns the Zod schema a toJSONSchema() result was built from, if any.
|
|
6
|
+
*/
|
|
7
|
+
export const zodSchemaFor = (jsonSchema) => jsonSchema && typeof jsonSchema === "object" ? zodSchemaByJsonSchema.get(jsonSchema) : undefined;
|
|
2
8
|
/**
|
|
3
9
|
* Convert a Zod schema to JSON Schema, fixing nullable/optional fields
|
|
4
10
|
* so they are not marked as required, and extracting required fields from the Zod schema.
|
|
@@ -154,5 +160,6 @@ export const toJSONSchema = (schema) => {
|
|
|
154
160
|
}
|
|
155
161
|
}
|
|
156
162
|
}
|
|
163
|
+
zodSchemaByJsonSchema.set(fixedSchema, schema);
|
|
157
164
|
return fixedSchema;
|
|
158
165
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zereight/mcp-gitlab",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.2",
|
|
4
4
|
"mcpName": "io.github.zereight/gitlab-mcp",
|
|
5
5
|
"description": "GitLab MCP server for projects, merge requests, issues, pipelines, wiki, releases, and more",
|
|
6
6
|
"keywords": [
|
|
@@ -69,6 +69,7 @@
|
|
|
69
69
|
"lint:fix": "eslint . --fix",
|
|
70
70
|
"release": "bash scripts/release.sh",
|
|
71
71
|
"release:mcp-registry": "bash scripts/publish_mcp_registry.sh",
|
|
72
|
+
"pack:mcpb": "npm run build && bash scripts/pack-mcpb.sh",
|
|
72
73
|
"format": "prettier --write \"**/*.{js,ts,json,md}\"",
|
|
73
74
|
"format:check": "prettier --check \"**/*.{js,ts,json,md}\""
|
|
74
75
|
},
|