gitlab-mcp 1.3.0 → 1.4.0

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.
@@ -1,24 +1,31 @@
1
1
  import { Kind, parse } from "graphql";
2
2
  import { z } from "zod";
3
3
  import { GitLabApiError } from "../lib/gitlab-client.js";
4
+ import { bodySchema, displayNameSchema, nullableOptional, optionalBodySchema, optionalDisplayNameSchema, optionalProjectIdSchema, optionalRefLikeSchema, optionalUrlOrPathSchema, projectIdSchema, refLikeSchema, slugSchema } from "../lib/tool-schema.js";
4
5
  import { getSessionAuth } from "../lib/auth-context.js";
5
6
  import { stripNullsDeep } from "../lib/sanitize.js";
6
7
  import { getMergeRequestCodeContext, mergeRequestCodeContextSchema } from "./mr-code-context.js";
7
- const optionalString = z.preprocess((value) => (value === null ? undefined : value), z.string().optional());
8
- const optionalNumber = z.preprocess((value) => (value === null ? undefined : value), z.number().optional());
9
- const optionalBoolean = z.preprocess((value) => (value === null ? undefined : value), z.boolean().optional());
10
- const optionalStringArray = z.preprocess((value) => (value === null ? undefined : value), z.array(z.string()).optional());
11
- const optionalNumberArray = z.preprocess((value) => (value === null ? undefined : value), z.array(z.number()).optional());
12
- const optionalStringOrNumber = z.preprocess((value) => (value === null ? undefined : value), z.union([z.string(), z.number()]).optional());
13
- const optionalStringOrStringArray = z.preprocess((value) => (value === null ? undefined : value), z.union([z.string(), z.array(z.string())]).optional());
14
- const optionalRecord = z.preprocess((value) => (value === null ? undefined : value), z.record(z.string(), z.unknown()).optional());
8
+ const readCapabilities = ["read"];
9
+ const writeCapabilities = ["write"];
10
+ const deleteCapabilities = ["delete"];
11
+ const adminCapabilities = ["admin"];
12
+ const readGraphqlCapabilities = ["read", "graphql"];
13
+ const writeGraphqlCapabilities = ["write", "graphql"];
14
+ const optionalString = nullableOptional(z.string());
15
+ const optionalNumber = nullableOptional(z.number());
16
+ const optionalBoolean = nullableOptional(z.boolean());
17
+ const optionalStringArray = nullableOptional(z.array(z.string()));
18
+ const optionalNumberArray = nullableOptional(z.array(z.number()));
19
+ const optionalStringOrNumber = nullableOptional(z.union([z.string(), z.number()]));
20
+ const optionalStringOrStringArray = nullableOptional(z.union([z.string(), z.array(z.string())]));
21
+ const optionalRecord = nullableOptional(z.record(z.string(), z.unknown()));
15
22
  const pipelineInputValueSchema = z.union([
16
23
  z.string(),
17
24
  z.number(),
18
25
  z.boolean(),
19
26
  z.array(z.union([z.string(), z.number(), z.boolean()]))
20
27
  ]);
