@zereight/mcp-gitlab 2.3.0 → 2.3.1

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 CHANGED
@@ -138,7 +138,7 @@ 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.2.6`처럼 직전 안정 버전(문서가 권장하는 버전)으로 고정하세요. 항상 최신 버전을 원하면 `npx -y @zereight/mcp-gitlab@latest`를 사용하세요. 새 버전이 나오면 서버가 시작 시 stderr로 알려줍니다(`GITLAB_DISABLE_VERSION_CHECK=true`로 비활성화 가능).
141
+ 전역 설치를 쓰지 않으려면 `npx -y @zereight/mcp-gitlab@2.3.0`처럼 직전 안정 버전(문서가 권장하는 버전)으로 고정하세요. 항상 최신 버전을 원하면 `npx -y @zereight/mcp-gitlab@latest`를 사용하세요. 새 버전이 나오면 서버가 시작 시 stderr로 알려줍니다(`GITLAB_DISABLE_VERSION_CHECK=true`로 비활성화 가능).
142
142
 
143
143
  #### CLI 인자 사용하기(환경 변수 문제가 있는 클라이언트용)
144
144
 
package/README.md CHANGED
@@ -143,7 +143,7 @@ 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.2.6`. 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`).
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.0`. 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
147
 
148
148
  #### Using CLI Arguments (for clients with env var issues)
149
149
 
package/README.pt-BR.md CHANGED
@@ -138,7 +138,7 @@ 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.2.6`. 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`).
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.0`. 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
142
 
143
143
  #### Usando argumentos de CLI (para clientes com problemas com variáveis de ambiente)
144
144
 
package/README.zh-CN.md CHANGED
@@ -138,7 +138,7 @@ 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.2.6`。如果始终想使用最新版本,请改用 `npx -y @zereight/mcp-gitlab@latest`。有新版本发布时,服务器会在启动时通过 stderr 提示(可用 `GITLAB_DISABLE_VERSION_CHECK=true` 关闭)。
141
+ 如果不想全局安装,请将 `npx` 固定到上一个稳定版本(即文档推荐的版本),例如 `npx -y @zereight/mcp-gitlab@2.3.0`。如果始终想使用最新版本,请改用 `npx -y @zereight/mcp-gitlab@latest`。有新版本发布时,服务器会在启动时通过 stderr 提示(可用 `GITLAB_DISABLE_VERSION_CHECK=true` 关闭)。
142
142
 
143
143
  #### 使用 CLI 参数(适用于环境变量有问题的客户端)
144
144
 
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
- const coerceBooleanString = z.preprocess(val => {
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
- }, z.boolean());
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: z.coerce
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: z.coerce.boolean().optional().describe("Whether to include retried jobs"),
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: z.coerce.boolean().optional().describe("Run pipeline creation simulation"),
386
- include_jobs: z.coerce.boolean().optional().describe("Include jobs in the lint response"),
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: z.coerce.boolean().optional().describe("Run pipeline creation simulation"),
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: z.coerce.boolean().optional().describe("Include jobs in the lint response"),
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: z.coerce.boolean().optional().describe("Include version README content"),
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: z.coerce.boolean().optional().describe("Force cancellation of the job"),
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: z.coerce.boolean().optional().describe("Boolean value to get a recursive tree"),
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: z.coerce.boolean().optional(), // Changed from auto_init to match GitLab API
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: z.coerce.boolean().optional().describe("Resolve or unresolve the note"),
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: z.coerce.boolean().optional().describe("Resolve or unresolve the note"),
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: z.coerce.boolean().optional().describe("Initialize with README.md"),
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: z.coerce.boolean().optional().describe("Create as draft merge request"),
2015
- allow_collaboration: z.coerce
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: z.coerce
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: z.coerce
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: z.coerce
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: z.coerce
2200
- .boolean()
2203
+ remove_source_branch: coerceBooleanString
2201
2204
  .optional()
2202
2205
  .describe("Flag indicating if the source branch should be removed"),
2203
- squash: z.coerce
2204
- .boolean()
2206
+ squash: coerceBooleanString
2205
2207
  .optional()
