@zereight/mcp-gitlab 2.1.70 → 2.2.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.
Files changed (158) hide show
  1. package/README.ko.md +9 -5
  2. package/README.md +15 -11
  3. package/README.pt-BR.md +9 -5
  4. package/README.zh-CN.md +9 -5
  5. package/build/config.js +12 -4
  6. package/build/deprecated-env.js +63 -0
  7. package/build/index.js +430 -200
  8. package/build/oauth-device-flow.js +80 -0
  9. package/build/oauth.js +135 -18
  10. package/build/schemas.js +1 -1
  11. package/build/server/remote-http-stack.js +39 -0
  12. package/build/tools/discover-activation.js +38 -0
  13. package/build/tools/exposed-tools.js +35 -0
  14. package/build/tools/listed-tools.js +76 -0
  15. package/build/tools/registry.js +232 -63
  16. package/build/tools/tool-descriptions.js +3 -3
  17. package/build/tools/tool-profile.js +66 -0
  18. package/build/utils/compact-tool-allowlist.js +14 -0
  19. package/build/utils/logger.js +34 -12
  20. package/package.json +3 -3
  21. package/build/scripts/check-skill-sync.js +0 -143
  22. package/build/scripts/generate-server-card.js +0 -39
  23. package/build/scripts/generate-tool-coverage.js +0 -58
  24. package/build/scripts/generate-tool-docs.js +0 -430
  25. package/build/scripts/tool-coverage/coverage.js +0 -341
  26. package/build/scripts/tool-coverage/coverage.test.js +0 -142
  27. package/build/test/callback-proxy-tests.js +0 -321
  28. package/build/test/cli/args.test.js +0 -175
  29. package/build/test/cli/boolean-flags.test.js +0 -106
  30. package/build/test/cli/compact-mcp-result.test.js +0 -93
  31. package/build/test/cli/credentials.test.js +0 -153
  32. package/build/test/cli/exposure.test.js +0 -104
  33. package/build/test/cli/load-config-snapshot.js +0 -5
  34. package/build/test/cli/output.test.js +0 -74
  35. package/build/test/cli/replay-command.test.js +0 -37
  36. package/build/test/cli/router.test.js +0 -183
  37. package/build/test/client-pool-test.js +0 -109
  38. package/build/test/clients/client.js +0 -34
  39. package/build/test/clients/custom-header-client.js +0 -122
  40. package/build/test/clients/sse-client.js +0 -95
  41. package/build/test/clients/stdio-client.js +0 -113
  42. package/build/test/clients/streamable-http-client.js +0 -95
  43. package/build/test/config-allowed-groups.test.js +0 -97
  44. package/build/test/create-commit-actions.test.js +0 -102
  45. package/build/test/draft-note-schema.test.js +0 -44
  46. package/build/test/dynamic-api-url-allowlist.test.js +0 -121
  47. package/build/test/dynamic-api-url-test.js +0 -304
  48. package/build/test/dynamic-routing-tests.js +0 -495
  49. package/build/test/get-merge-request-discussion-schema.test.js +0 -30
  50. package/build/test/gitlab-api-tool-errors.test.js +0 -112
  51. package/build/test/gitlab-artifact-entry-schema.test.js +0 -44
  52. package/build/test/gitlab-diff-schema.test.js +0 -36
  53. package/build/test/gitlab-pipeline-schedule-schema.test.js +0 -32
  54. package/build/test/gitlab-tag-schema.test.js +0 -51
  55. package/build/test/group-milestone-schema.test.js +0 -45
  56. package/build/test/mcp-oauth-tests.js +0 -905
  57. package/build/test/mcp-server-name.test.js +0 -87
  58. package/build/test/merge-merge-request-schema.test.js +0 -75
  59. package/build/test/multi-server-test.js +0 -190
  60. package/build/test/no-proxy-integration-test.js +0 -183
  61. package/build/test/no-proxy-test.js +0 -149
  62. package/build/test/nullable-gitlab-response-fields.test.js +0 -37
  63. package/build/test/nullish-tool-arguments-schema.test.js +0 -118
  64. package/build/test/oauth-device-flow-tests.js +0 -450
  65. package/build/test/oauth-download-url.test.js +0 -157
  66. package/build/test/oauth-startup.test.js +0 -204
  67. package/build/test/oauth-tests.js +0 -428
  68. package/build/test/path-segment-encoding.test.js +0 -98
  69. package/build/test/remote-auth-simple-test.js +0 -277
  70. package/build/test/remote-auth-tests.js +0 -314
  71. package/build/test/response-masking.test.js +0 -445
  72. package/build/test/schema-tests.js +0 -1679
  73. package/build/test/server/metrics.test.js +0 -47
  74. package/build/test/server/request-helpers.test.js +0 -48
  75. package/build/test/server/version.test.js +0 -13
  76. package/build/test/sse-auth-guard.test.js +0 -96
  77. package/build/test/sse-session-limits.test.js +0 -273
  78. package/build/test/stateless/callback-proxy.test.js +0 -510
  79. package/build/test/stateless/client-id.test.js +0 -177
  80. package/build/test/stateless/codec.test.js +0 -328
  81. package/build/test/stateless/config-ttl.test.js +0 -149
  82. package/build/test/stateless/consumed-proxy-code-cache.test.js +0 -150
  83. package/build/test/stateless/session-id-integration.test.js +0 -675
  84. package/build/test/stateless/session-id.test.js +0 -157
  85. package/build/test/streamable-http-concurrent-session.test.js +0 -171
  86. package/build/test/streamable-http-dns-rebinding.test.js +0 -185
  87. package/build/test/streamable-http-sse-stream.test.js +0 -350
  88. package/build/test/streamable-http-static-token-auth.test.js +0 -157
  89. package/build/test/streamable-http-unauthenticated-discovery.test.js +0 -207
  90. package/build/test/test-all-transport-server.js +0 -255
  91. package/build/test/test-auth-retry.js +0 -195
  92. package/build/test/test-blank-filters.js +0 -156
  93. package/build/test/test-ci-catalog.js +0 -177
  94. package/build/test/test-ci-lint.js +0 -191
  95. package/build/test/test-ci-variables.js +0 -309
  96. package/build/test/test-create-repository.js +0 -120
  97. package/build/test/test-dependency-proxy.js +0 -195
  98. package/build/test/test-deployment-tools.js +0 -463
  99. package/build/test/test-download-attachment.js +0 -190
  100. package/build/test/test-dynamic-project-scope.js +0 -524
  101. package/build/test/test-empty-toolsets.js +0 -535
  102. package/build/test/test-get-file-blame.js +0 -145
  103. package/build/test/test-get-file-contents.js +0 -128
  104. package/build/test/test-geteffectiveprojectid.js +0 -804
  105. package/build/test/test-health-check.js +0 -115
  106. package/build/test/test-issue-description-patch.js +0 -256
  107. package/build/test/test-job-artifacts.js +0 -275
  108. package/build/test/test-json-schema.js +0 -166
  109. package/build/test/test-list-group-members.js +0 -150
  110. package/build/test/test-list-group-merge-requests.js +0 -165
  111. package/build/test/test-list-issues.js +0 -170
  112. package/build/test/test-list-merge-requests.js +0 -201
  113. package/build/test/test-list-milestones.js +0 -145
  114. package/build/test/test-list-project-members.js +0 -132
  115. package/build/test/test-merge-request-approval-state-tools.js +0 -213
  116. package/build/test/test-merge-request-approvals.js +0 -187
  117. package/build/test/test-merge-request-pipelines.js +0 -106
  118. package/build/test/test-mr-diffs-filter.js +0 -132
  119. package/build/test/test-mr-file-diffs.js +0 -251
  120. package/build/test/test-oauth-proxy-rate-limit.js +0 -133
  121. package/build/test/test-orbit.js +0 -155
  122. package/build/test/test-permission-mode.js +0 -424
  123. package/build/test/test-pipeline-schedules.js +0 -484
  124. package/build/test/test-protected-branches.js +0 -174
  125. package/build/test/test-remote-downloads.js +0 -510
  126. package/build/test/test-search-code.js +0 -275
  127. package/build/test/test-snippets.js +0 -735
  128. package/build/test/test-tags.js +0 -220
  129. package/build/test/test-todos.js +0 -195
  130. package/build/test/test-token-optimizations.js +0 -691
  131. package/build/test/test-toolset-filtering.js +0 -499
  132. package/build/test/test-update-issue-slim.js +0 -141
  133. package/build/test/test-update-project.js +0 -112
  134. package/build/test/test-upload-markdown.js +0 -206
  135. package/build/test/test-vulnerabilities.js +0 -399
  136. package/build/test/test-webhooks.js +0 -218
  137. package/build/test/tool-description-quality.test.js +0 -50
  138. package/build/test/utils/bulk-publish-options.test.js +0 -32
  139. package/build/test/utils/download-token.test.js +0 -35
  140. package/build/test/utils/forwarded-public-base-url.test.js +0 -46
  141. package/build/test/utils/gitlab-instance-version.test.js +0 -32
  142. package/build/test/utils/gitlab-version-gate.test.js +0 -74
  143. package/build/test/utils/graphql-query.test.js +0 -168
  144. package/build/test/utils/helpers-path.test.js +0 -104
  145. package/build/test/utils/jmespath-tool-result.test.js +0 -91
  146. package/build/test/utils/masking.test.js +0 -384
  147. package/build/test/utils/merge-request-position.test.js +0 -57
  148. package/build/test/utils/mock-gitlab-server.js +0 -614
  149. package/build/test/utils/proxy-client-ip.test.js +0 -28
  150. package/build/test/utils/redact-sensitive.test.js +0 -32
  151. package/build/test/utils/safe-redirect-fetch.test.js +0 -463
  152. package/build/test/utils/server-launcher.js +0 -231
  153. package/build/test/utils/tool-args.test.js +0 -210
  154. package/build/test/utils/url.test.js +0 -141
  155. package/build/test/utils/version-check.test.js +0 -239
  156. package/build/test/utils/wiki-title.test.js +0 -21
  157. package/build/test-note.js +0 -54
  158. package/build/test-resolve-issue-note.js +0 -127
