@zereight/mcp-gitlab 2.2.6 → 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/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
@@ -2253,6 +2243,30 @@ export const ApproveMergeRequestSchema = ProjectParamsSchema.extend({
2253
2243
  export const UnapproveMergeRequestSchema = ProjectParamsSchema.extend({
2254
2244
  merge_request_iid: z.coerce.string().describe("The IID of the merge request to unapprove"),
2255
2245
  });
2246
+ export const RebaseMergeRequestSchema = ProjectParamsSchema.extend({
2247
+ merge_request_iid: z.coerce.string().describe("The IID of the merge request to rebase"),
2248
+ skip_ci: coerceBooleanString
2249
+ .optional()
2250
+ .describe("If true, GitLab does not create a CI pipeline for the rebased source branch"),
2251
+ wait: coerceBooleanString
2252
+ .optional()
2253
+ .default(true)
2254
+ .describe("If true, poll the merge request until the rebase ends or timeout_seconds passes. If false, return GitLab's enqueue response at once."),
2255
+ timeout_seconds: z.coerce
2256
+ .number()
2257
+ .int()
2258
+ .min(1)
2259
+ .max(600)
2260
+ .optional()
2261
+ .describe("Maximum seconds to wait for the rebase to end"),
2262
+ poll_interval_seconds: z.coerce
2263
+ .number()
2264
+ .int()
2265
+ .min(1)
2266
+ .max(30)
2267
+ .optional()
2268
+ .describe("Seconds between status polls while waiting for the rebase"),
2269
+ });
2256
2270
  // Merge Request Approval State response schema
2257
2271
  export const GitLabApprovalUserSchema = z.object({
2258
2272
  id: z.coerce.string(),
@@ -2340,8 +2354,7 @@ export const ListMergeRequestDiffsSchema = MergeRequestParamsSchema.extend({
2340
2354
  .number()
2341
2355
  .optional()
2342
2356
  .describe("Number of items per page (max: 100, default: 20)"),
2343
- unidiff: z.coerce
2344
- .boolean()
2357
+ unidiff: coerceBooleanString
2345
2358
  .optional()
2346
2359
  .describe("Present diffs in the unified diff format. Default is false. Introduced in GitLab 16.5."),
2347
2360
  });
@@ -2356,8 +2369,7 @@ export const GetMergeRequestFileDiffSchema = MergeRequestParamsSchema.extend({
2356
2369
  .array(z.string())
2357
2370
  .describe("List of file paths to retrieve diffs for (e.g. ['src/api/users.ts', 'src/repo/user.go']). " +
2358
2371
  "Call list_merge_request_changed_files first to get the full list of changed paths."),
2359
- unidiff: z.coerce
2360
- .boolean()
2372
+ unidiff: coerceBooleanString
2361
2373
  .optional()
2362
2374
  .describe("Present diff in the unified diff format. Default is false."),
2363
2375
  });
@@ -2367,8 +2379,7 @@ export const ListMergeRequestVersionsSchema = ProjectParamsSchema.extend({
2367
2379
  });
2368
2380
  export const GetMergeRequestVersionSchema = ListMergeRequestVersionsSchema.extend({
2369
2381
  version_id: z.coerce.string().describe("The ID of the merge request diff version"),
2370
- unidiff: z.coerce
2371
- .boolean()
2382
+ unidiff: coerceBooleanString
2372
2383
  .optional()
2373
2384
  .describe("Present diffs in the unified diff format. Default is false. Introduced in GitLab 16.5."),
2374
2385
  });
@@ -2403,7 +2414,7 @@ export const ListIssuesSchema = z
2403
2414
  .string()
2404
2415
  .optional()
2405
2416
  .describe("Return issues created by the given username. Mutually exclusive with author_id."),
2406
- confidential: z.coerce.boolean().optional().describe("Filter confidential or public issues"),
2417
+ confidential: coerceBooleanString.optional().describe("Filter confidential or public issues"),
2407
2418
  created_after: z.string().optional().describe("Return issues created after the given time"),
2408
2419
  created_before: z.string().optional().describe("Return issues created before the given time"),
2409
2420
  due_date: z.string().optional().describe("Return issues that have the due date"),
@@ -2428,8 +2439,7 @@ export const ListIssuesSchema = z
2428
2439
  .describe("Return issues with a specific state"),
2429
2440
  updated_after: z.string().optional().describe("Return issues updated after the given time"),
2430
2441
  updated_before: z.string().optional().describe("Return issues updated before the given time"),
2431
- with_labels_details: z.coerce
2432
- .boolean()
2442
+ with_labels_details: coerceBooleanString
2433
2443
  .optional()
2434
2444
  .describe("Return more details for each label"),
2435
2445
  })
@@ -2522,8 +2532,7 @@ export const ListMergeRequestsSchema = z
2522
2532
  .enum(["yes", "no"])
2523
2533
  .optional()
2524
2534
  .describe("Filter merge requests against their wip status"),
2525
- with_labels_details: z.coerce
2526
- .boolean()
2535
+ with_labels_details: coerceBooleanString
2527
2536
  .optional()
2528
2537
  .describe("Return more details for each label"),
2529
2538
  })