2206
2208
  .describe("Squash commits into a single commit when merging"),
2207
- draft: z.coerce.boolean().optional().describe("Work in progress merge request"),
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: z.coerce
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: z.coerce
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: z.coerce
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: z.coerce
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: z.coerce
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: z.coerce
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: z.coerce
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: z.coerce.boolean().optional().describe("Filter confidential or public issues"),
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: z.coerce
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: z.coerce
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: z.coerce.boolean().optional().describe("Set the issue to be confidential"),
2582
- discussion_locked: z.coerce.boolean().optional().describe("Flag to lock discussions"),
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: z.coerce
2610
- .boolean()
2594
+ dry_run: coerceBooleanString
2611
2595
  .optional()
2612
2596
  .describe("If true, preview changes without updating the issue"),
2613
- create_note: z.coerce
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: z.coerce
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: z.coerce.boolean().optional().describe("Filter for namespaces owned by current user"),
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: z.coerce
2717
- .boolean()
2698
+ search_namespaces: coerceBooleanString
2718
2699
  .optional()
2719
2700
  .describe("Needs to be true if search is full path"),
2720
- owned: z.coerce.boolean().optional().describe("Filter for projects owned by current user"),
2721
- membership: z.coerce
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: z.coerce.boolean().optional().describe("Return only limited fields"),
2726
- archived: z.coerce.boolean().optional().describe("Filter for archived projects"),
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: z.coerce
2740
- .boolean()
2719
+ with_issues_enabled: coerceBooleanString
2741
2720
  .optional()
2742
2721
  .describe("Filter projects with issues feature enabled"),
2743
- with_merge_requests_enabled: z.coerce
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: z.coerce
2756
- .boolean()
2733
+ with_counts: coerceBooleanString
2757
2734
  .optional()
2758
2735
  .describe("Whether to include issue and merge request counts"),
2759
- include_ancestor_groups: z.coerce.boolean().optional().describe("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: z.coerce.boolean().optional().describe("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: z.coerce.boolean().optional().describe("Include projects from 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: z.coerce.boolean().optional().describe("Filter for archived projects"),
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: z.coerce
2809
- .boolean()
2785
+ with_issues_enabled: coerceBooleanString
2810
2786
  .optional()
2811
2787
  .describe("Filter projects with issues feature enabled"),
2812
- with_merge_requests_enabled: z.coerce
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: z.coerce.boolean().optional().describe("Filter by starred projects"),
2819
- statistics: z.coerce.boolean().optional().describe("Include project statistics"),
2820
- with_custom_attributes: z.coerce.boolean().optional().describe("Include custom attributes"),
2821
- with_security_reports: z.coerce.boolean().optional().describe("Include 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: z.coerce.boolean().optional().describe("Include content of the wiki pages"),
2830
- render_html: z.coerce
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: z.coerce
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: z.coerce.boolean().optional().describe("Include content of the wiki pages"),
2879
- render_html: z.coerce
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: z.coerce
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: z.coerce
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: z.coerce
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: z.coerce
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: z.coerce.boolean().describe("Whether to resolve the thread"),
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: z.coerce.boolean().optional().describe("Include ancestor groups"),
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: z.coerce.boolean().optional().describe("Include ancestor groups"),
3211
- include_descendants: z.coerce.boolean().optional().describe("Include descendant groups"),
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: z.coerce.boolean().optional().describe("Retrieve every commit from the repository"),
3265
- with_stats: z.coerce
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: z.coerce
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: z.coerce
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: z.coerce.boolean().optional().describe("Include commit 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: z.coerce
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: z.coerce
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: z.coerce
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: z.coerce
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: z.coerce
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: z.coerce
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: z.coerce
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: z.coerce.boolean().optional().describe("Whether to list artifacts recursively"),
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: z.coerce.boolean().optional().describe("Set confidentiality"),
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: z.coerce
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: z.coerce.boolean().optional().describe("Set confidentiality"),
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: z.coerce
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: z.coerce
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"),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zereight/mcp-gitlab",
3
- "version": "2.3.0",
3
+ "version": "2.3.1",
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": [