@@ -1,5 +1,5 @@
1
1
  import { toJSONSchema } from "../utils/schema.js";
2
- import { USE_GITLAB_WIKI, USE_MILESTONE, USE_PIPELINE, SSE, STREAMABLE_HTTP, } from "../config.js";
2
+ import { USE_GITLAB_WIKI, USE_MILESTONE, USE_PIPELINE, SSE, STREAMABLE_HTTP } from "../config.js";
3
3
  import { getToolDescription } from "./tool-descriptions.js";
4
4
  import { ApproveMergeRequestSchema, BulkPublishDraftNotesSchema, CancelPipelineJobSchema, ErasePipelineJobSchema, CancelPipelineSchema, ConvertWorkItemTypeSchema, CreateBranchSchema, CreateDraftNoteSchema, CreateGroupSchema, CreateGroupWikiPageSchema, CreateIssueLinkSchema, CreateIssueNoteSchema, CreateIssueSchema, CreateIssueEmojiReactionSchema, CreateIssueNoteEmojiReactionSchema, ListIssueEmojiReactionsSchema, ListIssueNoteEmojiReactionsSchema, CreateLabelSchema, MarkAllTodosDoneSchema, ListTodosSchema, MarkTodoDoneSchema, CreateMergeRequestDiscussionNoteSchema, CreateMergeRequestEmojiReactionSchema, ListMergeRequestEmojiReactionsSchema, ListMergeRequestNoteEmojiReactionsSchema, CreateMergeRequestNoteSchema, CreateMergeRequestNoteEmojiReactionSchema, CreateMergeRequestSchema, CreateMergeRequestThreadSchema, CreateNoteSchema, CreateCommitStatusSchema, CreateOrUpdateFileSchema, CreatePipelineSchema, CreateProjectMilestoneSchema, CreateGroupMilestoneSchema, CreateReleaseEvidenceSchema, CreateReleaseSchema, CreateRepositorySchema, CreateTagSchema, CreateTimelineEventSchema, CreateWebhookSchema, CreateWikiPageSchema, CreateWorkItemNoteSchema, CreateWorkItemEmojiReactionSchema, CreateWorkItemNoteEmojiReactionSchema, ListWorkItemEmojiReactionsSchema, ListWorkItemNoteEmojiReactionsSchema, CreateWorkItemSchema, DeleteBranchSchema, GetProtectedBranchSchema, ListProtectedBranchesSchema, ProtectBranchSchema, UnprotectBranchSchema, UpdateDefaultBranchSchema, DeleteDraftNoteSchema, DeleteGroupMilestoneSchema, DeleteGroupWikiPageSchema, DeleteIssueLinkSchema, DeleteIssueSchema, DeleteIssueEmojiReactionSchema, DeleteIssueNoteEmojiReactionSchema, DeleteLabelSchema, DeleteMergeRequestDiscussionNoteSchema, DeleteMergeRequestNoteSchema, DeleteMergeRequestEmojiReactionSchema, DeleteMergeRequestNoteEmojiReactionSchema, DeleteProjectMilestoneSchema, DeleteReleaseSchema, DeleteTagSchema, DeleteWebhookSchema, DeleteWikiPageSchema, DeleteWorkItemEmojiReactionSchema, DeleteWorkItemNoteEmojiReactionSchema, DownloadAttachmentSchema, DownloadAttachmentRemoteSchema, DownloadJobArtifactsSchema, DownloadJobArtifactsRemoteSchema, DownloadReleaseAssetSchema, EditProjectMilestoneSchema, EditGroupMilestoneSchema, ExecuteGraphQLSchema, ForkRepositorySchema, HealthCheckSchema, GetBranchSchema, GetBranchDiffsSchema, GetCommitDiffSchema, GetCommitSchema, GetFileBlameSchema, GetDeploymentSchema, CreateDeploymentSchema, UpdateDeploymentSchema, DeploymentApprovalSchema, ListDeploymentMergeRequestsSchema, GetDraftNoteSchema, GetEnvironmentSchema, UpdateEnvironmentSchema, StopEnvironmentSchema, StopStaleEnvironmentsSchema, DeleteReviewAppEnvironmentsSchema, PipelineTriggerIdSchema, ListPipelineTriggersSchema, CreatePipelineTriggerSchema, UpdatePipelineTriggerSchema, TriggerPipelineSchema, GetFileContentsSchema, GetGroupWikiPageSchema, GetIssueLinkSchema, GetIssueSchema, GetJobArtifactFileSchema, GetLabelSchema, GetMergeRequestApprovalStateSchema, GetMergeRequestConflictsSchema, GetMergeRequestDiffsSchema, GetMergeRequestFileDiffSchema, GetMergeRequestDiscussionSchema, GetMergeRequestNoteSchema, GetMergeRequestNotesSchema, GetMergeRequestSchema, GetMergeRequestVersionSchema, GetMilestoneBurndownEventsSchema, GetMilestoneIssuesSchema, GetMilestoneMergeRequestsSchema, GetGroupMilestoneSchema, GetGroupMilestoneIssuesSchema, GetGroupMilestoneMergeRequestsSchema, GetGroupMilestoneBurndownEventsSchema, GetNamespaceSchema, GetPipelineJobOutputSchema, PipelineJobControlSchema, GetPipelineSchema, GetPipelineVariablesSchema, UpdatePipelineMetadataSchema, DeletePipelineSchema, PipelineReportSchema, WaitForPipelineSchema, WaitForPipelineJobSchema, PlayPipelineJobsSchema, GetProjectEventsSchema, GetProjectMilestoneSchema, GetProjectSchema, GetReleaseSchema, GetRepositoryTreeSchema, GetTagSchema, GetTagSignatureSchema, GetTimelineEventsSchema, GetUsersSchema, GetUserSchema, WhoAmISchema, GetWebhookEventSchema, GetWikiPageSchema, GetWorkItemSchema, ListBranchesSchema, ListCommitsSchema, ListCommitStatusesSchema, ListCustomFieldDefinitionsSchema, ListDeploymentsSchema, ListDraftNotesSchema, ListEnvironmentsSchema, ListEventsSchema, ListGroupIterationsSchema, ListGroupMilestonesSchema, ListGroupProjectsSchema, ListGroupWikiPagesSchema, ListIssueDiscussionsSchema, ListIssueLinksSchema, ListIssuesSchema, ListJobArtifactsSchema, ListLabelsSchema, ListMergeRequestChangedFilesSchema, ListMergeRequestDiffsSchema, ListMergeRequestDiscussionsSchema, ListMergeRequestPipelinesSchema, ListMergeRequestVersionsSchema, ListMergeRequestsSchema, ListGroupMergeRequestsSchema, ListNamespacesSchema, ListPipelineJobsSchema, ListPipelineTriggerJobsSchema, ValidateCiLintSchema, ValidateProjectCiLintSchema, ListCiCatalogResourcesSchema, GetCiCatalogResourceSchema, ListPipelinesSchema, ListPipelineSchedulesSchema, GetPipelineScheduleSchema, ListPipelineSchedulePipelinesSchema, CreatePipelineScheduleSchema, UpdatePipelineScheduleSchema, DeletePipelineScheduleSchema, PlayPipelineScheduleSchema, TakeOwnershipPipelineScheduleSchema, GetPipelineScheduleVariableSchema, CreatePipelineScheduleVariableSchema, UpdatePipelineScheduleVariableSchema, DeletePipelineScheduleVariableSchema, ListGroupMembersSchema, ListProjectMembersSchema, ListProjectMilestonesSchema, ListProjectsSchema, ListReleasesSchema, ListTagsSchema, ListWebhookEventsSchema, ListWebhooksSchema, ListWikiPagesSchema, ListWorkItemNotesSchema, ListWorkItemStatusesSchema, ListWorkItemsSchema, MarkdownUploadSchema, MarkdownUploadRemoteSchema, MergeMergeRequestSchema, MoveWorkItemSchema, MyIssuesSchema, OrbitQuerySchema, OrbitSchemaSchema, OrbitStatusSchema, OrbitToolsSchema, PlayPipelineJobSchema, PromoteProjectMilestoneSchema, PublishDraftNoteSchema, PushFilesSchema, ResolveMergeRequestThreadSchema, RetryPipelineJobSchema, RetryPipelineSchema, SearchCodeSchema, SearchGroupCodeSchema, SearchProjectCodeSchema, SearchRepositoriesSchema, ListSnippetsSchema, GetSnippetSchema, CreateSnippetSchema, UpdateSnippetSchema, DeleteSnippetSchema, UnapproveMergeRequestSchema, UpdateDraftNoteSchema, UpdateGroupWikiPageSchema, UpdateIssueNoteSchema, UpdateIssueSchema, UpdateIssueDescriptionPatchSchema, UpdateLabelSchema, UpdateProjectSchema, UpdateMergeRequestDiscussionNoteSchema, UpdateMergeRequestNoteSchema, UpdateMergeRequestSchema, UpdateReleaseSchema, UpdateWebhookSchema, UpdateWikiPageSchema, UpdateWorkItemSchema, VerifyNamespaceSchema, ListProjectVariablesSchema, GetProjectVariableSchema, CreateProjectVariableSchema, UpdateProjectVariableSchema, DeleteProjectVariableSchema, ListGroupVariablesSchema, GetGroupVariableSchema, CreateGroupVariableSchema, UpdateGroupVariableSchema, DeleteGroupVariableSchema, GetDependencyProxySettingsSchema, UpdateDependencyProxySettingsSchema, ListDependencyProxyBlobsSchema, PurgeDependencyProxyCacheSchema, ListProjectVulnerabilitiesSchema, GetVulnerabilitySchema, DismissVulnerabilitySchema, ConfirmVulnerabilitySchema, } from "../schemas.js";