21
- const optionalPipelineInputsRecord = z.preprocess((value) => (value === null ? undefined : value), z.record(z.string(), pipelineInputValueSchema).optional());
28
+ const optionalPipelineInputsRecord = nullableOptional(z.record(z.string(), pipelineInputValueSchema));
22
29
  const paginationShape = {
23
30
  page: optionalNumber,
24
31
  per_page: optionalNumber
@@ -28,7 +35,7 @@ export function registerGitLabTools(server, context) {
28
35
  const disableGraphqlTools = shouldDisableGraphqlTools(context.env.GITLAB_ALLOWED_PROJECT_IDS, context.env.GITLAB_ALLOW_GRAPHQL_WITH_PROJECT_SCOPE);
29
36
  const filtered = context.policy.filterTools(definitions.map((item) => ({
30
37
  name: item.name,
31
- mutating: item.mutating,
38
+ capabilities: item.capabilities,
32
39
  requiresFeature: item.requiresFeature
33
40
  })));
34
41
  const enabledNames = new Set(filtered.map((item) => item.name));
@@ -50,7 +57,7 @@ export function registerGitLabTools(server, context) {
50
57
  try {
51
58
  context.policy.assertCanExecute({
52
59
  name: definition.name,
53
- mutating: definition.mutating,
60
+ capabilities: definition.capabilities,
54
61
  requiresFeature: definition.requiresFeature
55
62
  });
56
63
  if (definition.requiresAuth ?? true) {
@@ -90,9 +97,9 @@ function getGitLabToolDefinitions() {
90
97
  name: "gitlab_get_project",
91
98
  title: "Get Project",
92
99
  description: "Get project details by ID or path.",
93
- mutating: false,
100
+ capabilities: readCapabilities,
94
101
  inputSchema: {
95
- project_id: z.string().optional()
102
+ project_id: optionalProjectIdSchema
96
103
  },
97
104
  handler: async (args, context) => {
98
105
  const projectId = resolveProjectId(args, context, true);
@@ -103,7 +110,7 @@ function getGitLabToolDefinitions() {
103
110
  name: "gitlab_list_projects",
104
111
  title: "List Projects",
105
112
  description: "List projects available to the current user.",
106
- mutating: false,
113
+ capabilities: readCapabilities,
107
114
  inputSchema: {
108
115
  search: optionalString,
109
116
  search_namespaces: optionalBoolean,
@@ -127,15 +134,15 @@ function getGitLabToolDefinitions() {
127
134
  name: "gitlab_create_repository",
128
135
  title: "Create Repository",
129
136
  description: "Create a new GitLab project/repository.",
130
- mutating: true,
137
+ capabilities: adminCapabilities,
131
138
  inputSchema: {
132
- name: optionalString,
139
+ name: displayNameSchema,
133
140
  description: optionalString,
134
141
  visibility: z.enum(["private", "internal", "public"]).optional(),
135
142
  initialize_with_readme: optionalBoolean,
136
143
  path: optionalString,
137
- namespace_id: optionalString,
138
- default_branch: optionalString
144
+ namespace_id: optionalProjectIdSchema,
145
+ default_branch: optionalRefLikeSchema
139
146
  },
140
147
  handler: async (args, context) => context.gitlab.createRepository({
141
148
  name: getString(args, "name"),
@@ -151,9 +158,9 @@ function getGitLabToolDefinitions() {
151
158
  name: "gitlab_list_project_members",
152
159
  title: "List Project Members",
153
160
  description: "List members of a project.",
154
- mutating: false,
161
+ capabilities: readCapabilities,
155
162
  inputSchema: {
156
- project_id: z.string().optional(),
163
+ project_id: optionalProjectIdSchema,
157
164
  query: optionalString,
158
165
  user_ids: optionalNumberArray,
159
166
  skip_users: optionalNumberArray,
@@ -171,7 +178,7 @@ function getGitLabToolDefinitions() {
171
178
  name: "gitlab_list_group_projects",
172
179
  title: "List Group Projects",
173
180
  description: "List projects under a group.",
174
- mutating: false,
181
+ capabilities: readCapabilities,
175
182
  inputSchema: {
176
183
  group_id: z.string(),
177
184
  include_subgroups: optionalBoolean,
@@ -202,7 +209,7 @@ function getGitLabToolDefinitions() {
202
209
  name: "gitlab_list_group_iterations",
203
210
  title: "List Group Iterations",
204
211
  description: "List iterations for a group.",
205
- mutating: false,
212
+ capabilities: readCapabilities,
206
213
  inputSchema: {
207
214
  group_id: z.string().min(1),
208
215
  state: optionalString,
@@ -228,7 +235,7 @@ function getGitLabToolDefinitions() {
228
235
  name: "gitlab_search_repositories",
229
236
  title: "Search Repositories",
230
237
  description: "Search repositories by keyword.",
231
- mutating: false,
238
+ capabilities: readCapabilities,
232
239
  inputSchema: {
233
240
  search: z.string().min(1),
234
241
  ...paginationShape
@@ -241,11 +248,11 @@ function getGitLabToolDefinitions() {
241
248
  name: "gitlab_search_code_blobs",
242
249
  title: "Search Code Blobs",
243
250
  description: "Search repository code blobs in a specific project.",
244
- mutating: false,
251
+ capabilities: readCapabilities,
245
252
  inputSchema: {
246
- project_id: z.string().optional(),
253
+ project_id: optionalProjectIdSchema,
247
254
  search: z.string().min(1),
248
- ref: optionalString,
255
+ ref: optionalRefLikeSchema,
249
256
  ...paginationShape
250
257
  },
251
258
  handler: async (args, context) => context.gitlab.searchCodeBlobs(resolveProjectId(args, context, true), getString(args, "search"), { query: toQuery(omit(args, ["project_id", "search"])) })
@@ -254,11 +261,11 @@ function getGitLabToolDefinitions() {
254
261
  name: "gitlab_get_repository_tree",
255
262
  title: "Get Repository Tree",
256
263
  description: "List files and directories in a repository tree.",
257
- mutating: false,
264
+ capabilities: readCapabilities,
258
265
  inputSchema: {
259
- project_id: z.string().optional(),
266
+ project_id: optionalProjectIdSchema,
260
267
  path: optionalString,
261
- ref: optionalString,
268
+ ref: optionalRefLikeSchema,
262
269
  recursive: optionalBoolean,
263
270
  ...paginationShape
264
271
  },
@@ -273,11 +280,11 @@ function getGitLabToolDefinitions() {
273
280
  name: "gitlab_get_file_contents",
274
281
  title: "Get File Contents",
275
282
  description: "Get a file in repository by path and ref.",
276
- mutating: false,
283
+ capabilities: readCapabilities,
277
284
  inputSchema: {
278
- project_id: z.string().optional(),
285
+ project_id: optionalProjectIdSchema,
279
286
  file_path: z.string().min(1),
280
- ref: optionalString
287
+ ref: optionalRefLikeSchema
281
288
  },
282
289
  handler: async (args, context) => {
283
290
  const projectId = resolveProjectId(args, context, true);
@@ -293,11 +300,11 @@ function getGitLabToolDefinitions() {
293
300
  name: "gitlab_create_or_update_file",
294
301
  title: "Create Or Update File",
295
302
  description: "Create or update one file in repository.",
296
- mutating: true,
303
+ capabilities: writeCapabilities,
297
304
  inputSchema: {
298
- project_id: z.string().optional(),
305
+ project_id: optionalProjectIdSchema,
299
306
  file_path: z.string().min(1),
300
- branch: z.string().min(1),
307
+ branch: refLikeSchema,
301
308
  content: z.string(),
302
309
  commit_message: z.string().min(1),
303
310
  previous_path: optionalString,
@@ -328,10 +335,10 @@ function getGitLabToolDefinitions() {
328
335
  name: "gitlab_push_files",
329
336
  title: "Push Files",
330
337
  description: "Create a commit with multiple file actions.",
331
- mutating: true,
338
+ capabilities: writeCapabilities,
332
339
  inputSchema: {
333
- project_id: z.string().optional(),
334
- branch: z.string().min(1),
340
+ project_id: optionalProjectIdSchema,
341
+ branch: refLikeSchema,
335
342
  commit_message: z.string().min(1),
336
343
  actions: z
337
344
  .array(z.object({
@@ -391,11 +398,11 @@ function getGitLabToolDefinitions() {
391
398
  name: "gitlab_create_branch",
392
399
  title: "Create Branch",
393
400
  description: "Create a new branch from an existing ref.",
394
- mutating: true,
401
+ capabilities: writeCapabilities,
395
402
  inputSchema: {
396
- project_id: z.string().optional(),
397
- branch: z.string().min(1),
398
- ref: optionalString
403
+ project_id: optionalProjectIdSchema,
404
+ branch: refLikeSchema,
405
+ ref: optionalRefLikeSchema
399
406
  },
400
407
  handler: async (args, context) => {
401
408
  const projectId = resolveProjectId(args, context, true);
@@ -414,11 +421,11 @@ function getGitLabToolDefinitions() {
414
421
  name: "gitlab_get_branch_diffs",
415
422
  title: "Get Branch Diffs",
416
423
  description: "Compare two branches/refs and return diffs.",
417
- mutating: false,
424
+ capabilities: readCapabilities,
418
425
  inputSchema: {
419
- project_id: z.string().optional(),
420
- from: z.string().min(1),
421
- to: z.string().min(1),
426
+ project_id: optionalProjectIdSchema,
427
+ from: refLikeSchema,
428
+ to: refLikeSchema,
422
429
  straight: optionalBoolean,
423
430
  excluded_file_patterns: optionalStringArray
424
431
  },
@@ -438,10 +445,10 @@ function getGitLabToolDefinitions() {
438
445
  name: "gitlab_list_commits",
439
446
  title: "List Commits",
440
447
  description: "List commits in a project.",
441
- mutating: false,
448
+ capabilities: readCapabilities,
442
449
  inputSchema: {
443
- project_id: z.string().optional(),
444
- ref_name: optionalString,
450
+ project_id: optionalProjectIdSchema,
451
+ ref_name: optionalRefLikeSchema,
445
452
  since: optionalString,
446
453
  until: optionalString,
447
454
  path: optionalString,
@@ -464,9 +471,9 @@ function getGitLabToolDefinitions() {
464
471
  name: "gitlab_get_commit",
465
472
  title: "Get Commit",
466
473
  description: "Get one commit by SHA.",
467
- mutating: false,
474
+ capabilities: readCapabilities,
468
475
  inputSchema: {
469
- project_id: z.string().optional(),
476
+ project_id: optionalProjectIdSchema,
470
477
  sha: z.string().min(1),
471
478
  stats: optionalBoolean
472
479
  },
@@ -481,9 +488,9 @@ function getGitLabToolDefinitions() {
481
488
  name: "gitlab_get_commit_diff",
482
489
  title: "Get Commit Diff",
483
490
  description: "Get diff for one commit.",
484
- mutating: false,
491
+ capabilities: readCapabilities,
485
492
  inputSchema: {
486
- project_id: z.string().optional(),
493
+ project_id: optionalProjectIdSchema,
487
494
  sha: z.string().min(1),
488
495
  full_diff: optionalBoolean,
489
496
  ...paginationShape
@@ -499,9 +506,9 @@ function getGitLabToolDefinitions() {
499
506
  name: "gitlab_list_merge_requests",
500
507
  title: "List Merge Requests",
501
508
  description: "List merge requests for a project.",
502
- mutating: false,
509
+ capabilities: readCapabilities,
503
510
  inputSchema: {
504
- project_id: z.string().optional(),
511
+ project_id: optionalProjectIdSchema,
505
512
  assignee_id: optionalStringOrNumber,
506
513
  assignee_username: optionalString,
507
514
  author_id: optionalStringOrNumber,
@@ -527,8 +534,8 @@ function getGitLabToolDefinitions() {
527
534
  ])
528
535
  .optional(),
529
536
  sort: z.enum(["asc", "desc"]).optional(),
530
- source_branch: optionalString,
531
- target_branch: optionalString,
537
+ source_branch: optionalRefLikeSchema,
538
+ target_branch: optionalRefLikeSchema,
532
539
  search: optionalString,
533
540
  wip: z.enum(["yes", "no"]).optional(),
534
541
  with_labels_details: optionalBoolean,
@@ -547,11 +554,11 @@ function getGitLabToolDefinitions() {
547
554
  name: "gitlab_get_merge_request",
548
555
  title: "Get Merge Request",
549
556
  description: "Get one merge request.",
550
- mutating: false,
557
+ capabilities: readCapabilities,
551
558
  inputSchema: {
552
- project_id: z.string().optional(),
559
+ project_id: optionalProjectIdSchema,
553
560
  merge_request_iid: optionalString,
554
- source_branch: optionalString
561
+ source_branch: optionalRefLikeSchema
555
562
  },
556
563
  handler: async (args, context) => {
557
564
  const projectId = resolveProjectId(args, context, true);
@@ -580,14 +587,14 @@ function getGitLabToolDefinitions() {
580
587
  name: "gitlab_create_merge_request",
581
588
  title: "Create Merge Request",
582
589
  description: "Create a merge request.",
583
- mutating: true,
590
+ capabilities: writeCapabilities,
584
591
  inputSchema: {
585
- project_id: z.string().optional(),
586
- source_branch: z.string().min(1),
587
- target_branch: z.string().min(1),
592
+ project_id: optionalProjectIdSchema,
593
+ source_branch: refLikeSchema,
594
+ target_branch: refLikeSchema,
588
595
  title: z.string().min(1),
589
596
  description: optionalString,
590
- target_project_id: optionalString,
597
+ target_project_id: optionalProjectIdSchema,
591
598
  assignee_ids: optionalNumberArray,
592
599
  reviewer_ids: optionalNumberArray,
593
600
  labels: optionalStringOrStringArray,
@@ -618,16 +625,16 @@ function getGitLabToolDefinitions() {
618
625
  name: "gitlab_fork_repository",
619
626
  title: "Fork Repository",
620
627
  description: "Fork an existing project to another namespace.",
621
- mutating: true,
628
+ capabilities: adminCapabilities,
622
629
  inputSchema: {
623
- project_id: z.string().optional(),
630
+ project_id: optionalProjectIdSchema,
624
631
  namespace: optionalString,
625
- namespace_id: optionalString,
632
+ namespace_id: optionalProjectIdSchema,
626
633
  path: optionalString,
627
- name: optionalString,
634
+ name: optionalDisplayNameSchema,
628
635
  description: optionalString,
629
636
  visibility: z.enum(["private", "internal", "public"]).optional(),
630
- default_branch: optionalString
637
+ default_branch: optionalRefLikeSchema
631
638
  },
632
639
  handler: async (args, context) => context.gitlab.forkRepository(resolveProjectId(args, context, true), {
633
640
  namespace: getOptionalString(args, "namespace"),
@@ -643,14 +650,14 @@ function getGitLabToolDefinitions() {
643
650
  name: "gitlab_update_merge_request",
644
651
  title: "Update Merge Request",
645
652
  description: "Update merge request fields.",
646
- mutating: true,
653
+ capabilities: writeCapabilities,
647
654
  inputSchema: {
648
- project_id: z.string().optional(),
655
+ project_id: optionalProjectIdSchema,
649
656
  merge_request_iid: z.string().min(1),
650
- source_branch: optionalString,
657
+ source_branch: optionalRefLikeSchema,
651
658
  title: optionalString,
652
659
  description: optionalString,
653
- target_branch: optionalString,
660
+ target_branch: optionalRefLikeSchema,
654
661
  assignee_ids: optionalNumberArray,
655
662
  reviewer_ids: optionalNumberArray,
656
663
  reviewers: optionalStringArray,
@@ -682,11 +689,11 @@ function getGitLabToolDefinitions() {
682
689
  name: "gitlab_merge_merge_request",
683
690
  title: "Merge Merge Request",
684
691
  description: "Merge an existing merge request.",
685
- mutating: true,
692
+ capabilities: writeCapabilities,
686
693
  inputSchema: {
687
- project_id: z.string().optional(),
694
+ project_id: optionalProjectIdSchema,
688
695
  merge_request_iid: optionalString,
689
- source_branch: optionalString,
696
+ source_branch: optionalRefLikeSchema,
690
697
  auto_merge: optionalBoolean,
691
698
  merge_when_pipeline_succeeds: optionalBoolean,
692
699
  merge_commit_message: optionalString,
@@ -723,9 +730,9 @@ function getGitLabToolDefinitions() {
723
730
  name: "gitlab_get_merge_request_diffs",
724
731
  title: "Get Merge Request Diffs",
725
732
  description: "Get MR diffs with changed files.",
726
- mutating: false,
733
+ capabilities: readCapabilities,
727
734
  inputSchema: {
728
- project_id: z.string().optional(),
735
+ project_id: optionalProjectIdSchema,
729
736
  merge_request_iid: z.string().min(1),
730
737
  view: z.enum(["inline", "parallel"]).optional(),
731
738
  excluded_file_patterns: optionalStringArray
@@ -736,9 +743,9 @@ function getGitLabToolDefinitions() {
736
743
  name: "gitlab_list_merge_request_diffs",
737
744
  title: "List Merge Request Diffs",
738
745
  description: "List detailed MR diffs (versions/changes view).",
739
- mutating: false,
746
+ capabilities: readCapabilities,
740
747
  inputSchema: {
741
- project_id: z.string().optional(),
748
+ project_id: optionalProjectIdSchema,
742
749
  merge_request_iid: z.string().min(1),
743
750
  page: optionalNumber,
744
751
  per_page: optionalNumber,
@@ -750,7 +757,7 @@ function getGitLabToolDefinitions() {
750
757
  name: "gitlab_get_merge_request_code_context",
751
758
  title: "Get Merge Request Code Context",
752
759
  description: "High-signal MR code context with include/exclude filters, sorting, and token-budgeted output.",
753
- mutating: false,
760
+ capabilities: readCapabilities,
754
761
  inputSchema: mergeRequestCodeContextSchema,
755
762
  handler: async (args, context) => getMergeRequestCodeContext({
756
763
  projectId: resolveProjectId(args, context, true),
@@ -771,9 +778,9 @@ function getGitLabToolDefinitions() {
771
778
  name: "gitlab_list_merge_request_versions",
772
779
  title: "List Merge Request Versions",
773
780
  description: "List MR diff versions.",
774
- mutating: false,
781
+ capabilities: readCapabilities,
775
782
  inputSchema: {
776
- project_id: z.string().optional(),
783
+ project_id: optionalProjectIdSchema,
777
784
  merge_request_iid: z.string().min(1)
778
785
  },
779
786
  handler: async (args, context) => context.gitlab.listMergeRequestVersions(resolveProjectId(args, context, true), getString(args, "merge_request_iid"))
@@ -782,9 +789,9 @@ function getGitLabToolDefinitions() {
782
789
  name: "gitlab_get_merge_request_version",
783
790
  title: "Get Merge Request Version",
784
791
  description: "Get one MR diff version.",
785
- mutating: false,
792
+ capabilities: readCapabilities,
786
793
  inputSchema: {
787
- project_id: z.string().optional(),
794
+ project_id: optionalProjectIdSchema,
788
795
  merge_request_iid: z.string().min(1),
789
796
  version_id: z.string().min(1),
790
797
  unidiff: optionalBoolean
@@ -795,9 +802,9 @@ function getGitLabToolDefinitions() {
795
802
  name: "gitlab_approve_merge_request",
796
803
  title: "Approve Merge Request",
797
804
  description: "Approve a merge request.",
798
- mutating: true,
805
+ capabilities: writeCapabilities,
799
806
  inputSchema: {
800
- project_id: z.string().optional(),
807
+ project_id: optionalProjectIdSchema,
801
808
  merge_request_iid: z.string().min(1),
802
809
  sha: optionalString,
803
810
  approval_password: optionalString
@@ -808,9 +815,9 @@ function getGitLabToolDefinitions() {
808
815
  name: "gitlab_unapprove_merge_request",
809
816
  title: "Unapprove Merge Request",
810
817
  description: "Remove current user approval from MR.",
811
- mutating: true,
818
+ capabilities: writeCapabilities,
812
819
  inputSchema: {
813
- project_id: z.string().optional(),
820
+ project_id: optionalProjectIdSchema,
814
821
  merge_request_iid: z.string().min(1)
815
822
  },
816
823
  handler: async (args, context) => context.gitlab.unapproveMergeRequest(resolveProjectId(args, context, true), getString(args, "merge_request_iid"))
@@ -819,9 +826,9 @@ function getGitLabToolDefinitions() {
819
826
  name: "gitlab_get_merge_request_approval_state",
820
827
  title: "Get Merge Request Approval State",
821
828
  description: "Get approval state for MR.",
822
- mutating: false,
829
+ capabilities: readCapabilities,
823
830
  inputSchema: {
824
- project_id: z.string().optional(),
831
+ project_id: optionalProjectIdSchema,
825
832
  merge_request_iid: z.string().min(1)
826
833
  },
827
834
  handler: async (args, context) => context.gitlab.getMergeRequestApprovalState(resolveProjectId(args, context, true), getString(args, "merge_request_iid"))
@@ -830,9 +837,9 @@ function getGitLabToolDefinitions() {
830
837
  name: "gitlab_get_merge_request_conflicts",
831
838
  title: "Get Merge Request Conflicts",
832
839
  description: "Get conflict details for MR.",
833
- mutating: false,
840
+ capabilities: readCapabilities,
834
841
  inputSchema: {
835
- project_id: z.string().optional(),
842
+ project_id: optionalProjectIdSchema,
836
843
  merge_request_iid: z.string().min(1)
837
844
  },
838
845
  handler: async (args, context) => context.gitlab.getMergeRequestConflicts(resolveProjectId(args, context, true), getString(args, "merge_request_iid"))
@@ -841,9 +848,9 @@ function getGitLabToolDefinitions() {
841
848
  name: "gitlab_list_merge_request_discussions",
842
849
  title: "List Merge Request Discussions",
843
850
  description: "List MR discussions.",
844
- mutating: false,
851
+ capabilities: readCapabilities,
845
852
  inputSchema: {
846
- project_id: z.string().optional(),
853
+ project_id: optionalProjectIdSchema,
847
854
  merge_request_iid: z.string().min(1),
848
855
  ...paginationShape
849
856
  },
@@ -853,11 +860,11 @@ function getGitLabToolDefinitions() {
853
860
  name: "gitlab_create_merge_request_thread",
854
861
  title: "Create Merge Request Thread",
855
862
  description: "Create a new MR discussion thread (supports diff positions).",
856
- mutating: true,
863
+ capabilities: writeCapabilities,
857
864
  inputSchema: {
858
- project_id: z.string().optional(),
865
+ project_id: optionalProjectIdSchema,
859
866
  merge_request_iid: z.string().min(1),
860
- body: z.string().min(1),
867
+ body: bodySchema,
861
868
  position: optionalRecord,
862
869
  created_at: optionalString
863
870
  },
@@ -871,9 +878,9 @@ function getGitLabToolDefinitions() {
871
878
  name: "gitlab_mr_discussions",
872
879
  title: "Merge Request Discussions (Alias)",
873
880
  description: "Backward-compatible alias of gitlab_list_merge_request_discussions.",
874
- mutating: false,
881
+ capabilities: readCapabilities,
875
882
  inputSchema: {
876
- project_id: z.string().optional(),
883
+ project_id: optionalProjectIdSchema,
877
884
  merge_request_iid: z.string().min(1),
878
885
  ...paginationShape
879
886
  },
@@ -883,12 +890,12 @@ function getGitLabToolDefinitions() {
883
890
  name: "gitlab_create_merge_request_discussion_note",
884
891
  title: "Create MR Discussion Note",
885
892
  description: "Add note to existing MR discussion thread.",
886
- mutating: true,
893
+ capabilities: writeCapabilities,
887
894
  inputSchema: {
888
- project_id: z.string().optional(),
895
+ project_id: optionalProjectIdSchema,
889
896
  merge_request_iid: z.string().min(1),
890
897
  discussion_id: z.string().min(1),
891
- body: z.string().min(1),
898
+ body: bodySchema,
892
899
  created_at: optionalString
893
900
  },
894
901
  handler: async (args, context) => context.gitlab.createMergeRequestDiscussionNote(resolveProjectId(args, context, true), getString(args, "merge_request_iid"), getString(args, "discussion_id"), {
@@ -900,13 +907,13 @@ function getGitLabToolDefinitions() {
900
907
  name: "gitlab_update_merge_request_discussion_note",
901
908
  title: "Update MR Discussion Note",
902
909
  description: "Update note body/resolved state in MR discussion.",
903
- mutating: true,
910
+ capabilities: writeCapabilities,
904
911
  inputSchema: {
905
- project_id: z.string().optional(),
912
+ project_id: optionalProjectIdSchema,
906
913
  merge_request_iid: z.string().min(1),
907
914
  discussion_id: z.string().min(1),
908
915
  note_id: z.string().min(1),
909
- body: optionalString,
916
+ body: optionalBodySchema,
910
917
  resolved: optionalBoolean
911
918
  },
912
919
  handler: async (args, context) => {
@@ -927,10 +934,10 @@ function getGitLabToolDefinitions() {
927
934
  {
928
935
  name: "gitlab_delete_merge_request_discussion_note",
929
936
  title: "Delete MR Discussion Note",
930
- description: "Delete note from MR discussion thread.",
931
- mutating: true,
937
+ description: "Delete an MR discussion note permanently. Irreversible. Requires merge_request_iid, discussion_id, and note_id. Recommended pre-check: gitlab_list_merge_request_discussions.",
938
+ capabilities: deleteCapabilities,
932
939
  inputSchema: {
933
- project_id: z.string().optional(),
940
+ project_id: optionalProjectIdSchema,
934
941
  merge_request_iid: z.string().min(1),
935
942
  discussion_id: z.string().min(1),
936
943
  note_id: z.string().min(1)
@@ -941,9 +948,9 @@ function getGitLabToolDefinitions() {
941
948
  name: "gitlab_resolve_merge_request_thread",
942
949
  title: "Resolve Merge Request Thread",
943
950
  description: "Resolve/unresolve an MR discussion note.",
944
- mutating: true,
951
+ capabilities: writeCapabilities,
945
952
  inputSchema: {
946
- project_id: z.string().optional(),
953
+ project_id: optionalProjectIdSchema,
947
954
  merge_request_iid: z.string().min(1),
948
955
  discussion_id: z.string().min(1),
949
956
  note_id: z.string().min(1),
@@ -955,9 +962,9 @@ function getGitLabToolDefinitions() {
955
962
  name: "gitlab_list_merge_request_notes",
956
963
  title: "List Merge Request Notes",
957
964
  description: "List top-level notes for an MR.",
958
- mutating: false,
965
+ capabilities: readCapabilities,
959
966
  inputSchema: {
960
- project_id: z.string().optional(),
967
+ project_id: optionalProjectIdSchema,
961
968
  merge_request_iid: z.string().min(1),
962
969
  sort: optionalString,
963
970
  order_by: optionalString,
@@ -969,9 +976,9 @@ function getGitLabToolDefinitions() {
969
976
  name: "gitlab_get_merge_request_notes",
970
977
  title: "Get Merge Request Notes (Alias)",
971
978
  description: "Backward-compatible alias of gitlab_list_merge_request_notes.",
972
- mutating: false,
979
+ capabilities: readCapabilities,
973
980
  inputSchema: {
974
- project_id: z.string().optional(),
981
+ project_id: optionalProjectIdSchema,
975
982
  merge_request_iid: z.string().min(1),
976
983
  sort: optionalString,
977
984
  order_by: optionalString,
@@ -983,9 +990,9 @@ function getGitLabToolDefinitions() {
983
990
  name: "gitlab_get_draft_note",
984
991
  title: "Get Draft Note",
985
992
  description: "Get a single merge-request draft note.",
986
- mutating: false,
993
+ capabilities: readCapabilities,
987
994
  inputSchema: {
988
- project_id: z.string().optional(),
995
+ project_id: optionalProjectIdSchema,
989
996
  merge_request_iid: z.string().min(1),
990
997
  draft_note_id: z.string().min(1)
991
998
  },
@@ -995,9 +1002,9 @@ function getGitLabToolDefinitions() {
995
1002
  name: "gitlab_list_draft_notes",
996
1003
  title: "List Draft Notes",
997
1004
  description: "List draft notes on a merge request.",
998
- mutating: false,
1005
+ capabilities: readCapabilities,
999
1006
  inputSchema: {
1000
- project_id: z.string().optional(),
1007
+ project_id: optionalProjectIdSchema,
1001
1008
  merge_request_iid: z.string().min(1)
1002
1009
  },
1003
1010
  handler: async (args, context) => context.gitlab.listDraftNotes(resolveProjectId(args, context, true), getString(args, "merge_request_iid"))
@@ -1006,11 +1013,11 @@ function getGitLabToolDefinitions() {
1006
1013
  name: "gitlab_create_draft_note",
1007
1014
  title: "Create Draft Note",
1008
1015
  description: "Create a merge-request draft note.",
1009
- mutating: true,
1016
+ capabilities: writeCapabilities,
1010
1017
  inputSchema: {
1011
- project_id: z.string().optional(),
1018
+ project_id: optionalProjectIdSchema,
1012
1019
  merge_request_iid: z.string().min(1),
1013
- body: z.string().min(1),
1020
+ body: bodySchema,
1014
1021
  position: optionalRecord,
1015
1022
  resolve_discussion: optionalBoolean
1016
1023
  },
@@ -1024,12 +1031,12 @@ function getGitLabToolDefinitions() {
1024
1031
  name: "gitlab_update_draft_note",
1025
1032
  title: "Update Draft Note",
1026
1033
  description: "Update a merge-request draft note.",
1027
- mutating: true,
1034
+ capabilities: writeCapabilities,
1028
1035
  inputSchema: {
1029
- project_id: z.string().optional(),
1036
+ project_id: optionalProjectIdSchema,
1030
1037
  merge_request_iid: z.string().min(1),
1031
1038
  draft_note_id: z.string().min(1),
1032
- body: optionalString,
1039
+ body: optionalBodySchema,
1033
1040
  position: optionalRecord,
1034
1041
  resolve_discussion: optionalBoolean
1035
1042
  },
@@ -1049,10 +1056,10 @@ function getGitLabToolDefinitions() {
1049
1056
  {
1050
1057
  name: "gitlab_delete_draft_note",
1051
1058
  title: "Delete Draft Note",
1052
- description: "Delete a merge-request draft note.",
1053
- mutating: true,
1059
+ description: "Delete a merge-request draft note permanently. Irreversible. Requires merge_request_iid and draft_note_id. Recommended pre-check: gitlab_get_draft_note or gitlab_list_draft_notes.",
1060
+ capabilities: deleteCapabilities,
1054
1061
  inputSchema: {
1055
- project_id: z.string().optional(),
1062
+ project_id: optionalProjectIdSchema,
1056
1063
  merge_request_iid: z.string().min(1),
1057
1064
  draft_note_id: z.string().min(1)
1058
1065
  },
@@ -1062,9 +1069,9 @@ function getGitLabToolDefinitions() {
1062
1069
  name: "gitlab_publish_draft_note",
1063
1070
  title: "Publish Draft Note",
1064
1071
  description: "Publish one merge-request draft note.",
1065
- mutating: true,
1072
+ capabilities: writeCapabilities,
1066
1073
  inputSchema: {
1067
- project_id: z.string().optional(),
1074
+ project_id: optionalProjectIdSchema,
1068
1075
  merge_request_iid: z.string().min(1),
1069
1076
  draft_note_id: z.string().min(1)
1070
1077
  },
@@ -1074,9 +1081,9 @@ function getGitLabToolDefinitions() {
1074
1081
  name: "gitlab_bulk_publish_draft_notes",
1075
1082
  title: "Bulk Publish Draft Notes",
1076
1083
  description: "Publish all merge-request draft notes.",
1077
- mutating: true,
1084
+ capabilities: writeCapabilities,
1078
1085
  inputSchema: {
1079
- project_id: z.string().optional(),
1086
+ project_id: optionalProjectIdSchema,
1080
1087
  merge_request_iid: z.string().min(1)
1081
1088
  },
1082
1089
  handler: async (args, context) => context.gitlab.bulkPublishDraftNotes(resolveProjectId(args, context, true), getString(args, "merge_request_iid"))
@@ -1085,9 +1092,9 @@ function getGitLabToolDefinitions() {
1085
1092
  name: "gitlab_get_merge_request_note",
1086
1093
  title: "Get Merge Request Note",
1087
1094
  description: "Get a single MR note.",
1088
- mutating: false,
1095
+ capabilities: readCapabilities,
1089
1096
  inputSchema: {
1090
- project_id: z.string().optional(),
1097
+ project_id: optionalProjectIdSchema,
1091
1098
  merge_request_iid: z.string().min(1),
1092
1099
  note_id: z.string().min(1)
1093
1100
  },
@@ -1097,11 +1104,11 @@ function getGitLabToolDefinitions() {
1097
1104
  name: "gitlab_create_merge_request_note",
1098
1105
  title: "Create Merge Request Note",
1099
1106
  description: "Create a top-level MR note.",
1100
- mutating: true,
1107
+ capabilities: writeCapabilities,
1101
1108
  inputSchema: {
1102
- project_id: z.string().optional(),
1109
+ project_id: optionalProjectIdSchema,
1103
1110
  merge_request_iid: z.string().min(1),
1104
- body: z.string().min(1)
1111
+ body: bodySchema
1105
1112
  },
1106
1113
  handler: async (args, context) => context.gitlab.createMergeRequestNote(resolveProjectId(args, context, true), getString(args, "merge_request_iid"), getString(args, "body"))
1107
1114
  },
@@ -1109,12 +1116,12 @@ function getGitLabToolDefinitions() {
1109
1116
  name: "gitlab_create_note",
1110
1117
  title: "Create Note",
1111
1118
  description: "Create a note on an issue or merge request.",
1112
- mutating: true,
1119
+ capabilities: writeCapabilities,
1113
1120
  inputSchema: {
1114
- project_id: z.string().optional(),
1121
+ project_id: optionalProjectIdSchema,
1115
1122
  noteable_type: z.enum(["issue", "merge_request"]),
1116
1123
  noteable_iid: z.string().min(1),
1117
- body: z.string().min(1)
1124
+ body: bodySchema
1118
1125
  },
1119
1126
  handler: async (args, context) => context.gitlab.createNote(resolveProjectId(args, context, true), getString(args, "noteable_type"), getString(args, "noteable_iid"), getString(args, "body"))
1120
1127
  },
@@ -1122,22 +1129,22 @@ function getGitLabToolDefinitions() {
1122
1129
  name: "gitlab_update_merge_request_note",
1123
1130
  title: "Update Merge Request Note",
1124
1131
  description: "Update MR note body.",
1125
- mutating: true,
1132
+ capabilities: writeCapabilities,
1126
1133
  inputSchema: {
1127
- project_id: z.string().optional(),
1134
+ project_id: optionalProjectIdSchema,
1128
1135
  merge_request_iid: z.string().min(1),
1129
1136
  note_id: z.string().min(1),
1130
- body: z.string().min(1)
1137
+ body: bodySchema
1131
1138
  },
1132
1139
  handler: async (args, context) => context.gitlab.updateMergeRequestNote(resolveProjectId(args, context, true), getString(args, "merge_request_iid"), getString(args, "note_id"), getString(args, "body"))
1133
1140
  },
1134
1141
  {
1135
1142
  name: "gitlab_delete_merge_request_note",
1136
1143
  title: "Delete Merge Request Note",
1137
- description: "Delete an MR note.",
1138
- mutating: true,
1144
+ description: "Delete a top-level MR note permanently. Irreversible. Requires merge_request_iid and note_id. Recommended pre-check: gitlab_get_merge_request_note or gitlab_list_merge_request_notes.",
1145
+ capabilities: deleteCapabilities,
1139
1146
  inputSchema: {
1140
- project_id: z.string().optional(),
1147
+ project_id: optionalProjectIdSchema,
1141
1148
  merge_request_iid: z.string().min(1),
1142
1149
  note_id: z.string().min(1)
1143
1150
  },
@@ -1147,9 +1154,9 @@ function getGitLabToolDefinitions() {
1147
1154
  name: "gitlab_list_issues",
1148
1155
  title: "List Issues",
1149
1156
  description: "List issues in project.",
1150
- mutating: false,
1157
+ capabilities: readCapabilities,
1151
1158
  inputSchema: {
1152
- project_id: z.string().optional(),
1159
+ project_id: optionalProjectIdSchema,
1153
1160
  assignee_id: optionalStringOrNumber,
1154
1161
  assignee_username: optionalStringArray,
1155
1162
  author_id: optionalStringOrNumber,
@@ -1183,9 +1190,9 @@ function getGitLabToolDefinitions() {
1183
1190
  name: "gitlab_my_issues",
1184
1191
  title: "My Issues",
1185
1192
  description: "List issues assigned to the current authenticated user.",
1186
- mutating: false,
1193
+ capabilities: readCapabilities,
1187
1194
  inputSchema: {
1188
- project_id: z.string().optional(),
1195
+ project_id: optionalProjectIdSchema,
1189
1196
  state: z.enum(["opened", "closed", "all"]).optional(),
1190
1197
  labels: optionalStringOrStringArray,
1191
1198
  milestone: optionalString,
@@ -1208,9 +1215,9 @@ function getGitLabToolDefinitions() {
1208
1215
  name: "gitlab_get_issue",
1209
1216
  title: "Get Issue",
1210
1217
  description: "Get issue by IID.",
1211
- mutating: false,
1218
+ capabilities: readCapabilities,
1212
1219
  inputSchema: {
1213
- project_id: z.string().optional(),
1220
+ project_id: optionalProjectIdSchema,
1214
1221
  issue_iid: z.string().min(1)
1215
1222
  },
1216
1223
  handler: async (args, context) => context.gitlab.getIssue(resolveProjectId(args, context, true), getString(args, "issue_iid"))
@@ -1219,9 +1226,9 @@ function getGitLabToolDefinitions() {
1219
1226
  name: "gitlab_create_issue",
1220
1227
  title: "Create Issue",
1221
1228
  description: "Create a new issue.",
1222
- mutating: true,
1229
+ capabilities: writeCapabilities,
1223
1230
  inputSchema: {
1224
- project_id: z.string().optional(),
1231
+ project_id: optionalProjectIdSchema,
1225
1232
  title: z.string().min(1),
1226
1233
  description: optionalString,
1227
1234
  labels: optionalStringOrStringArray,
@@ -1246,9 +1253,9 @@ function getGitLabToolDefinitions() {
1246
1253
  name: "gitlab_update_issue",
1247
1254
  title: "Update Issue",
1248
1255
  description: "Update issue fields.",
1249
- mutating: true,
1256
+ capabilities: writeCapabilities,
1250
1257
  inputSchema: {
1251
- project_id: z.string().optional(),
1258
+ project_id: optionalProjectIdSchema,
1252
1259
  issue_iid: z.string().min(1),
1253
1260
  title: optionalString,
1254
1261
  description: optionalString,
@@ -1276,10 +1283,10 @@ function getGitLabToolDefinitions() {
1276
1283
  {
1277
1284
  name: "gitlab_delete_issue",
1278
1285
  title: "Delete Issue",
1279
- description: "Delete an issue.",
1280
- mutating: true,
1286
+ description: "Delete an issue permanently. Irreversible. Requires issue_iid. Recommended pre-check: gitlab_get_issue.",
1287
+ capabilities: deleteCapabilities,
1281
1288
  inputSchema: {
1282
- project_id: z.string().optional(),
1289
+ project_id: optionalProjectIdSchema,
1283
1290
  issue_iid: z.string().min(1)
1284
1291
  },
1285
1292
  handler: async (args, context) => context.gitlab.deleteIssue(resolveProjectId(args, context, true), getString(args, "issue_iid"))
@@ -1288,9 +1295,9 @@ function getGitLabToolDefinitions() {
1288
1295
  name: "gitlab_list_issue_discussions",
1289
1296
  title: "List Issue Discussions",
1290
1297
  description: "List issue discussions.",
1291
- mutating: false,
1298
+ capabilities: readCapabilities,
1292
1299
  inputSchema: {
1293
- project_id: z.string().optional(),
1300
+ project_id: optionalProjectIdSchema,
1294
1301
  issue_iid: z.string().min(1),
1295
1302
  ...paginationShape
1296
1303
  },
@@ -1300,12 +1307,12 @@ function getGitLabToolDefinitions() {
1300
1307
  name: "gitlab_create_issue_note",
1301
1308
  title: "Create Issue Note",
1302
1309
  description: "Create issue comment (top-level or discussion note).",
1303
- mutating: true,
1310
+ capabilities: writeCapabilities,
1304
1311
  inputSchema: {
1305
- project_id: z.string().optional(),
1312
+ project_id: optionalProjectIdSchema,
1306
1313
  issue_iid: z.string().min(1),
1307
1314
  discussion_id: optionalString,
1308
- body: z.string().min(1),
1315
+ body: bodySchema,
1309
1316
  created_at: optionalString
1310
1317
  },
1311
1318
  handler: async (args, context) => context.gitlab.createIssueNote(resolveProjectId(args, context, true), getString(args, "issue_iid"), {
@@ -1318,13 +1325,13 @@ function getGitLabToolDefinitions() {
1318
1325
  name: "gitlab_update_issue_note",
1319
1326
  title: "Update Issue Note",
1320
1327
  description: "Update an issue discussion note body or resolved state.",
1321
- mutating: true,
1328
+ capabilities: writeCapabilities,
1322
1329
  inputSchema: {
1323
- project_id: z.string().optional(),
1330
+ project_id: optionalProjectIdSchema,
1324
1331
  issue_iid: z.string().min(1),
1325
1332
  discussion_id: z.string().min(1),
1326
1333
  note_id: z.string().min(1),
1327
- body: optionalString,
1334
+ body: optionalBodySchema,
1328
1335
  resolved: optionalBoolean
1329
1336
  },
1330
1337
  handler: async (args, context) => {
@@ -1343,9 +1350,9 @@ function getGitLabToolDefinitions() {
1343
1350
  name: "gitlab_list_issue_links",
1344
1351
  title: "List Issue Links",
1345
1352
  description: "List related issue links for an issue.",
1346
- mutating: false,
1353
+ capabilities: readCapabilities,
1347
1354
  inputSchema: {
1348
- project_id: z.string().optional(),
1355
+ project_id: optionalProjectIdSchema,
1349
1356
  issue_iid: z.string().min(1)
1350
1357
  },
1351
1358
  handler: async (args, context) => context.gitlab.listIssueLinks(resolveProjectId(args, context, true), getString(args, "issue_iid"))
@@ -1354,9 +1361,9 @@ function getGitLabToolDefinitions() {
1354
1361
  name: "gitlab_get_issue_link",
1355
1362
  title: "Get Issue Link",
1356
1363
  description: "Get a single issue link by ID.",
1357
- mutating: false,
1364
+ capabilities: readCapabilities,
1358
1365
  inputSchema: {
1359
- project_id: z.string().optional(),
1366
+ project_id: optionalProjectIdSchema,
1360
1367
  issue_iid: z.string().min(1),
1361
1368
  issue_link_id: z.string().min(1)
1362
1369
  },
@@ -1366,11 +1373,11 @@ function getGitLabToolDefinitions() {
1366
1373
  name: "gitlab_create_issue_link",
1367
1374
  title: "Create Issue Link",
1368
1375
  description: "Create a relation between two issues.",
1369
- mutating: true,
1376
+ capabilities: writeCapabilities,
1370
1377
  inputSchema: {
1371
- project_id: z.string().optional(),
1378
+ project_id: optionalProjectIdSchema,
1372
1379
  issue_iid: z.string().min(1),
1373
- target_project_id: z.string().min(1),
1380
+ target_project_id: projectIdSchema,
1374
1381
  target_issue_iid: z.string().min(1),
1375
1382
  link_type: z.enum(["relates_to", "blocks", "is_blocked_by"]).optional()
1376
1383
  },
@@ -1383,10 +1390,10 @@ function getGitLabToolDefinitions() {
1383
1390
  {
1384
1391
  name: "gitlab_delete_issue_link",
1385
1392
  title: "Delete Issue Link",
1386
- description: "Delete a relation between issues.",
1387
- mutating: true,
1393
+ description: "Delete an issue link permanently. Irreversible for that relation. Requires issue_iid and issue_link_id. Recommended pre-check: gitlab_get_issue_link or gitlab_list_issue_links.",
1394
+ capabilities: deleteCapabilities,
1388
1395
  inputSchema: {
1389
- project_id: z.string().optional(),
1396
+ project_id: optionalProjectIdSchema,
1390
1397
  issue_iid: z.string().min(1),
1391
1398
  issue_link_id: z.string().min(1)
1392
1399
  },
@@ -1396,10 +1403,10 @@ function getGitLabToolDefinitions() {
1396
1403
  name: "gitlab_list_wiki_pages",
1397
1404
  title: "List Wiki Pages",
1398
1405
  description: "List wiki pages in a project.",
1399
- mutating: false,
1406
+ capabilities: readCapabilities,
1400
1407
  requiresFeature: "wiki",
1401
1408
  inputSchema: {
1402
- project_id: z.string().optional(),
1409
+ project_id: optionalProjectIdSchema,
1403
1410
  with_content: optionalBoolean,
1404
1411
  ...paginationShape
1405
1412
  },
@@ -1411,11 +1418,11 @@ function getGitLabToolDefinitions() {
1411
1418
  name: "gitlab_get_wiki_page",
1412
1419
  title: "Get Wiki Page",
1413
1420
  description: "Get wiki page by slug.",
1414
- mutating: false,
1421
+ capabilities: readCapabilities,
1415
1422
  requiresFeature: "wiki",
1416
1423
  inputSchema: {
1417
- project_id: z.string().optional(),
1418
- slug: z.string().min(1),
1424
+ project_id: optionalProjectIdSchema,
1425
+ slug: slugSchema,
1419
1426
  version: optionalString
1420
1427
  },
1421
1428
  handler: async (args, context) => context.gitlab.getWikiPage(resolveProjectId(args, context, true), getString(args, "slug"), {
@@ -1426,10 +1433,10 @@ function getGitLabToolDefinitions() {
1426
1433
  name: "gitlab_create_wiki_page",
1427
1434
  title: "Create Wiki Page",
1428
1435
  description: "Create a wiki page.",
1429
- mutating: true,
1436
+ capabilities: writeCapabilities,
1430
1437
  requiresFeature: "wiki",
1431
1438
  inputSchema: {
1432
- project_id: z.string().optional(),
1439
+ project_id: optionalProjectIdSchema,
1433
1440
  title: z.string().min(1),
1434
1441
  content: z.string().min(1),
1435
1442
  format: optionalString
@@ -1444,11 +1451,11 @@ function getGitLabToolDefinitions() {
1444
1451
  name: "gitlab_update_wiki_page",
1445
1452
  title: "Update Wiki Page",
1446
1453
  description: "Update wiki page by slug.",
1447
- mutating: true,
1454
+ capabilities: writeCapabilities,
1448
1455
  requiresFeature: "wiki",
1449
1456
  inputSchema: {
1450
- project_id: z.string().optional(),
1451
- slug: z.string().min(1),
1457
+ project_id: optionalProjectIdSchema,
1458
+ slug: slugSchema,
1452
1459
  content: z.string().min(1),
1453
1460
  title: optionalString,
1454
1461
  format: optionalString
@@ -1462,12 +1469,12 @@ function getGitLabToolDefinitions() {
1462
1469
  {
1463
1470
  name: "gitlab_delete_wiki_page",
1464
1471
  title: "Delete Wiki Page",
1465
- description: "Delete wiki page by slug.",
1466
- mutating: true,
1472
+ description: "Delete a wiki page permanently. Irreversible. Requires slug. Recommended pre-check: gitlab_get_wiki_page or gitlab_list_wiki_pages.",
1473
+ capabilities: deleteCapabilities,
1467
1474
  requiresFeature: "wiki",
1468
1475
  inputSchema: {
1469
- project_id: z.string().optional(),
1470
- slug: z.string().min(1)
1476
+ project_id: optionalProjectIdSchema,
1477
+ slug: slugSchema
1471
1478
  },
1472
1479
  handler: async (args, context) => context.gitlab.deleteWikiPage(resolveProjectId(args, context, true), getString(args, "slug"))
1473
1480
  },
@@ -1475,10 +1482,10 @@ function getGitLabToolDefinitions() {
1475
1482
  name: "gitlab_list_pipelines",
1476
1483
  title: "List Pipelines",
1477
1484
  description: "List pipelines for a project.",
1478
- mutating: false,
1485
+ capabilities: readCapabilities,
1479
1486
  requiresFeature: "pipeline",
1480
1487
  inputSchema: {
1481
- project_id: z.string().optional(),
1488
+ project_id: optionalProjectIdSchema,
1482
1489
  scope: z.enum(["running", "pending", "finished", "branches", "tags"]).optional(),
1483
1490
  status: z
1484
1491
  .enum([
@@ -1495,7 +1502,7 @@ function getGitLabToolDefinitions() {
1495
1502
  "scheduled"
1496
1503
  ])
1497
1504
  .optional(),
1498
- ref: optionalString,
1505
+ ref: optionalRefLikeSchema,
1499
1506
  sha: optionalString,
1500
1507
  yaml_errors: optionalBoolean,
1501
1508
  username: optionalString,
@@ -1514,10 +1521,10 @@ function getGitLabToolDefinitions() {
1514
1521
  name: "gitlab_get_pipeline",
1515
1522
  title: "Get Pipeline",
1516
1523
  description: "Get one pipeline.",
1517
- mutating: false,
1524
+ capabilities: readCapabilities,
1518
1525
  requiresFeature: "pipeline",
1519
1526
  inputSchema: {
1520
- project_id: z.string().optional(),
1527
+ project_id: optionalProjectIdSchema,
1521
1528
  pipeline_id: z.string().min(1)
1522
1529
  },
1523
1530
  handler: async (args, context) => context.gitlab.getPipeline(resolveProjectId(args, context, true), getString(args, "pipeline_id"))
@@ -1526,12 +1533,12 @@ function getGitLabToolDefinitions() {
1526
1533
  name: "gitlab_list_deployments",
1527
1534
  title: "List Deployments",
1528
1535
  description: "List deployments in a project.",
1529
- mutating: false,
1536
+ capabilities: readCapabilities,
1530
1537
  requiresFeature: "pipeline",
1531
1538
  inputSchema: {
1532
- project_id: z.string().optional(),
1539
+ project_id: optionalProjectIdSchema,
1533
1540
  environment: optionalString,
1534
- ref: optionalString,
1541
+ ref: optionalRefLikeSchema,
1535
1542
  sha: optionalString,
1536
1543
  status: optionalString,
1537
1544
  updated_after: optionalString,
@@ -1550,10 +1557,10 @@ function getGitLabToolDefinitions() {
1550
1557
  name: "gitlab_get_deployment",
1551
1558
  title: "Get Deployment",
1552
1559
  description: "Get one deployment by ID.",
1553
- mutating: false,
1560
+ capabilities: readCapabilities,
1554
1561
  requiresFeature: "pipeline",
1555
1562
  inputSchema: {
1556
- project_id: z.string().optional(),
1563
+ project_id: optionalProjectIdSchema,
1557
1564
  deployment_id: z.string().min(1)
1558
1565
  },
1559
1566
  handler: async (args, context) => context.gitlab.getDeployment(resolveProjectId(args, context, true), getString(args, "deployment_id"))
@@ -1562,11 +1569,11 @@ function getGitLabToolDefinitions() {
1562
1569
  name: "gitlab_list_environments",
1563
1570
  title: "List Environments",
1564
1571
  description: "List environments in a project.",
1565
- mutating: false,
1572
+ capabilities: readCapabilities,
1566
1573
  requiresFeature: "pipeline",
1567
1574
  inputSchema: {
1568
- project_id: z.string().optional(),
1569
- name: optionalString,
1575
+ project_id: optionalProjectIdSchema,
1576
+ name: optionalDisplayNameSchema,
1570
1577
  search: optionalString,
1571
1578
  states: z.enum(["available", "stopped"]).optional(),
1572
1579
  ...paginationShape
@@ -1579,10 +1586,10 @@ function getGitLabToolDefinitions() {
1579
1586
  name: "gitlab_get_environment",
1580
1587
  title: "Get Environment",
1581
1588
  description: "Get one environment by ID.",
1582
- mutating: false,
1589
+ capabilities: readCapabilities,
1583
1590
  requiresFeature: "pipeline",
1584
1591
  inputSchema: {
1585
- project_id: z.string().optional(),
1592
+ project_id: optionalProjectIdSchema,
1586
1593
  environment_id: z.string().min(1)
1587
1594
  },
1588
1595
  handler: async (args, context) => context.gitlab.getEnvironment(resolveProjectId(args, context, true), getString(args, "environment_id"))
@@ -1591,10 +1598,10 @@ function getGitLabToolDefinitions() {
1591
1598
  name: "gitlab_list_pipeline_jobs",
1592
1599
  title: "List Pipeline Jobs",
1593
1600
  description: "List jobs in a pipeline.",
1594
- mutating: false,
1601
+ capabilities: readCapabilities,
1595
1602
  requiresFeature: "pipeline",
1596
1603
  inputSchema: {
1597
- project_id: z.string().optional(),
1604
+ project_id: optionalProjectIdSchema,
1598
1605
  pipeline_id: z.string().min(1),
1599
1606
  scope: z
1600
1607
  .enum([
@@ -1617,10 +1624,10 @@ function getGitLabToolDefinitions() {
1617
1624
  name: "gitlab_list_pipeline_trigger_jobs",
1618
1625
  title: "List Pipeline Trigger Jobs",
1619
1626
  description: "List downstream/bridge trigger jobs in a pipeline.",
1620
- mutating: false,
1627
+ capabilities: readCapabilities,
1621
1628
  requiresFeature: "pipeline",
1622
1629
  inputSchema: {
1623
- project_id: z.string().optional(),
1630
+ project_id: optionalProjectIdSchema,
1624
1631
  pipeline_id: z.string().min(1),
1625
1632
  scope: z
1626
1633
  .enum([
@@ -1646,10 +1653,10 @@ function getGitLabToolDefinitions() {
1646
1653
  name: "gitlab_get_pipeline_job",
1647
1654
  title: "Get Pipeline Job",
1648
1655
  description: "Get one job by job ID.",
1649
- mutating: false,
1656
+ capabilities: readCapabilities,
1650
1657
  requiresFeature: "pipeline",
1651
1658
  inputSchema: {
1652
- project_id: z.string().optional(),
1659
+ project_id: optionalProjectIdSchema,
1653
1660
  job_id: z.string().min(1)
1654
1661
  },
1655
1662
  handler: async (args, context) => context.gitlab.getPipelineJob(resolveProjectId(args, context, true), getString(args, "job_id"))
@@ -1658,10 +1665,10 @@ function getGitLabToolDefinitions() {
1658
1665
  name: "gitlab_get_pipeline_job_output",
1659
1666
  title: "Get Pipeline Job Output",
1660
1667
  description: "Get raw job trace output.",
1661
- mutating: false,
1668
+ capabilities: readCapabilities,
1662
1669
  requiresFeature: "pipeline",
1663
1670
  inputSchema: {
1664
- project_id: z.string().optional(),
1671
+ project_id: optionalProjectIdSchema,
1665
1672
  job_id: z.string().min(1)
1666
1673
  },
1667
1674
  handler: async (args, context) => context.gitlab.getPipelineJobOutput(resolveProjectId(args, context, true), getString(args, "job_id"))
@@ -1670,10 +1677,10 @@ function getGitLabToolDefinitions() {
1670
1677
  name: "gitlab_list_job_artifacts",
1671
1678
  title: "List Job Artifacts",
1672
1679
  description: "List files and directories inside a job artifacts archive.",
1673
- mutating: false,
1680
+ capabilities: readCapabilities,
1674
1681
  requiresFeature: "pipeline",
1675
1682
  inputSchema: {
1676
- project_id: z.string().optional(),
1683
+ project_id: optionalProjectIdSchema,
1677
1684
  job_id: z.string().min(1),
1678
1685
  path: optionalString,
1679
1686
  recursive: optionalBoolean
@@ -1684,10 +1691,10 @@ function getGitLabToolDefinitions() {
1684
1691
  name: "gitlab_download_job_artifacts",
1685
1692
  title: "Download Job Artifacts",
1686
1693
  description: "Download the full job artifacts archive as base64 content.",
1687
- mutating: false,
1694
+ capabilities: readCapabilities,
1688
1695
  requiresFeature: "pipeline",
1689
1696
  inputSchema: {
1690
- project_id: z.string().optional(),
1697
+ project_id: optionalProjectIdSchema,
1691
1698
  job_id: z.string().min(1)
1692
1699
  },
1693
1700
  handler: async (args, context) => context.gitlab.downloadJobArtifacts(resolveProjectId(args, context, true), getString(args, "job_id"))
@@ -1696,11 +1703,11 @@ function getGitLabToolDefinitions() {
1696
1703
  name: "gitlab_download_job_artifacts_local",
1697
1704
  title: "Download Job Artifacts Local",
1698
1705
  description: "Download the full job artifacts archive to a local directory.",
1699
- mutating: true,
1706
+ capabilities: writeCapabilities,
1700
1707
  requiresFeature: "pipeline",
1701
1708
  requiresLocalFileTools: true,
1702
1709
  inputSchema: {
1703
- project_id: z.string().optional(),
1710
+ project_id: optionalProjectIdSchema,
1704
1711
  job_id: z.string().min(1),
1705
1712
  local_path: optionalString
1706
1713
  },
@@ -1710,10 +1717,10 @@ function getGitLabToolDefinitions() {
1710
1717
  name: "gitlab_get_job_artifact_file",
1711
1718
  title: "Get Job Artifact File",
1712
1719
  description: "Return one file from a job artifacts archive as inline UTF-8 or base64 content.",
1713
- mutating: false,
1720
+ capabilities: readCapabilities,
1714
1721
  requiresFeature: "pipeline",
1715
1722
  inputSchema: {
1716
- project_id: z.string().optional(),
1723
+ project_id: optionalProjectIdSchema,
1717
1724
  job_id: z.string().min(1),
1718
1725
  artifact_path: z.string().min(1)
1719
1726
  },
@@ -1723,11 +1730,11 @@ function getGitLabToolDefinitions() {
1723
1730
  name: "gitlab_get_job_artifact_file_local",
1724
1731
  title: "Get Job Artifact File Local",
1725
1732
  description: "Save one file from a job artifacts archive to a local directory.",
1726
- mutating: true,
1733
+ capabilities: writeCapabilities,
1727
1734
  requiresFeature: "pipeline",
1728
1735
  requiresLocalFileTools: true,
1729
1736
  inputSchema: {
1730
- project_id: z.string().optional(),
1737
+ project_id: optionalProjectIdSchema,
1731
1738
  job_id: z.string().min(1),
1732
1739
  artifact_path: z.string().min(1),
1733
1740
  local_path: optionalString
@@ -1738,11 +1745,11 @@ function getGitLabToolDefinitions() {
1738
1745
  name: "gitlab_create_pipeline",
1739
1746
  title: "Create Pipeline",
1740
1747
  description: "Trigger a new pipeline.",
1741
- mutating: true,
1748
+ capabilities: writeCapabilities,
1742
1749
  requiresFeature: "pipeline",
1743
1750
  inputSchema: {
1744
- project_id: z.string().optional(),
1745
- ref: z.string().min(1),
1751
+ project_id: optionalProjectIdSchema,
1752
+ ref: refLikeSchema,
1746
1753
  inputs: optionalPipelineInputsRecord,
1747
1754
  variables: z
1748
1755
  .array(z.object({
@@ -1762,10 +1769,10 @@ function getGitLabToolDefinitions() {
1762
1769
  name: "gitlab_retry_pipeline",
1763
1770
  title: "Retry Pipeline",
1764
1771
  description: "Retry failed jobs in pipeline.",
1765
- mutating: true,
1772
+ capabilities: writeCapabilities,
1766
1773
  requiresFeature: "pipeline",
1767
1774
  inputSchema: {
1768
- project_id: z.string().optional(),
1775
+ project_id: optionalProjectIdSchema,
1769
1776
  pipeline_id: z.string().min(1)
1770
1777
  },
1771
1778
  handler: async (args, context) => context.gitlab.retryPipeline(resolveProjectId(args, context, true), getString(args, "pipeline_id"))
@@ -1774,10 +1781,10 @@ function getGitLabToolDefinitions() {
1774
1781
  name: "gitlab_cancel_pipeline",
1775
1782
  title: "Cancel Pipeline",
1776
1783
  description: "Cancel a running pipeline.",
1777
- mutating: true,
1784
+ capabilities: writeCapabilities,
1778
1785
  requiresFeature: "pipeline",
1779
1786
  inputSchema: {
1780
- project_id: z.string().optional(),
1787
+ project_id: optionalProjectIdSchema,
1781
1788
  pipeline_id: z.string().min(1)
1782
1789
  },
1783
1790
  handler: async (args, context) => context.gitlab.cancelPipeline(resolveProjectId(args, context, true), getString(args, "pipeline_id"))
@@ -1786,10 +1793,10 @@ function getGitLabToolDefinitions() {
1786
1793
  name: "gitlab_retry_pipeline_job",
1787
1794
  title: "Retry Pipeline Job",
1788
1795
  description: "Retry one failed job.",
1789
- mutating: true,
1796
+ capabilities: writeCapabilities,
1790
1797
  requiresFeature: "pipeline",
1791
1798
  inputSchema: {
1792
- project_id: z.string().optional(),
1799
+ project_id: optionalProjectIdSchema,
1793
1800
  job_id: z.string().min(1)
1794
1801
  },
1795
1802
  handler: async (args, context) => context.gitlab.retryPipelineJob(resolveProjectId(args, context, true), getString(args, "job_id"))
@@ -1798,10 +1805,10 @@ function getGitLabToolDefinitions() {
1798
1805
  name: "gitlab_cancel_pipeline_job",
1799
1806
  title: "Cancel Pipeline Job",
1800
1807
  description: "Cancel one running job.",
1801
- mutating: true,
1808
+ capabilities: writeCapabilities,
1802
1809
  requiresFeature: "pipeline",
1803
1810
  inputSchema: {
1804
- project_id: z.string().optional(),
1811
+ project_id: optionalProjectIdSchema,
1805
1812
  job_id: z.string().min(1)
1806
1813
  },
1807
1814
  handler: async (args, context) => context.gitlab.cancelPipelineJob(resolveProjectId(args, context, true), getString(args, "job_id"))
@@ -1810,10 +1817,10 @@ function getGitLabToolDefinitions() {
1810
1817
  name: "gitlab_play_pipeline_job",
1811
1818
  title: "Play Pipeline Job",
1812
1819
  description: "Play a manual job.",
1813
- mutating: true,
1820
+ capabilities: writeCapabilities,
1814
1821
  requiresFeature: "pipeline",
1815
1822
  inputSchema: {
1816
- project_id: z.string().optional(),
1823
+ project_id: optionalProjectIdSchema,
1817
1824
  job_id: z.string().min(1)
1818
1825
  },
1819
1826
  handler: async (args, context) => context.gitlab.playPipelineJob(resolveProjectId(args, context, true), getString(args, "job_id"))
@@ -1822,10 +1829,10 @@ function getGitLabToolDefinitions() {
1822
1829
  name: "gitlab_list_milestones",
1823
1830
  title: "List Milestones",
1824
1831
  description: "List project milestones.",
1825
- mutating: false,
1832
+ capabilities: readCapabilities,
1826
1833
  requiresFeature: "milestone",
1827
1834
  inputSchema: {
1828
- project_id: z.string().optional(),
1835
+ project_id: optionalProjectIdSchema,
1829
1836
  iids: optionalNumberArray,
1830
1837
  state: optionalString,
1831
1838
  title: optionalString,
@@ -1843,10 +1850,10 @@ function getGitLabToolDefinitions() {
1843
1850
  name: "gitlab_get_milestone",
1844
1851
  title: "Get Milestone",
1845
1852
  description: "Get a milestone by ID.",
1846
- mutating: false,
1853
+ capabilities: readCapabilities,
1847
1854
  requiresFeature: "milestone",
1848
1855
  inputSchema: {
1849
- project_id: z.string().optional(),
1856
+ project_id: optionalProjectIdSchema,
1850
1857
  milestone_id: z.string().min(1)
1851
1858
  },
1852
1859
  handler: async (args, context) => context.gitlab.getMilestone(resolveProjectId(args, context, true), getString(args, "milestone_id"))
@@ -1855,10 +1862,10 @@ function getGitLabToolDefinitions() {
1855
1862
  name: "gitlab_create_milestone",
1856
1863
  title: "Create Milestone",
1857
1864
  description: "Create a milestone.",
1858
- mutating: true,
1865
+ capabilities: writeCapabilities,
1859
1866
  requiresFeature: "milestone",
1860
1867
  inputSchema: {
1861
- project_id: z.string().optional(),
1868
+ project_id: optionalProjectIdSchema,
1862
1869
  title: z.string().min(1),
1863
1870
  description: optionalString,
1864
1871
  due_date: optionalString,
@@ -1875,10 +1882,10 @@ function getGitLabToolDefinitions() {
1875
1882
  name: "gitlab_update_milestone",
1876
1883
  title: "Update Milestone",
1877
1884
  description: "Update milestone fields.",
1878
- mutating: true,
1885
+ capabilities: writeCapabilities,
1879
1886
  requiresFeature: "milestone",
1880
1887
  inputSchema: {
1881
- project_id: z.string().optional(),
1888
+ project_id: optionalProjectIdSchema,
1882
1889
  milestone_id: z.string().min(1),
1883
1890
  title: optionalString,
1884
1891
  description: optionalString,
@@ -1892,10 +1899,10 @@ function getGitLabToolDefinitions() {
1892
1899
  name: "gitlab_edit_milestone",
1893
1900
  title: "Edit Milestone (Alias)",
1894
1901
  description: "Backward-compatible alias of gitlab_update_milestone.",
1895
- mutating: true,
1902
+ capabilities: writeCapabilities,
1896
1903
  requiresFeature: "milestone",
1897
1904
  inputSchema: {
1898
- project_id: z.string().optional(),
1905
+ project_id: optionalProjectIdSchema,
1899
1906
  milestone_id: z.string().min(1),
1900
1907
  title: optionalString,
1901
1908
  description: optionalString,
@@ -1908,11 +1915,11 @@ function getGitLabToolDefinitions() {
1908
1915
  {
1909
1916
  name: "gitlab_delete_milestone",
1910
1917
  title: "Delete Milestone",
1911
- description: "Delete a milestone.",
1912
- mutating: true,
1918
+ description: "Delete a milestone permanently. Irreversible. Requires milestone_id. Recommended pre-check: gitlab_get_milestone or gitlab_list_milestones.",
1919
+ capabilities: deleteCapabilities,
1913
1920
  requiresFeature: "milestone",
1914
1921
  inputSchema: {
1915
- project_id: z.string().optional(),
1922
+ project_id: optionalProjectIdSchema,
1916
1923
  milestone_id: z.string().min(1)
1917
1924
  },
1918
1925
  handler: async (args, context) => context.gitlab.deleteMilestone(resolveProjectId(args, context, true), getString(args, "milestone_id"))
@@ -1921,10 +1928,10 @@ function getGitLabToolDefinitions() {
1921
1928
  name: "gitlab_get_milestone_issue",
1922
1929
  title: "Get Milestone Issues",
1923
1930
  description: "List issues assigned to a milestone.",
1924
- mutating: false,
1931
+ capabilities: readCapabilities,
1925
1932
  requiresFeature: "milestone",
1926
1933
  inputSchema: {
1927
- project_id: z.string().optional(),
1934
+ project_id: optionalProjectIdSchema,
1928
1935
  milestone_id: z.string().min(1)
1929
1936
  },
1930
1937
  handler: async (args, context) => context.gitlab.getMilestoneIssues(resolveProjectId(args, context, true), getString(args, "milestone_id"))
@@ -1933,10 +1940,10 @@ function getGitLabToolDefinitions() {
1933
1940
  name: "gitlab_get_milestone_merge_requests",
1934
1941
  title: "Get Milestone Merge Requests",
1935
1942
  description: "List merge requests assigned to a milestone.",
1936
- mutating: false,
1943
+ capabilities: readCapabilities,
1937
1944
  requiresFeature: "milestone",
1938
1945
  inputSchema: {
1939
- project_id: z.string().optional(),
1946
+ project_id: optionalProjectIdSchema,
1940
1947
  milestone_id: z.string().min(1),
1941
1948
  ...paginationShape
1942
1949
  },
@@ -1946,10 +1953,10 @@ function getGitLabToolDefinitions() {
1946
1953
  name: "gitlab_promote_milestone",
1947
1954
  title: "Promote Milestone",
1948
1955
  description: "Promote a project milestone to a group milestone.",
1949
- mutating: true,
1956
+ capabilities: adminCapabilities,
1950
1957
  requiresFeature: "milestone",
1951
1958
  inputSchema: {
1952
- project_id: z.string().optional(),
1959
+ project_id: optionalProjectIdSchema,
1953
1960
  milestone_id: z.string().min(1)
1954
1961
  },
1955
1962
  handler: async (args, context) => context.gitlab.promoteMilestone(resolveProjectId(args, context, true), getString(args, "milestone_id"))
@@ -1958,10 +1965,10 @@ function getGitLabToolDefinitions() {
1958
1965
  name: "gitlab_get_milestone_burndown_events",
1959
1966
  title: "Get Milestone Burndown Events",
1960
1967
  description: "List burndown events for a milestone.",
1961
- mutating: false,
1968
+ capabilities: readCapabilities,
1962
1969
  requiresFeature: "milestone",
1963
1970
  inputSchema: {
1964
- project_id: z.string().optional(),
1971
+ project_id: optionalProjectIdSchema,
1965
1972
  milestone_id: z.string().min(1),
1966
1973
  ...paginationShape
1967
1974
  },
@@ -1971,10 +1978,10 @@ function getGitLabToolDefinitions() {
1971
1978
  name: "gitlab_list_releases",
1972
1979
  title: "List Releases",
1973
1980
  description: "List project releases.",
1974
- mutating: false,
1981
+ capabilities: readCapabilities,
1975
1982
  requiresFeature: "release",
1976
1983
  inputSchema: {
1977
- project_id: z.string().optional(),
1984
+ project_id: optionalProjectIdSchema,
1978
1985
  order_by: z.enum(["released_at", "created_at"]).optional(),
1979
1986
  sort: z.enum(["asc", "desc"]).optional(),
1980
1987
  include_html_description: optionalBoolean,
@@ -1988,11 +1995,11 @@ function getGitLabToolDefinitions() {
1988
1995
  name: "gitlab_get_release",
1989
1996
  title: "Get Release",
1990
1997
  description: "Get one release by tag name.",
1991
- mutating: false,
1998
+ capabilities: readCapabilities,
1992
1999
  requiresFeature: "release",
1993
2000
  inputSchema: {
1994
- project_id: z.string().optional(),
1995
- tag_name: z.string().min(1),
2001
+ project_id: optionalProjectIdSchema,
2002
+ tag_name: refLikeSchema,
1996
2003
  include_html_description: optionalBoolean
1997
2004
  },
1998
2005
  handler: async (args, context) => context.gitlab.getRelease(resolveProjectId(args, context, true), getString(args, "tag_name"), { query: toQuery(omit(args, ["project_id", "tag_name"])) })
@@ -2001,15 +2008,15 @@ function getGitLabToolDefinitions() {
2001
2008
  name: "gitlab_create_release",
2002
2009
  title: "Create Release",
2003
2010
  description: "Create a release.",
2004
- mutating: true,
2011
+ capabilities: writeCapabilities,
2005
2012
  requiresFeature: "release",
2006
2013
  inputSchema: {
2007
- project_id: z.string().optional(),
2008
- name: optionalString,
2009
- tag_name: z.string().min(1),
2014
+ project_id: optionalProjectIdSchema,
2015
+ name: optionalDisplayNameSchema,
2016
+ tag_name: refLikeSchema,
2010
2017
  tag_message: optionalString,
2011
2018
  description: optionalString,
2012
- ref: optionalString,
2019
+ ref: optionalRefLikeSchema,
2013
2020
  released_at: optionalString,
2014
2021
  milestones: optionalStringArray,
2015
2022
  assets: optionalRecord
@@ -2020,12 +2027,12 @@ function getGitLabToolDefinitions() {
2020
2027
  name: "gitlab_update_release",
2021
2028
  title: "Update Release",
2022
2029
  description: "Update existing release.",
2023
- mutating: true,
2030
+ capabilities: writeCapabilities,
2024
2031
  requiresFeature: "release",
2025
2032
  inputSchema: {
2026
- project_id: z.string().optional(),
2027
- tag_name: z.string().min(1),
2028
- name: optionalString,
2033
+ project_id: optionalProjectIdSchema,
2034
+ tag_name: refLikeSchema,
2035
+ name: optionalDisplayNameSchema,
2029
2036
  description: optionalString,
2030
2037
  released_at: optionalString,
2031
2038
  milestones: optionalStringArray,
@@ -2036,12 +2043,12 @@ function getGitLabToolDefinitions() {
2036
2043
  {
2037
2044
  name: "gitlab_delete_release",
2038
2045
  title: "Delete Release",
2039
- description: "Delete a release by tag.",
2040
- mutating: true,
2046
+ description: "Delete the release record for tag_name permanently. Irreversible for the release entry. Requires tag_name. Recommended pre-check: gitlab_get_release or gitlab_list_releases.",
2047
+ capabilities: deleteCapabilities,
2041
2048
  requiresFeature: "release",
2042
2049
  inputSchema: {
2043
- project_id: z.string().optional(),
2044
- tag_name: z.string().min(1)
2050
+ project_id: optionalProjectIdSchema,
2051
+ tag_name: refLikeSchema
2045
2052
  },
2046
2053
  handler: async (args, context) => context.gitlab.deleteRelease(resolveProjectId(args, context, true), getString(args, "tag_name"))
2047
2054
  },
@@ -2049,11 +2056,11 @@ function getGitLabToolDefinitions() {
2049
2056
  name: "gitlab_create_release_evidence",
2050
2057
  title: "Create Release Evidence",
2051
2058
  description: "Create evidence for an existing release.",
2052
- mutating: true,
2059
+ capabilities: writeCapabilities,
2053
2060
  requiresFeature: "release",
2054
2061
  inputSchema: {
2055
- project_id: z.string().optional(),
2056
- tag_name: z.string().min(1)
2062
+ project_id: optionalProjectIdSchema,
2063
+ tag_name: refLikeSchema
2057
2064
  },
2058
2065
  handler: async (args, context) => context.gitlab.createReleaseEvidence(resolveProjectId(args, context, true), getString(args, "tag_name"))
2059
2066
  },
@@ -2061,11 +2068,11 @@ function getGitLabToolDefinitions() {
2061
2068
  name: "gitlab_download_release_asset",
2062
2069
  title: "Download Release Asset",
2063
2070
  description: "Download a release asset using its direct asset path.",
2064
- mutating: false,
2071
+ capabilities: readCapabilities,
2065
2072
  requiresFeature: "release",
2066
2073
  inputSchema: {
2067
- project_id: z.string().optional(),
2068
- tag_name: z.string().min(1),
2074
+ project_id: optionalProjectIdSchema,
2075
+ tag_name: refLikeSchema,
2069
2076
  direct_asset_path: z.string().min(1)
2070
2077
  },
2071
2078
  handler: async (args, context) => context.gitlab.downloadReleaseAsset(resolveProjectId(args, context, true), getString(args, "tag_name"), getString(args, "direct_asset_path"))
@@ -2074,9 +2081,9 @@ function getGitLabToolDefinitions() {
2074
2081
  name: "gitlab_list_labels",
2075
2082
  title: "List Labels",
2076
2083
  description: "List project labels.",
2077
- mutating: false,
2084
+ capabilities: readCapabilities,
2078
2085
  inputSchema: {
2079
- project_id: z.string().optional(),
2086
+ project_id: optionalProjectIdSchema,
2080
2087
  with_counts: optionalBoolean,
2081
2088
  include_ancestor_groups: optionalBoolean,
2082
2089
  search: optionalString,
@@ -2090,10 +2097,10 @@ function getGitLabToolDefinitions() {
2090
2097
  name: "gitlab_get_label",
2091
2098
  title: "Get Label",
2092
2099
  description: "Get one label by ID.",
2093
- mutating: false,
2100
+ capabilities: readCapabilities,
2094
2101
  inputSchema: {
2095
- project_id: z.string().optional(),
2096
- label_id: z.string().min(1),
2102
+ project_id: optionalProjectIdSchema,
2103
+ label_id: displayNameSchema,
2097
2104
  include_ancestor_groups: optionalBoolean
2098
2105
  },
2099
2106
  handler: async (args, context) => context.gitlab.getLabel(resolveProjectId(args, context, true), getString(args, "label_id"), {
@@ -2104,10 +2111,10 @@ function getGitLabToolDefinitions() {
2104
2111
  name: "gitlab_create_label",
2105
2112
  title: "Create Label",
2106
2113
  description: "Create a label.",
2107
- mutating: true,
2114
+ capabilities: writeCapabilities,
2108
2115
  inputSchema: {
2109
- project_id: z.string().optional(),
2110
- name: z.string().min(1),
2116
+ project_id: optionalProjectIdSchema,
2117
+ name: displayNameSchema,
2111
2118
  color: z.string().min(1),
2112
2119
  description: optionalString,
2113
2120
  priority: optionalNumber
@@ -2118,12 +2125,12 @@ function getGitLabToolDefinitions() {
2118
2125
  name: "gitlab_update_label",
2119
2126
  title: "Update Label",
2120
2127
  description: "Update a label.",
2121
- mutating: true,
2128
+ capabilities: writeCapabilities,
2122
2129
  inputSchema: {
2123
- project_id: z.string().optional(),
2124
- name: optionalString,
2125
- label_id: optionalString,
2126
- new_name: optionalString,
2130
+ project_id: optionalProjectIdSchema,
2131
+ name: optionalDisplayNameSchema,
2132
+ label_id: optionalDisplayNameSchema,
2133
+ new_name: optionalDisplayNameSchema,
2127
2134
  color: optionalString,
2128
2135
  description: optionalString,
2129
2136
  priority: optionalNumber
@@ -2142,12 +2149,12 @@ function getGitLabToolDefinitions() {
2142
2149
  {
2143
2150
  name: "gitlab_delete_label",
2144
2151
  title: "Delete Label",
2145
- description: "Delete a label by name.",
2146
- mutating: true,
2152
+ description: "Delete a label permanently. Irreversible. Requires name or label_id. Recommended pre-check: gitlab_get_label or gitlab_list_labels.",
2153
+ capabilities: deleteCapabilities,
2147
2154
  inputSchema: {
2148
- project_id: z.string().optional(),
2149
- name: optionalString,
2150
- label_id: optionalString
2155
+ project_id: optionalProjectIdSchema,
2156
+ name: optionalDisplayNameSchema,
2157
+ label_id: optionalDisplayNameSchema
2151
2158
  },
2152
2159
  handler: async (args, context) => {
2153
2160
  const labelName = getOptionalString(args, "name") ?? getOptionalString(args, "label_id");
@@ -2161,7 +2168,7 @@ function getGitLabToolDefinitions() {
2161
2168
  name: "gitlab_list_namespaces",
2162
2169
  title: "List Namespaces",
2163
2170
  description: "List namespaces visible to user.",
2164
- mutating: false,
2171
+ capabilities: readCapabilities,
2165
2172
  inputSchema: {
2166
2173
  search: optionalString,
2167
2174
  owned: optionalBoolean,
@@ -2173,10 +2180,10 @@ function getGitLabToolDefinitions() {
2173
2180
  name: "gitlab_get_namespace",
2174
2181
  title: "Get Namespace",
2175
2182
  description: "Get namespace by ID or path.",
2176
- mutating: false,
2183
+ capabilities: readCapabilities,
2177
2184
  inputSchema: {
2178
- namespace_id_or_path: optionalString,
2179
- namespace_id: optionalString
2185
+ namespace_id_or_path: optionalProjectIdSchema,
2186
+ namespace_id: optionalProjectIdSchema
2180
2187
  },
2181
2188
  handler: async (args, context) => {
2182
2189
  const namespaceId = getOptionalString(args, "namespace_id_or_path") ??
@@ -2191,7 +2198,7 @@ function getGitLabToolDefinitions() {
2191
2198
  name: "gitlab_verify_namespace",
2192
2199
  title: "Verify Namespace",
2193
2200
  description: "Verify if namespace path exists.",
2194
- mutating: false,
2201
+ capabilities: readCapabilities,
2195
2202
  inputSchema: {
2196
2203
  path: z.string().min(1)
2197
2204
  },
@@ -2201,7 +2208,7 @@ function getGitLabToolDefinitions() {
2201
2208
  name: "gitlab_get_users",
2202
2209
  title: "Get Users",
2203
2210
  description: "Search users.",
2204
- mutating: false,
2211
+ capabilities: readCapabilities,
2205
2212
  inputSchema: {
2206
2213
  username: optionalString,
2207
2214
  search: optionalString,
@@ -2216,7 +2223,7 @@ function getGitLabToolDefinitions() {
2216
2223
  name: "gitlab_list_events",
2217
2224
  title: "List Events",
2218
2225
  description: "List current user events.",
2219
- mutating: false,
2226
+ capabilities: readCapabilities,
2220
2227
  inputSchema: {
2221
2228
  action: optionalString,
2222
2229
  target_type: optionalString,
@@ -2232,9 +2239,9 @@ function getGitLabToolDefinitions() {
2232
2239
  name: "gitlab_get_project_events",
2233
2240
  title: "Get Project Events",
2234
2241
  description: "List events for a specific project.",
2235
- mutating: false,
2242
+ capabilities: readCapabilities,
2236
2243
  inputSchema: {
2237
- project_id: z.string().optional(),
2244
+ project_id: optionalProjectIdSchema,
2238
2245
  action: optionalString,
2239
2246
  target_type: optionalString,
2240
2247
  before: optionalString,
@@ -2250,9 +2257,9 @@ function getGitLabToolDefinitions() {
2250
2257
  name: "gitlab_upload_markdown",
2251
2258
  title: "Upload Markdown",
2252
2259
  description: "Upload markdown file/attachment to project.",
2253
- mutating: true,
2260
+ capabilities: writeCapabilities,
2254
2261
  inputSchema: {
2255
- project_id: z.string().optional(),
2262
+ project_id: optionalProjectIdSchema,
2256
2263
  content: optionalString,
2257
2264
  filename: z.string().default("upload.md"),
2258
2265
  file_path: optionalString
@@ -2274,10 +2281,10 @@ function getGitLabToolDefinitions() {
2274
2281
  name: "gitlab_download_attachment",
2275
2282
  title: "Download Attachment",
2276
2283
  description: "Download attachment by URL/path and return base64.",
2277
- mutating: false,
2284
+ capabilities: readCapabilities,
2278
2285
  inputSchema: {
2279
- project_id: z.string().optional(),
2280
- url_or_path: optionalString,
2286
+ project_id: optionalProjectIdSchema,
2287
+ url_or_path: optionalUrlOrPathSchema,
2281
2288
  secret: optionalString,
2282
2289
  filename: optionalString
2283
2290
  },
@@ -2316,7 +2323,7 @@ function getGitLabToolDefinitions() {
2316
2323
  name: "gitlab_execute_graphql_query",
2317
2324
  title: "Execute GraphQL Query",
2318
2325
  description: "Execute read-only GraphQL query.",
2319
- mutating: false,
2326
+ capabilities: readGraphqlCapabilities,
2320
2327
  inputSchema: {
2321
2328
  query: z.string().min(1),
2322
2329
  variables: optionalRecord
@@ -2333,7 +2340,7 @@ function getGitLabToolDefinitions() {
2333
2340
  name: "gitlab_execute_graphql_mutation",
2334
2341
  title: "Execute GraphQL Mutation",
2335
2342
  description: "Execute GraphQL mutation (disabled in read-only mode).",
2336
- mutating: true,
2343
+ capabilities: writeGraphqlCapabilities,
2337
2344
  inputSchema: {
2338
2345
  query: z.string().min(1),
2339
2346
  variables: optionalRecord
@@ -2350,7 +2357,7 @@ function getGitLabToolDefinitions() {
2350
2357
  name: "gitlab_execute_graphql",
2351
2358
  title: "Execute GraphQL (Compat)",
2352
2359
  description: "Backward-compatible GraphQL executor. Mutation payloads still honor read-only policy.",
2353
- mutating: false,
2360
+ capabilities: readGraphqlCapabilities,
2354
2361
  inputSchema: {
2355
2362
  query: z.string().min(1),
2356
2363
  variables: optionalRecord
@@ -2360,7 +2367,7 @@ function getGitLabToolDefinitions() {
2360
2367
  if (containsGraphqlMutation(query)) {
2361
2368
  context.policy.assertCanExecute({
2362
2369
  name: "gitlab_execute_graphql",
2363
- mutating: true
2370
+ capabilities: writeGraphqlCapabilities
2364
2371
  });
2365
2372
  }
2366
2373
  return context.gitlab.executeGraphql(query, getOptionalRecord(args, "variables"));