@@ -2554,8 +2563,8 @@ export const UpdateIssueSchema = z.object({
2554
2563
  .array(z.coerce.number())
2555
2564
  .optional()
2556
2565
  .describe("Array of user IDs to assign issue to"),
2557
- confidential: z.coerce.boolean().optional().describe("Set the issue to be confidential"),
2558
- 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"),
2559
2568
  due_date: z.string().optional().describe("Date the issue is due (YYYY-MM-DD)"),
2560
2569
  labels: coerceStringArray.optional().describe("Array of label names"),
2561
2570
  milestone_id: z.coerce.string().optional().describe("Milestone ID to assign"),
@@ -2582,16 +2591,13 @@ export const UpdateIssueDescriptionPatchSchema = z.object({
2582
2591
  .min(1)
2583
2592
  .max(50000)
2584
2593
  .describe("The patch content to apply to the issue description"),
2585
- dry_run: z.coerce
2586
- .boolean()
2594
+ dry_run: coerceBooleanString
2587
2595
  .optional()
2588
2596
  .describe("If true, preview changes without updating the issue"),
2589
- create_note: z.coerce
2590
- .boolean()
2597
+ create_note: coerceBooleanString
2591
2598
  .optional()
2592
2599
  .describe("If true, add a note summarizing the change after update"),
2593
- allow_multiple: z.coerce
2594
- .boolean()
2600
+ allow_multiple: coerceBooleanString
2595
2601
  .optional()
2596
2602
  .describe("For search_replace: allow multiple matches to all be replaced (default: false — fail on duplicate)"),
2597
2603
  });
@@ -2629,7 +2635,7 @@ export const DeleteIssueLinkSchema = z.object({
2629
2635
  export const ListNamespacesSchema = z
2630
2636
  .object({
2631
2637
  search: z.string().optional().describe("Search term for namespaces"),
2632
- 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"),
2633
2639
  })
2634
2640
  .merge(PaginationOptionsSchema);
2635
2641
  export const GetNamespaceSchema = z.object({
@@ -2689,17 +2695,15 @@ export const UpdateProjectSchema = ProjectParamsSchema.extend({
2689
2695
  export const ListProjectsSchema = z
2690
2696
  .object({
2691
2697
  search: z.string().optional().describe("Search term for projects"),
2692
- search_namespaces: z.coerce
2693
- .boolean()
2698
+ search_namespaces: coerceBooleanString
2694
2699
  .optional()
2695
2700
  .describe("Needs to be true if search is full path"),
2696
- owned: z.coerce.boolean().optional().describe("Filter for projects owned by current user"),
2697
- membership: z.coerce
2698
- .boolean()
2701
+ owned: coerceBooleanString.optional().describe("Filter for projects owned by current user"),
2702
+ membership: coerceBooleanString
2699
2703
  .optional()
2700
2704
  .describe("Filter for projects where current user is a member"),
2701
- simple: z.coerce.boolean().optional().describe("Return only limited fields"),
2702
- 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"),
2703
2707
  visibility: z
2704
2708
  .enum(["public", "internal", "private"])
2705
2709
  .optional()
@@ -2712,12 +2716,10 @@ export const ListProjectsSchema = z
2712
2716
  .enum(["asc", "desc"])
2713
2717
  .optional()
2714
2718
  .describe("Return projects sorted in ascending or descending order"),
2715
- with_issues_enabled: z.coerce
2716
- .boolean()
2719
+ with_issues_enabled: coerceBooleanString
2717
2720
  .optional()
2718
2721
  .describe("Filter projects with issues feature enabled"),
2719
- with_merge_requests_enabled: z.coerce
2720
- .boolean()
2722
+ with_merge_requests_enabled: coerceBooleanString
2721
2723
  .optional()
2722
2724
  .describe("Filter projects with merge requests feature enabled"),
2723
2725
  min_access_level: z.coerce.number().optional().describe("Filter by minimum access level"),
@@ -2728,18 +2730,17 @@ export const ListProjectsSchema = z
2728
2730
  export const ListLabelsSchema = z
2729
2731
  .object({
2730
2732
  project_id: z.coerce.string().describe("Project ID or URL-encoded path"),
2731
- with_counts: z.coerce
2732
- .boolean()
2733
+ with_counts: coerceBooleanString
2733
2734
  .optional()
2734
2735
  .describe("Whether to include issue and merge request counts"),
2735
- include_ancestor_groups: z.coerce.boolean().optional().describe("Include ancestor groups"),
2736
+ include_ancestor_groups: coerceBooleanString.optional().describe("Include ancestor groups"),
2736
2737
  search: z.string().optional().describe("Keyword to filter labels by"),
2737
2738
  })
2738
2739
  .merge(PaginationOptionsSchema);
2739
2740
  export const GetLabelSchema = z.object({
2740
2741
  project_id: z.coerce.string().describe("Project ID or URL-encoded path"),
2741
2742
  label_id: z.coerce.string().describe("The ID or title of a project's label"),
2742
- include_ancestor_groups: z.coerce.boolean().optional().describe("Include ancestor groups"),
2743
+ include_ancestor_groups: coerceBooleanString.optional().describe("Include ancestor groups"),
2743
2744
  });
2744
2745
  export const CreateLabelSchema = z.object({
2745
2746
  project_id: z.coerce.string().describe("Project ID or URL-encoded path"),
@@ -2769,32 +2770,30 @@ export const DeleteLabelSchema = z.object({
2769
2770
  export const ListGroupProjectsSchema = z
2770
2771
  .object({
2771
2772
  group_id: z.coerce.string().describe("Group ID or path"),
2772
- include_subgroups: z.coerce.boolean().optional().describe("Include projects from subgroups"),
2773
+ include_subgroups: coerceBooleanString.optional().describe("Include projects from subgroups"),
2773
2774
  search: z.string().optional().describe("Search term to filter projects"),
2774
2775
  order_by: z
2775
2776
  .enum(["name", "path", "created_at", "updated_at", "last_activity_at"])
2776
2777
  .optional()
2777
2778
  .describe("Field to sort by"),
2778
2779
  sort: z.enum(["asc", "desc"]).optional().describe("Sort direction"),
2779
- archived: z.coerce.boolean().optional().describe("Filter for archived projects"),
2780
+ archived: coerceBooleanString.optional().describe("Filter for archived projects"),
2780
2781
  visibility: z
2781
2782
  .enum(["public", "internal", "private"])
2782
2783
  .optional()
2783
2784
  .describe("Filter by project visibility"),
2784
- with_issues_enabled: z.coerce
2785
- .boolean()
2785
+ with_issues_enabled: coerceBooleanString
2786
2786
  .optional()
2787
2787
  .describe("Filter projects with issues feature enabled"),
2788
- with_merge_requests_enabled: z.coerce
2789
- .boolean()
2788
+ with_merge_requests_enabled: coerceBooleanString
2790
2789
  .optional()
2791
2790
  .describe("Filter projects with merge requests feature enabled"),
2792
2791
  min_access_level: z.coerce.number().optional().describe("Filter by minimum access level"),
2793
2792
  with_programming_language: z.string().optional().describe("Filter by programming language"),
2794
- starred: z.coerce.boolean().optional().describe("Filter by starred projects"),
2795
- statistics: z.coerce.boolean().optional().describe("Include project statistics"),
2796
- with_custom_attributes: z.coerce.boolean().optional().describe("Include custom attributes"),
2797
- 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"),
2798
2797
  topic: z.string().optional().describe("Filter by topic (projects tagged with this topic)"),
2799
2798
  })
2800
2799
  .merge(PaginationOptionsSchema);
@@ -2802,9 +2801,8 @@ export const ListGroupProjectsSchema = z
2802
2801
  export const ListWikiPagesSchema = z
2803
2802
  .object({
2804
2803
  project_id: z.coerce.string().describe("Project ID or URL-encoded path"),
2805
- with_content: z.coerce.boolean().optional().describe("Include content of the wiki pages"),
2806
- render_html: z.coerce
2807
- .boolean()
2804
+ with_content: coerceBooleanString.optional().describe("Include content of the wiki pages"),
2805
+ render_html: coerceBooleanString
2808
2806
  .optional()
2809
2807
  .describe("Return rendered HTML content and include front_matter (e.g., the custom title)"),
2810
2808
  })
@@ -2812,8 +2810,7 @@ export const ListWikiPagesSchema = z
2812
2810
  export const GetWikiPageSchema = z.object({
2813
2811
  project_id: z.coerce.string().describe("Project ID or URL-encoded path"),
2814
2812
  slug: z.string().describe("Slug of the wiki page (will be URL-encoded internally)"),
2815
- render_html: z.coerce
2816
- .boolean()
2813
+ render_html: coerceBooleanString
2817
2814
  .optional()
2818
2815
  .describe("Return rendered HTML content and include front_matter (e.g., the custom title)"),
2819
2816
  });
@@ -2851,9 +2848,8 @@ export const GitLabWikiPageSchema = z.object({
2851
2848
  export const ListGroupWikiPagesSchema = z
2852
2849
  .object({
2853
2850
  group_id: z.coerce.string().describe("Group ID or URL-encoded path"),
2854
- with_content: z.coerce.boolean().optional().describe("Include content of the wiki pages"),
2855
- render_html: z.coerce
2856
- .boolean()
2851
+ with_content: coerceBooleanString.optional().describe("Include content of the wiki pages"),
2852
+ render_html: coerceBooleanString
2857
2853
  .optional()
2858
2854
  .describe("Return rendered HTML content and include front_matter (e.g., the custom title)"),
2859
2855
  })
@@ -2861,8 +2857,7 @@ export const ListGroupWikiPagesSchema = z
2861
2857
  export const GetGroupWikiPageSchema = z.object({
2862
2858
  group_id: z.coerce.string().describe("Group ID or URL-encoded path"),
2863
2859
  slug: z.string().describe("Slug of the wiki page (will be URL-encoded internally)"),
2864
- render_html: z.coerce
2865
- .boolean()
2860
+ render_html: coerceBooleanString
2866
2861
  .optional()
2867
2862
  .describe("Return rendered HTML content and include front_matter (e.g., the custom title)"),
2868
2863
  });
@@ -3048,8 +3043,7 @@ export const CreateDraftNoteSchema = ProjectParamsSchema.extend({
3048
3043
  .optional()
3049
3044
  .describe("The ID of a discussion the draft note replies to"),
3050
3045
  position: optionalMergeRequestThreadPosition.describe("Position when creating a diff note"),
3051
- resolve_discussion: z.coerce
3052
- .boolean()
3046
+ resolve_discussion: coerceBooleanString
3053
3047
  .optional()
3054
3048
  .describe("Whether to resolve the discussion when publishing"),
3055
3049
  });
@@ -3059,8 +3053,7 @@ export const UpdateDraftNoteSchema = ProjectParamsSchema.extend({
3059
3053
  draft_note_id: z.coerce.string().describe("The ID of the draft note"),
3060
3054
  body: z.string().optional().describe("The content of the draft note"),
3061
3055
  position: optionalMergeRequestThreadPosition.describe("Position when creating a diff note"),
3062
- resolve_discussion: z.coerce
3063
- .boolean()
3056
+ resolve_discussion: coerceBooleanString
3064
3057
  .optional()
3065
3058
  .describe("Whether to resolve the discussion when publishing"),
3066
3059
  });
@@ -3085,8 +3078,7 @@ export const BulkPublishDraftNotesSchema = ProjectParamsSchema.extend({
3085
3078
  .string()
3086
3079
  .optional()
3087
3080
  .describe("Summary note body to post on the merge request (GitLab 19.2+)"),
3088
- internal: z.coerce
3089
- .boolean()
3081
+ internal: coerceBooleanString
3090
3082
  .optional()
3091
3083
  .describe("If true, the summary note is internal (GitLab 19.2+, default false)"),
3092
3084
  });
@@ -3100,7 +3092,7 @@ export const CreateMergeRequestThreadSchema = ProjectParamsSchema.extend({
3100
3092
  export const ResolveMergeRequestThreadSchema = ProjectParamsSchema.extend({
3101
3093
  merge_request_iid: z.coerce.string().describe("The IID of a merge request"),
3102
3094
  discussion_id: z.coerce.string().describe("The ID of a thread"),
3103
- resolved: z.coerce.boolean().describe("Whether to resolve the thread"),
3095
+ resolved: coerceBooleanString.describe("Whether to resolve the thread"),
3104
3096
  });
3105
3097
  // Milestone related schemas
3106
3098
  // Schema for listing project milestones
@@ -3121,7 +3113,7 @@ export const ListProjectMilestonesSchema = ProjectParamsSchema.extend({
3121
3113
  .string()
3122
3114
  .optional()
3123
3115
  .describe("Return only milestones with a title or description matching the provided string"),
3124
- include_ancestors: z.coerce.boolean().optional().describe("Include ancestor groups"),
3116
+ include_ancestors: coerceBooleanString.optional().describe("Include ancestor groups"),
3125
3117
  updated_before: z
3126
3118
  .string()
3127
3119
  .optional()
@@ -3183,8 +3175,8 @@ export const ListGroupMilestonesSchema = z
3183
3175
  .string()
3184
3176
  .optional()
3185
3177
  .describe("Return only milestones with a title or description matching the provided string"),
3186
- include_ancestors: z.coerce.boolean().optional().describe("Include ancestor groups"),
3187
- 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"),
3188
3180
  updated_before: z
3189
3181
  .string()
3190
3182
  .optional()
@@ -3237,18 +3229,15 @@ export const ListCommitsSchema = z.object({
3237
3229
  .describe("Only commits before or on this date are returned in ISO 8601 format YYYY-MM-DDTHH:MM:SSZ"),
3238
3230
  path: z.string().optional().describe("The file path"),
3239
3231
  author: z.string().optional().describe("Search commits by commit author"),
3240
- all: z.coerce.boolean().optional().describe("Retrieve every commit from the repository"),
3241
- with_stats: z.coerce
3242
- .boolean()
3232
+ all: coerceBooleanString.optional().describe("Retrieve every commit from the repository"),
3233
+ with_stats: coerceBooleanString
3243
3234
  .optional()
3244
3235
  .describe("Stats about each commit are added to the response"),
3245
- first_parent: z.coerce
3246
- .boolean()
3236
+ first_parent: coerceBooleanString
3247
3237
  .optional()
3248
3238
  .describe("Follow only the first parent commit upon seeing a merge commit"),
3249
3239
  order: z.enum(["default", "topo"]).optional().describe("List commits in order"),
3250
- trailers: z.coerce
3251
- .boolean()
3240
+ trailers: coerceBooleanString
3252
3241
  .optional()
3253
3242
  .describe("Parse and include Git trailers for every commit"),
3254
3243
  page: z.coerce.number().optional().describe("Page number for pagination (default: 1)"),
@@ -3260,13 +3249,12 @@ export const ListCommitsSchema = z.object({
3260
3249
  export const GetCommitSchema = z.object({
3261
3250
  project_id: z.coerce.string().describe("Project ID or complete URL-encoded path to project"),
3262
3251
  sha: z.string().describe("The commit hash or name of a repository branch or tag"),
3263
- stats: z.coerce.boolean().optional().describe("Include commit stats"),
3252
+ stats: coerceBooleanString.optional().describe("Include commit stats"),
3264
3253
  });
3265
3254
  export const GetCommitDiffSchema = z.object({
3266
3255
  project_id: z.coerce.string().describe("Project ID or complete URL-encoded path to project"),
3267
3256
  sha: z.string().describe("The commit hash or name of a repository branch or tag"),
3268
- full_diff: z.coerce
3269
- .boolean()
3257
+ full_diff: coerceBooleanString
3270
3258
  .optional()
3271
3259
  .describe("Whether to return the full diff or only first page (default: false)"),
3272
3260
  });
@@ -3386,8 +3374,7 @@ export const ListProjectMembersSchema = z.object({
3386
3374
  query: z.string().optional().describe("Search for members by name or username"),
3387
3375
  user_ids: z.array(z.coerce.number()).optional().describe("Filter by user IDs"),
3388
3376
  skip_users: z.array(z.coerce.number()).optional().describe("User IDs to exclude"),
3389
- include_inheritance: z.coerce
3390
- .boolean()
3377
+ include_inheritance: coerceBooleanString
3391
3378
  .optional()
3392
3379
  .describe("Include inherited members. Defaults to false."),
3393
3380
  per_page: z.coerce
@@ -3402,8 +3389,7 @@ export const ListGroupMembersSchema = z.object({
3402
3389
  query: z.string().optional().describe("Search for members by name or username"),
3403
3390
  user_ids: z.array(z.coerce.number()).optional().describe("Filter by user IDs"),
3404
3391
  skip_users: z.array(z.coerce.number()).optional().describe("User IDs to exclude"),
3405
- include_inheritance: z.coerce
3406
- .boolean()
3392
+ include_inheritance: coerceBooleanString
3407
3393
  .optional()
3408
3394
  .describe("Include inherited members. Defaults to false."),
3409
3395
  per_page: z.coerce
@@ -3450,7 +3436,7 @@ export const DownloadAttachmentSchema = z.object({
3450
3436
  local_path: z
3451
3437
  .string()
3452
3438
  .optional()
3453
- .describe("Local path to save the file (optional, defaults to current directory)"),
3439
+ .describe("Subdirectory of the download directory to save the file in (optional, defaults to the download directory itself). Names starting with a dot are rejected"),
3454
3440
  });
3455
3441
  export const DownloadAttachmentRemoteSchema = z.object({
3456
3442
  project_id: z.string().describe("Project ID or URL-encoded path of the project"),
@@ -3486,12 +3472,10 @@ export const ListGroupIterationsSchema = z
3486
3472
  .array(z.enum(["title", "cadence_title"]))
3487
3473
  .optional()
3488
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]."),
3489
- include_ancestors: z.coerce
3490
- .boolean()
3475
+ include_ancestors: coerceBooleanString
3491
3476
  .optional()
3492
3477
  .describe("Include iterations for group and its ancestors. Defaults to true."),
3493
- include_descendants: z.coerce
3494
- .boolean()
3478
+ include_descendants: coerceBooleanString
3495
3479
  .optional()
3496
3480
  .describe("Include iterations for group and its descendants. Defaults to false."),
3497
3481
  updated_before: z
@@ -3692,8 +3676,7 @@ export const ListReleasesSchema = z
3692
3676
  .enum(["desc", "asc"])
3693
3677
  .optional()
3694
3678
  .describe("The direction of the order. Either desc (default) for descending order or asc for ascending order."),
3695
- include_html_description: z.coerce
3696
- .boolean()
3679
+ include_html_description: coerceBooleanString
3697
3680
  .optional()
3698
3681
  .describe("If true, a response includes HTML rendered Markdown of the release description."),
3699
3682
  })
@@ -3701,8 +3684,7 @@ export const ListReleasesSchema = z
3701
3684
  export const GetReleaseSchema = z.object({
3702
3685
  project_id: z.coerce.string().describe("Project ID or URL-encoded path"),
3703
3686
  tag_name: z.string().describe("The Git tag the release is associated with"),
3704
- include_html_description: z.coerce
3705
- .boolean()
3687
+ include_html_description: coerceBooleanString
3706
3688
  .optional()
3707
3689
  .describe("If true, a response includes HTML rendered Markdown of the release description."),
3708
3690
  });
@@ -3784,7 +3766,7 @@ export const ListJobArtifactsSchema = z.object({
3784
3766
  .string()
3785
3767
  .optional()
3786
3768
  .describe("Directory path within the artifacts archive (defaults to root)"),
3787
- recursive: z.coerce.boolean().optional().describe("Whether to list artifacts recursively"),
3769
+ recursive: coerceBooleanString.optional().describe("Whether to list artifacts recursively"),
3788
3770
  });
3789
3771
  export const GitLabArtifactEntrySchema = z.object({
3790
3772
  name: z.string(),
@@ -4220,7 +4202,7 @@ export const CreateWorkItemSchema = z.object({
4220
4202
  .string()
4221
4203
  .optional()
4222
4204
  .describe("Iteration ID (e.g. 'gid://gitlab/Iteration/123' or numeric ID). Use list_group_iterations to find available iterations."),
4223
- confidential: z.coerce.boolean().optional().describe("Set confidentiality"),
4205
+ confidential: coerceBooleanString.optional().describe("Set confidentiality"),
4224
4206
  });
4225
4207
  export const UpdateWorkItemSchema = WorkItemParamsSchema.extend({
4226
4208
  title: z.string().optional().describe("New title"),
@@ -4244,8 +4226,7 @@ export const UpdateWorkItemSchema = WorkItemParamsSchema.extend({
4244
4226
  .string()
4245
4227
  .optional()
4246
4228
  .describe("Project ID or path of the parent work item (defaults to same project as the work item)"),
4247
- remove_parent: z.coerce
4248
- .boolean()
4229
+ remove_parent: coerceBooleanString
4249
4230
  .optional()
4250
4231
  .describe("Set to true to remove the parent from hierarchy"),
4251
4232
  children_to_add: z
@@ -4282,7 +4263,7 @@ export const UpdateWorkItemSchema = WorkItemParamsSchema.extend({
4282
4263
  .string()
4283
4264
  .optional()
4284
4265
  .describe("Iteration ID (e.g. 'gid://gitlab/Iteration/123' or numeric ID). Use list_group_iterations to find available iterations."),
4285
- confidential: z.coerce.boolean().optional().describe("Set confidentiality"),
4266
+ confidential: coerceBooleanString.optional().describe("Set confidentiality"),
4286
4267
  linked_items_to_add: z
4287
4268
  .array(z.object({
4288
4269
  project_id: z.coerce
@@ -4366,10 +4347,7 @@ export const CreateWorkItemNoteSchema = z.object({
4366
4347
  project_id: NamespaceIdOrPathSchema,
4367
4348
  iid: z.coerce.number().describe("The internal ID of the work item"),
4368
4349
  body: z.string().describe("Note body (Markdown supported)"),
4369
- internal: z.coerce
4370
- .boolean()
4371
- .optional()
4372
- .default(false)
4350
+ internal: coerceBooleanStringDefault(false)
4373
4351
  .describe("Create as internal/confidential note (only visible to project members)"),
4374
4352
  discussion_id: z
4375
4353
  .string()
@@ -4556,8 +4534,7 @@ export const ListWebhookEventsSchema = z
4556
4534
  .union([z.coerce.number(), z.string()])
4557
4535
  .optional()
4558
4536
  .describe("Filter by response status code (e.g. 200, 500) or category: successful, client_failure, server_failure"),
4559
- summary: z.coerce
4560
- .boolean()
4537
+ summary: coerceBooleanString
4561
4538
  .optional()
4562
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."),
4563
4540
  per_page: z.number().max(20).optional().default(20).describe("Number of events per page"),