5
5
  const IS_REMOTE = SSE || STREAMABLE_HTTP;
@@ -132,27 +132,27 @@ export const allTools = [
132
132
  },
133
133
  {
134
134
  name: "get_merge_request",
135
- description: "Get details of a merge request (mergeRequestIid or branchName required). Set include_summaries=true for deployment/commit/approval summaries",
135
+ description: "Get details of a merge request (merge_request_iid or source_branch required). Set include_summaries=true for deployment/commit/approval summaries",
136
136
  inputSchema: toJSONSchema(GetMergeRequestSchema),
137
137
  },
138
138
  {
139
139
  name: "get_merge_request_diffs",
140
- description: "Get the changes/diffs of a merge request (mergeRequestIid or branchName required)",
140
+ description: "Get the changes/diffs of a merge request (merge_request_iid or source_branch required)",
141
141
  inputSchema: toJSONSchema(GetMergeRequestDiffsSchema),
142
142
  },
143
143
  {
144
144
  name: "list_merge_request_changed_files",
145
- description: "List changed file paths in a merge request without diff content (mergeRequestIid or branchName required)",
145
+ description: "List changed file paths in a merge request without diff content (merge_request_iid or source_branch required)",
146
146
  inputSchema: toJSONSchema(ListMergeRequestChangedFilesSchema),
147
147
  },
148
148
  {
149
149
  name: "list_merge_request_diffs",
150
- description: "List merge request diffs with pagination (mergeRequestIid or branchName required)",
150
+ description: "List merge request diffs with pagination (merge_request_iid or source_branch required)",
151
151
  inputSchema: toJSONSchema(ListMergeRequestDiffsSchema),
152
152
  },
153
153
  {
154
154
  name: "get_merge_request_file_diff",
155
- description: "Get diffs for specific files from a merge request (mergeRequestIid or branchName required)",
155
+ description: "Get diffs for specific files from a merge request (merge_request_iid or source_branch required)",
156
156
  inputSchema: toJSONSchema(GetMergeRequestFileDiffSchema),
157
157
  },
158
158
  {
@@ -172,7 +172,7 @@ export const allTools = [
172
172
  },
173
173
  {
174
174
  name: "update_merge_request",
175
- description: "Update a merge request (mergeRequestIid or branchName required)",
175
+ description: "Update a merge request (merge_request_iid or source_branch required)",
176
176
  inputSchema: toJSONSchema(UpdateMergeRequestSchema),
177
177
  },
178
178
  {
@@ -359,7 +359,7 @@ export const allTools = [
359
359
  },
360
360
  {
361
361
  name: "get_issue",
362
- description: "Get details of a specific issue. Returns a slim milestone by default; set full_response=true for the complete milestone object",
362
+ description: "Get details of a specific issue. Returns the issue with a slim nested milestone by default; set full_response=true for the complete milestone object",
363
363
  inputSchema: toJSONSchema(GetIssueSchema),
364
364
  },
365
365
  {
@@ -559,10 +559,26 @@ export const allTools = [
559
559
  description: "Get variables configured for a pipeline",
560
560
  inputSchema: toJSONSchema(GetPipelineVariablesSchema),
561
561
  },
562
- { name: "get_pipeline_test_report", description: "Get pipeline test report", inputSchema: toJSONSchema(PipelineReportSchema) },
563
- { name: "get_pipeline_test_report_summary", description: "Get pipeline test report summary", inputSchema: toJSONSchema(PipelineReportSchema) },
564
- { name: "delete_pipeline", description: "Delete a pipeline. Requires the project Owner role, cannot be undone, and does not automatically delete child pipelines.", inputSchema: toJSONSchema(DeletePipelineSchema) },
565
- { name: "update_pipeline_metadata", description: "Update pipeline metadata", inputSchema: toJSONSchema(UpdatePipelineMetadataSchema) },
562
+ {
563
+ name: "get_pipeline_test_report",
564
+ description: "Get pipeline test report",
565
+ inputSchema: toJSONSchema(PipelineReportSchema),
566
+ },
567
+ {
568
+ name: "get_pipeline_test_report_summary",
569
+ description: "Get pipeline test report summary",
570
+ inputSchema: toJSONSchema(PipelineReportSchema),
571
+ },
572
+ {
573
+ name: "delete_pipeline",
574
+ description: "Delete a pipeline. Requires the project Owner role, cannot be undone, and does not automatically delete child pipelines.",
575
+ inputSchema: toJSONSchema(DeletePipelineSchema),
576
+ },
577
+ {
578
+ name: "update_pipeline_metadata",
579
+ description: "Update pipeline metadata",
580
+ inputSchema: toJSONSchema(UpdatePipelineMetadataSchema),
581
+ },
566
582
  {
567
583
  name: "list_deployments",
568
584
  description: "List deployments with filtering options",
@@ -573,11 +589,31 @@ export const allTools = [
573
589
  description: "Get deployment details, including approval_summary, approvals, and pending_approval_count when GitLab provides them",
574
590
  inputSchema: toJSONSchema(GetDeploymentSchema),
575
591
  },
576
- { name: "create_deployment", description: "Create a deployment", inputSchema: toJSONSchema(CreateDeploymentSchema) },
577
- { name: "update_deployment", description: "Update a deployment status", inputSchema: toJSONSchema(UpdateDeploymentSchema) },
578
- { name: "delete_deployment", description: "Delete a deployment", inputSchema: toJSONSchema(GetDeploymentSchema) },
579
- { name: "list_deployment_merge_requests", description: "List merge requests shipped with a deployment", inputSchema: toJSONSchema(ListDeploymentMergeRequestsSchema) },
580
- { name: "approve_deployment", description: "Approve or reject a protected-environment deployment", inputSchema: toJSONSchema(DeploymentApprovalSchema) },
592
+ {
593
+ name: "create_deployment",
594
+ description: "Create a deployment",
595
+ inputSchema: toJSONSchema(CreateDeploymentSchema),
596
+ },
597
+ {
598
+ name: "update_deployment",
599
+ description: "Update a deployment status",
600
+ inputSchema: toJSONSchema(UpdateDeploymentSchema),
601
+ },
602
+ {
603
+ name: "delete_deployment",
604
+ description: "Delete a deployment",
605
+ inputSchema: toJSONSchema(GetDeploymentSchema),
606
+ },
607
+ {
608
+ name: "list_deployment_merge_requests",
609
+ description: "List merge requests shipped with a deployment",
610
+ inputSchema: toJSONSchema(ListDeploymentMergeRequestsSchema),
611
+ },
612
+ {
613
+ name: "approve_deployment",
614
+ description: "Approve or reject a protected-environment deployment",
615
+ inputSchema: toJSONSchema(DeploymentApprovalSchema),
616
+ },
581
617
  {
582
618
  name: "list_environments",
583
619
  description: "List environments in a project",
@@ -588,17 +624,61 @@ export const allTools = [
588
624
  description: "Get details of a specific environment",
589
625
  inputSchema: toJSONSchema(GetEnvironmentSchema),
590
626
  },
591
- { name: "update_environment", description: "Update an environment", inputSchema: toJSONSchema(UpdateEnvironmentSchema) },
592
- { name: "delete_environment", description: "Delete a stopped environment", inputSchema: toJSONSchema(GetEnvironmentSchema) },
593
- { name: "stop_environment", description: "Stop an environment", inputSchema: toJSONSchema(StopEnvironmentSchema) },
594
- { name: "stop_stale_environments", description: "Stop eligible stale environments; protected environments are excluded and environments are stopped, not deleted", inputSchema: toJSONSchema(StopStaleEnvironmentsSchema) },
595
- { name: "delete_review_app_environments", description: "Schedule deletion of stopped review-app environments one week later; dry_run defaults to true and actual scheduling requires dry_run=false", inputSchema: toJSONSchema(DeleteReviewAppEnvironmentsSchema) },
596
- { name: "list_pipeline_triggers", description: "List project pipeline trigger tokens", inputSchema: toJSONSchema(ListPipelineTriggersSchema) },
597
- { name: "get_pipeline_trigger", description: "Get a project pipeline trigger", inputSchema: toJSONSchema(PipelineTriggerIdSchema) },
598
- { name: "create_pipeline_trigger", description: "Create a project pipeline trigger", inputSchema: toJSONSchema(CreatePipelineTriggerSchema) },
599
- { name: "update_pipeline_trigger", description: "Update a project pipeline trigger", inputSchema: toJSONSchema(UpdatePipelineTriggerSchema) },
600
- { name: "delete_pipeline_trigger", description: "Delete a project pipeline trigger", inputSchema: toJSONSchema(PipelineTriggerIdSchema) },
601
- { name: "trigger_pipeline", description: "Trigger a pipeline with a pipeline trigger token", inputSchema: toJSONSchema(TriggerPipelineSchema) },
627
+ {
628
+ name: "update_environment",
629
+ description: "Update an environment",
630
+ inputSchema: toJSONSchema(UpdateEnvironmentSchema),
631
+ },
632
+ {
633
+ name: "delete_environment",
634
+ description: "Delete a stopped environment",
635
+ inputSchema: toJSONSchema(GetEnvironmentSchema),
636
+ },
637
+ {
638
+ name: "stop_environment",
639
+ description: "Stop an environment",
640
+ inputSchema: toJSONSchema(StopEnvironmentSchema),
641
+ },
642
+ {
643
+ name: "stop_stale_environments",
644
+ description: "Stop eligible stale environments; protected environments are excluded and environments are stopped, not deleted",
645
+ inputSchema: toJSONSchema(StopStaleEnvironmentsSchema),
646
+ },
647
+ {
648
+ name: "delete_review_app_environments",
649
+ description: "Schedule deletion of stopped review-app environments one week later; dry_run defaults to true and actual scheduling requires dry_run=false",
650
+ inputSchema: toJSONSchema(DeleteReviewAppEnvironmentsSchema),
651
+ },
652
+ {
653
+ name: "list_pipeline_triggers",
654
+ description: "List project pipeline trigger tokens",
655
+ inputSchema: toJSONSchema(ListPipelineTriggersSchema),
656
+ },
657
+ {
658
+ name: "get_pipeline_trigger",
659
+ description: "Get a project pipeline trigger",
660
+ inputSchema: toJSONSchema(PipelineTriggerIdSchema),
661
+ },
662
+ {
663
+ name: "create_pipeline_trigger",
664
+ description: "Create a project pipeline trigger",
665
+ inputSchema: toJSONSchema(CreatePipelineTriggerSchema),
666
+ },
667
+ {
668
+ name: "update_pipeline_trigger",
669
+ description: "Update a project pipeline trigger",
670
+ inputSchema: toJSONSchema(UpdatePipelineTriggerSchema),
671
+ },
672
+ {
673
+ name: "delete_pipeline_trigger",
674
+ description: "Delete a project pipeline trigger",
675
+ inputSchema: toJSONSchema(PipelineTriggerIdSchema),
676
+ },
677
+ {
678
+ name: "trigger_pipeline",
679
+ description: "Trigger a pipeline with a pipeline trigger token",
680
+ inputSchema: toJSONSchema(TriggerPipelineSchema),
681
+ },
602
682
  {
603
683
  name: "list_pipeline_jobs",
604
684
  description: "List all jobs in a specific pipeline",
@@ -734,9 +814,21 @@ export const allTools = [
734
814
  description: "Cancel a running pipeline job",
735
815
  inputSchema: toJSONSchema(CancelPipelineJobSchema),
736
816
  },
737
- { name: "erase_pipeline_job", description: "Erase a pipeline job log and artifacts", inputSchema: toJSONSchema(ErasePipelineJobSchema) },
738
- { name: "wait_for_pipeline", description: "Wait for a pipeline to reach a terminal status", inputSchema: toJSONSchema(WaitForPipelineSchema) },
739
- { name: "wait_for_job", description: "Wait for a job to reach a terminal status", inputSchema: toJSONSchema(WaitForPipelineJobSchema) },
817
+ {
818
+ name: "erase_pipeline_job",
819
+ description: "Erase a pipeline job log and artifacts",
820
+ inputSchema: toJSONSchema(ErasePipelineJobSchema),
821
+ },
822
+ {
823
+ name: "wait_for_pipeline",
824
+ description: "Wait for a pipeline to reach a terminal status",
825
+ inputSchema: toJSONSchema(WaitForPipelineSchema),
826
+ },
827
+ {
828
+ name: "wait_for_job",
829
+ description: "Wait for a job to reach a terminal status",
830
+ inputSchema: toJSONSchema(WaitForPipelineJobSchema),
831
+ },
740
832
  {
741
833
  name: "list_job_artifacts",
742
834
  description: "List artifact files in a job's archive",
@@ -1432,6 +1524,12 @@ export const readOnlyTools = new Set([
1432
1524
  "orbit_get_status",
1433
1525
  "orbit_list_tools",
1434
1526
  ]);
1527
+ // Stays in readOnlyTools so readonly mode can still run queries, but mutations
1528
+ // are allowed in other permission modes and rejected only at call time.
1529
+ const MIXED_ACCESS_TOOLS = new Set(["execute_graphql"]);
1530
+ export function advertisesReadOnly(toolName) {
1531
+ return readOnlyTools.has(toolName) && !MIXED_ACCESS_TOOLS.has(toolName);
1532
+ }
1435
1533
  // Define which tools are destructive (data loss potential)
1436
1534
  export const destructiveTools = new Set([
1437
1535
  "delete_pipeline",
@@ -1620,8 +1718,52 @@ export const pipelineToolNames = new Set([
1620
1718
  ]);
1621
1719
  export const TOOLSET_DEFINITIONS = [
1622
1720
  {
1623
- id: "merge_requests",
1721
+ id: "core",
1624
1722
  isDefault: true,
1723
+ tools: new Set([
1724
+ "list_merge_requests",
1725
+ "get_merge_request",
1726
+ "get_merge_request_approval_state",
1727
+ "list_merge_request_changed_files",
1728
+ "get_merge_request_file_diff",
1729
+ "list_merge_request_diffs",
1730
+ "get_merge_request_diffs",
1731
+ "mr_discussions",
1732
+ "get_merge_request_discussion",
1733
+ "get_merge_request_note",
1734
+ "get_merge_request_notes",
1735
+ "create_merge_request",
1736
+ "create_merge_request_thread",
1737
+ "resolve_merge_request_thread",
1738
+ "update_merge_request",
1739
+ "list_issues",
1740
+ "my_issues",
1741
+ "get_issue",
1742
+ "create_issue",
1743
+ "update_issue",
1744
+ "create_issue_note",
1745
+ "list_issue_discussions",
1746
+ "update_issue_description_patch",
1747
+ "get_file_contents",
1748
+ "get_repository_tree",
1749
+ "search_repositories",
1750
+ "get_branch",
1751
+ "list_branches",
1752
+ "list_commits",
1753
+ "get_commit",
1754
+ "get_commit_diff",
1755
+ "get_file_blame",
1756
+ "get_project",
1757
+ "list_projects",
1758
+ "list_project_members",
1759
+ "list_labels",
1760
+ "whoami",
1761
+ "health_check",
1762
+ ]),
1763
+ },
1764
+ {
1765
+ id: "merge_requests",
1766
+ isDefault: false,
1625
1767
  tools: new Set([
1626
1768
  "merge_merge_request",
1627
1769
  "approve_merge_request",
@@ -1672,7 +1814,7 @@ export const TOOLSET_DEFINITIONS = [
1672
1814
  },
1673
1815
  {
1674
1816
  id: "issues",
1675
- isDefault: true,
1817
+ isDefault: false,
1676
1818
  tools: new Set([
1677
1819
  "create_issue",
1678
1820
  "list_issues",
@@ -1702,7 +1844,7 @@ export const TOOLSET_DEFINITIONS = [
1702
1844
  },
1703
1845
  {
1704
1846
  id: "repositories",
1705
- isDefault: true,
1847
+ isDefault: false,
1706
1848
  tools: new Set([
1707
1849
  "search_repositories",
1708
1850
  "create_repository",
@@ -1715,7 +1857,7 @@ export const TOOLSET_DEFINITIONS = [
1715
1857
  },
1716
1858
  {
1717
1859
  id: "branches",
1718
- isDefault: true,
1860
+ isDefault: false,
1719
1861
  tools: new Set([
1720
1862
  "create_branch",
1721
1863
  "get_branch",
@@ -1736,7 +1878,7 @@ export const TOOLSET_DEFINITIONS = [
1736
1878
  },
1737
1879
  {
1738
1880
  id: "projects",
1739
- isDefault: true,
1881
+ isDefault: false,
1740
1882
  tools: new Set([
1741
1883
  "get_project",
1742
1884
  "list_projects",
@@ -1753,18 +1895,12 @@ export const TOOLSET_DEFINITIONS = [
1753
1895
  },
1754
1896
  {
1755
1897
  id: "labels",
1756
- isDefault: true,
1757
- tools: new Set([
1758
- "list_labels",
1759
- "get_label",
1760
- "create_label",
1761
- "update_label",
1762
- "delete_label",
1763
- ]),
1898
+ isDefault: false,
1899
+ tools: new Set(["list_labels", "get_label", "create_label", "update_label", "delete_label"]),
1764
1900
  },
1765
1901
  {
1766
1902
  id: "ci",
1767
- isDefault: true,
1903
+ isDefault: false,
1768
1904
  tools: new Set([
1769
1905
  "validate_ci_lint",
1770
1906
  "validate_project_ci_lint",
@@ -1774,7 +1910,7 @@ export const TOOLSET_DEFINITIONS = [
1774
1910
  },
1775
1911
  {
1776
1912
  id: "groups",
1777
- isDefault: true,
1913
+ isDefault: false,
1778
1914
  tools: new Set(["create_group"]),
1779
1915
  },
1780
1916
  {
@@ -1894,13 +2030,7 @@ export const TOOLSET_DEFINITIONS = [
1894
2030
  {
1895
2031
  id: "tags",
1896
2032
  isDefault: false,
1897
- tools: new Set([
1898
- "list_tags",
1899
- "get_tag",
1900
- "create_tag",
1901
- "delete_tag",
1902
- "get_tag_signature",
1903
- ]),
2033
+ tools: new Set(["list_tags", "get_tag", "create_tag", "delete_tag", "get_tag_signature"]),
1904
2034
  },
1905
2035
  {
1906
2036
  id: "snippets",
@@ -1915,7 +2045,7 @@ export const TOOLSET_DEFINITIONS = [
1915
2045
  },
1916
2046
  {
1917
2047
  id: "users",
1918
- isDefault: true,
2048
+ isDefault: false,
1919
2049
  tools: new Set([
1920
2050
  "get_users",
1921
2051
  "get_user",
@@ -2009,18 +2139,29 @@ export const TOOLSET_DEFINITIONS = [
2009
2139
  tools: new Set(["orbit_query", "orbit_get_schema", "orbit_get_status", "orbit_list_tools"]),
2010
2140
  },
2011
2141
  ];
2012
- // Derived lookup: tool name → toolset ID
2013
- export const TOOLSET_BY_TOOL_NAME = new Map();
2142
+ // Derived lookup: tool name → toolset IDs. Most tools belong to one category.
2143
+ // The default `core` toolset intentionally overlaps with the full opt-in
2144
+ // categories so users get a small starter surface without losing the ability
2145
+ // to enable complete categories later.
2146
+ export const TOOLSETS_BY_TOOL_NAME = new Map();
2014
2147
  for (const def of TOOLSET_DEFINITIONS) {
2015
2148
  for (const tool of def.tools) {
2016
- if (TOOLSET_BY_TOOL_NAME.has(tool)) {
2017
- console.warn(`Tool "${tool}" is defined in multiple toolsets: "${TOOLSET_BY_TOOL_NAME.get(tool)}" and "${def.id}"`);
2018
- }
2019
- TOOLSET_BY_TOOL_NAME.set(tool, def.id);
2149
+ const toolsets = TOOLSETS_BY_TOOL_NAME.get(tool) ?? new Set();
2150
+ toolsets.add(def.id);
2151
+ TOOLSETS_BY_TOOL_NAME.set(tool, toolsets);
2020
2152
  }
2021
2153
  }
2022
2154
  export const DEFAULT_TOOLSET_IDS = new Set(TOOLSET_DEFINITIONS.filter(d => d.isDefault).map(d => d.id));
2023
2155
  export const ALL_TOOLSET_IDS = new Set(TOOLSET_DEFINITIONS.map(d => d.id));
2156
+ /**
2157
+ * Smallest toolset containing the tool, i.e. the cheapest category to activate for it.
2158
+ * Returns undefined for tools outside every toolset (e.g. `execute_graphql`) and unknown names.
2159
+ */
2160
+ export function findSmallestToolsetForTool(toolName) {
2161
+ const candidates = TOOLSET_DEFINITIONS.filter(d => d.tools.has(toolName));
2162
+ const smallest = candidates.reduce((best, d) => (best === undefined || d.tools.size < best.tools.size ? d : best), undefined);
2163
+ return smallest?.id;
2164
+ }
2024
2165
  // Update discover_tools description with all known categories (must be after TOOLSET_DEFINITIONS)
2025
2166
  const discoverTool = allTools.find(t => t.name === "discover_tools");
2026
2167
  if (discoverTool) {
@@ -2080,9 +2221,37 @@ export function buildFeatureFlagOverrides() {
2080
2221
  return overrides;
2081
2222
  }
2082
2223
  export function isToolInEnabledToolset(toolName, enabledToolsets) {
2083
- const toolsetId = TOOLSET_BY_TOOL_NAME.get(toolName);
2224
+ const toolsetIds = TOOLSETS_BY_TOOL_NAME.get(toolName);
2084
2225
  // Tools not in any toolset (e.g. execute_graphql) are excluded by default
2085
- if (toolsetId === undefined)
2226
+ if (toolsetIds === undefined)
2086
2227
  return false;
2087
- return enabledToolsets.has(toolsetId);
2228
+ for (const toolsetId of toolsetIds) {
2229
+ if (enabledToolsets.has(toolsetId))
2230
+ return true;
2231
+ }
2232
+ return false;
2233
+ }
2234
+ /**
2235
+ * True only when every tool in the set is already exposed.
2236
+ * Partial overlap (for example `core` sharing names with `merge_requests`) is not active.
2237
+ * `isExcluded` covers tools the caller will not list; those do not keep the toolset inactive.
2238
+ * An empty set is fully active, matching `Array.prototype.every`.
2239
+ */
2240
+ export function isToolsetFullyActive(tools, currentToolNames, isExcluded) {
2241
+ for (const toolName of tools) {
2242
+ if (currentToolNames.has(toolName) || isExcluded?.(toolName)) {
2243
+ continue;
2244
+ }
2245
+ return false;
2246
+ }
2247
+ return true;
2248
+ }
2249
+ /** Category listing returned by `discover_tools` when no category argument is given. */
2250
+ export function listDiscoverableCategories(currentToolNames, isExcluded) {
2251
+ return TOOLSET_DEFINITIONS.map(def => ({
2252
+ id: def.id,
2253
+ toolCount: def.tools.size,
2254
+ active: isToolsetFullyActive(def.tools, currentToolNames, isExcluded),
2255
+ isDefault: def.isDefault,
2256
+ }));
2088
2257
  }
@@ -9,7 +9,7 @@ const TOOL_GUIDANCE = {
9
9
  push_files: "Use this to commit several file changes atomically; use `create_or_update_file` when only one path is involved. Each file defaults to action `create`; optional per-file `action` (create/update/delete/move) and `encoding` (text/base64) are additive. `GITLAB_PERMISSION_MODE=modify` rejects `delete` and `move`. The operation writes repository history on the selected branch, requires repository write permission, and returns the commit result or a validation, conflict, or protected-branch error.",
10
10
  create_issue: "Use this to open a new issue; use `update_issue` for an existing issue and `create_issue_note` to add discussion without changing issue fields. The operation creates remote project data, requires issue creation permission, and returns the new issue or a validation, permission, or duplicate-related error.",
11
11
  list_issues: "Use this for issue management: list GitLab issues, optionally scoped with `project_id`. Use `get_issue` when the issue iid is already known and `my_issues` for issues assigned to the current user. It is read-only and paginated, requires issue read permission, and returns issue records or GitLab errors for invalid identifiers, missing resources, or rate limits.",
12
- my_issues: "Use this for issue management: list issues assigned to the authenticated user. Use `list_issues` for project-wide or author-scoped listing and `get_issue` for one issue. It is read-only and paginated, requires authentication, and returns assigned issue records or permission/rate-limit errors.",
12
+ my_issues: "Use this for issue management: list issues assigned to the authenticated user. Use `list_issues` for project-wide or author-scoped listing and `get_issue` for one issue. Resolving the current user requires classic read_user or fine-grained User:Read. It is read-only and paginated, requires authentication, and returns assigned issue records or permission/rate-limit errors.",
13
13
  get_issue: "Use this for issue management: inspect one issue's fields; use `list_issues` or `my_issues` to discover issues first. It is read-only, requires issue read permission, and returns the issue or an error when the identifier is invalid, the issue is missing, or access is denied.",
14
14
  create_merge_request: "Use this to open a new merge request from an existing source branch to a target branch; use `update_merge_request` after it exists. The operation creates remote review state, requires project access, and returns the new merge request or a validation, permission, branch, or duplicate-related error.",
15
15
  fork_repository: "Use this to create a copy of an existing project in the current user's namespace or a permitted namespace; use `search_repositories` or `get_project` to inspect projects without copying them. The operation creates a new project, requires fork permission, and returns the forked project or a namespace/permission error.",
@@ -36,8 +36,8 @@ const TOOL_GUIDANCE = {
36
36
  download_attachment: "Use this to retrieve a previously uploaded project attachment; remote mode returns inline base64 for images or a download URL, while local mode can save to a path. It is read-only with respect to GitLab, requires project access, and returns the file content or an attachment/permission error.",
37
37
  execute_graphql: "Use this only when a supported GitLab REST tool does not cover the requested operation; prefer a typed tool when one exists. The query is sent directly to GitLab and can include mutations when permission allows, so callers must treat it as potentially state-changing and handle GraphQL errors in the returned response.",
38
38
  discover_tools: "Use this when a needed opt-in category is not currently exposed; omit `category` to inspect available categories, then call it with a category to activate that group for the current session. It changes only the session's tool registry, returns the active-tool summary, and does not change GitLab data.",
39
- health_check: "Use this to verify server connectivity and authentication before making GitLab requests; use `whoami` when the authenticated user's identity is the goal. It does not mutate GitLab state and returns server/authentication status plus GitLab version details when available.",
40
- whoami: "Use this to identify the authenticated GitLab user; use `get_user` or `get_users` when looking up another user. It is read-only and returns the current user profile, while missing credentials or GitLab permission failures are reported as errors.",
39
+ health_check: "Use this to verify server connectivity and authentication before making GitLab requests; use `whoami` when the authenticated user's identity is the goal. A 403 from GET /user with an insufficient_scope error means the token is accepted but User API scope is missing (read_user or fine-grained User:Read); the check stays ok, sets user_api_warning, and omits version metadata. Rate-limit and authentication-ban 403 responses stay unauthenticated. It does not mutate GitLab state and returns server/authentication status plus GitLab version details when available.",
40
+ whoami: "Use this to identify the authenticated GitLab user; use `get_user` or `get_users` when looking up another user. It requires classic read_user or fine-grained User:Read. It is read-only and returns the current user profile, while missing credentials or GitLab permission failures are reported as errors.",
41
41
  list_pipeline_schedules: "Use this to survey a project's scheduled pipelines and their `cron`, `next_run_at`, and `active` state, optionally narrowed with `scope` to `active` or `inactive`; use `list_pipelines` for pipelines that already ran and `get_pipeline_schedule` when the schedule ID is known. The list response carries no `variables` — call `get_pipeline_schedule` for those — and includes `inputs` only for Maintainers, Owners, or the schedule owner. It is read-only and paginated, requires project access, and returns schedule records or an error when the project is missing or access is denied.",
42
42
  get_pipeline_schedule: "Use this to inspect one schedule's cron, owner, last pipeline, variables, and inputs; use `list_pipeline_schedules` to discover schedule IDs and `list_pipeline_schedule_pipelines` for the pipelines it produced. It is read-only, returns `variables` and `inputs` only to Maintainers, Owners, or the schedule owner, and returns the schedule or an error when the schedule is missing or access is denied.",
43
43
  list_pipeline_schedule_pipelines: "Use this to review the pipelines a schedule has actually triggered, for example to see whether the nightly run succeeded; use `get_pipeline` for one pipeline's full detail and `list_pipelines` for project-wide filtering. Narrow the result with `scope`, `status`, `sort`, and the `created_*` / `updated_*` date bounds. It is read-only and paginated, requires project access, and returns pipeline records or an error when the schedule is missing or access is denied.",
@@ -0,0 +1,66 @@
1
+ export const TOOL_PROFILES = ["full", "slim"];
2
+ /**
3
+ * Tools omitted from the initial list when `GITLAB_TOOL_PROFILE=slim` and
4
+ * `GITLAB_TOOLSETS` is unset. `discover_tools` does not add them back.
5
+ * `GITLAB_TOOLS` can still name one explicitly.
6
+ */
7
+ export const SLIM_PROFILE_EXCLUDED_TOOLS = new Set([
8
+ "get_draft_note",
9
+ "list_draft_notes",
10
+ "create_draft_note",
11
+ "update_draft_note",
12
+ "delete_draft_note",
13
+ "publish_draft_note",
14
+ "bulk_publish_draft_notes",
15
+ "list_merge_request_emoji_reactions",
16
+ "list_merge_request_note_emoji_reactions",
17
+ "create_merge_request_emoji_reaction",
18
+ "delete_merge_request_emoji_reaction",
19
+ "create_merge_request_note_emoji_reaction",
20
+ "delete_merge_request_note_emoji_reaction",
21
+ "list_issue_emoji_reactions",
22
+ "list_issue_note_emoji_reactions",
23
+ "create_issue_emoji_reaction",
24
+ "delete_issue_emoji_reaction",
25
+ "create_issue_note_emoji_reaction",
26
+ "delete_issue_note_emoji_reaction",
27
+ "list_labels",
28
+ "get_label",
29
+ "create_label",
30
+ "update_label",
31
+ "delete_label",
32
+ "validate_ci_lint",
33
+ "validate_project_ci_lint",
34
+ "list_ci_catalog_resources",
35
+ "get_ci_catalog_resource",
36
+ "create_group",
37
+ ]);
38
+ export function parseToolProfile(raw) {
39
+ if (raw === undefined) {
40
+ return "full";
41
+ }
42
+ const normalized = raw.trim().toLowerCase();
43
+ if (normalized === "" || normalized === "full") {
44
+ return "full";
45
+ }
46
+ if (normalized === "slim") {
47
+ return "slim";
48
+ }
49
+ throw new Error(`Invalid GITLAB_TOOL_PROFILE: "${raw}". Expected one of: ${TOOL_PROFILES.join(", ")}`);
50
+ }
51
+ /** Slim applies only when the caller did not pin an explicit toolset list. */
52
+ export function shouldApplySlimToolProfile(profile, toolsetsRaw) {
53
+ if (profile !== "slim") {
54
+ return false;
55
+ }
56
+ return toolsetsRaw === undefined || toolsetsRaw.trim() === "";
57
+ }
58
+ export function isExcludedBySlimProfile(toolName, applySlimProfile, explicitlyEnabledTools) {
59
+ if (!applySlimProfile) {
60
+ return false;
61
+ }
62
+ if (explicitlyEnabledTools.has(toolName)) {
63
+ return false;
64
+ }
65
+ return SLIM_PROFILE_EXCLUDED_TOOLS.has(toolName);
66
+ }
@@ -0,0 +1,14 @@
1
+ /** Tool names that compact oversized replies even when global compact mode is off. */
2
+ export function parseCompactToolAllowlist(raw) {
3
+ if (raw === undefined || raw.trim() === "") {
4
+ return new Set();
5
+ }
6
+ const names = raw
7
+ .split(",")
8
+ .map(name => name.trim())
9
+ .filter(name => name.length > 0);
10
+ return new Set(names);
11
+ }
12
+ export function shouldCompactToolResult(toolName, globalEnabled, allowlist) {
13
+ return globalEnabled || allowlist.has(toolName);
14
+ }
@@ -1,4 +1,6 @@
1
+ import { createRequire } from "node:module";
1
2
  import { pino } from "pino";
3
+ const require = createRequire(import.meta.url);
2
4
  const REDACT_PATHS = [
3
5
  "token",
4
6
  "*.token",
@@ -23,6 +25,31 @@ const REDACT_PATHS = [
23
25
  "arguments.approval_password",
24
26
  "params.arguments.approval_password",
25
27
  ];
28
+ function isPrettyFactory(value) {
29
+ return typeof value === "function";
30
+ }
31
+ function isPrettyModule(value) {
32
+ if (typeof value !== "object" || value === null || !("default" in value)) {
33
+ return false;
34
+ }
35
+ return isPrettyFactory(value.default);
36
+ }
37
+ /**
38
+ * Pretty-print in process. The worker transport has the same text format, but
39
+ * it spawns a thread on every logger, including stdio MCP startup.
40
+ * LOG_FORMAT=json still skips pino-pretty entirely.
41
+ */
42
+ function createPrettyStream() {
43
+ const loaded = require("pino-pretty");
44
+ const options = { colorize: true, levelFirst: true, destination: 2 };
45
+ if (isPrettyFactory(loaded)) {
46
+ return loaded(options);
47
+ }
48
+ if (isPrettyModule(loaded)) {
49
+ return loaded.default(options);
50
+ }
51
+ throw new Error("pino-pretty did not export a stream factory");
52
+ }
26
53
  /**
27
54
  * Create a pino logger with consistent redaction, level, format, and
28
55
  * destination across the entire codebase.
@@ -30,26 +57,21 @@ const REDACT_PATHS = [
30
57
  * - LOG_LEVEL (default "info") controls the minimum severity.
31
58
  * - LOG_FORMAT=json disables pino-pretty and outputs newline-delimited JSON
32
59
  * to stderr.
60
+ * - Any other value, including unset, keeps human-readable pino-pretty output.
33
61
  * - All loggers redact the same set of sensitive fields.
34
62
  */
35
63
  export function createLogger(name) {
36
64
  const isJson = process.env.LOG_FORMAT === "json";
37
- return pino({
65
+ const options = {
38
66
  ...(name && { name }),
39
67
  level: process.env.LOG_LEVEL || "info",
40
68
  redact: {
41
69
  paths: REDACT_PATHS,
42
70
  censor: "[REDACTED]",
43
71
  },
44
- ...(!isJson && {
45
- transport: {
46
- target: "pino-pretty",
47
- options: {
48
- colorize: true,
49
- levelFirst: true,
50
- destination: 2,
51
- },
52
- },
53
- }),
54
- }, ...(isJson ? [pino.destination(2)] : []));
72
+ };
73
+ if (isJson) {
74
+ return pino(options, pino.destination(2));
75
+ }
76
+ return pino(options, createPrettyStream());
55
77
  }