@zereight/mcp-gitlab 2.1.41 → 2.1.43

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.
@@ -0,0 +1,32 @@
1
+ import assert from "node:assert/strict";
2
+ import { describe, test } from "node:test";
3
+ import { buildBulkPublishDraftNotesBody, needsGitLab19_2BulkPublish, } from "../../utils/bulk-publish-options.js";
4
+ describe("When buildBulkPublishDraftNotesBody runs", () => {
5
+ describe("with no-op defaults", () => {
6
+ test("should omit internal false and empty note", () => {
7
+ assert.deepEqual(buildBulkPublishDraftNotesBody({ internal: false, note: "" }), {});
8
+ });
9
+ });
10
+ describe("with meaningful 19.2 fields", () => {
11
+ test("should keep reviewer_state, note, and internal true", () => {
12
+ assert.deepEqual(buildBulkPublishDraftNotesBody({
13
+ reviewer_state: "reviewed",
14
+ note: "LGTM",
15
+ internal: true,
16
+ }), { reviewer_state: "reviewed", note: "LGTM", internal: true });
17
+ });
18
+ });
19
+ });
20
+ describe("When needsGitLab19_2BulkPublish runs", () => {
21
+ describe("with an empty body", () => {
22
+ test("should return false", () => {
23
+ assert.equal(needsGitLab19_2BulkPublish({}), false);
24
+ assert.equal(needsGitLab19_2BulkPublish(buildBulkPublishDraftNotesBody({ internal: false })), false);
25
+ });
26
+ });
27
+ describe("with a non-empty body", () => {
28
+ test("should return true", () => {
29
+ assert.equal(needsGitLab19_2BulkPublish({ reviewer_state: "reviewed" }), true);
30
+ });
31
+ });
32
+ });
@@ -0,0 +1,74 @@
1
+ import assert from "node:assert/strict";
2
+ import { describe, test } from "node:test";
3
+ import { assertGitLabVersionAtLeast, isGitLabVersionAtLeast, parseGitLabVersion, } from "../../utils/gitlab-version-gate.js";
4
+ function versionFetcher(version) {
5
+ return async () => version;
6
+ }
7
+ function bulkPublishRequirement() {
8
+ return {
9
+ major: 19,
10
+ minor: 2,
11
+ feature: "reviewer_state, note, and internal on bulk_publish_draft_notes",
12
+ retryHint: "Omit reviewer_state, note, and internal, then retry.",
13
+ };
14
+ }
15
+ describe("When parseGitLabVersion runs", () => {
16
+ describe("with a release suffix", () => {
17
+ test("should parse major.minor.patch from ee builds", () => {
18
+ assert.deepEqual(parseGitLabVersion("19.2.0-ee"), {
19
+ major: 19,
20
+ minor: 2,
21
+ patch: 0,
22
+ });
23
+ });
24
+ });
25
+ describe("with a malformed string", () => {
26
+ test("should return null", () => {
27
+ assert.equal(parseGitLabVersion("unknown"), null);
28
+ assert.equal(parseGitLabVersion(""), null);
29
+ });
30
+ });
31
+ });
32
+ describe("When isGitLabVersionAtLeast compares versions", () => {
33
+ describe("with a version at or above the floor", () => {
34
+ test("should return true", () => {
35
+ assert.equal(isGitLabVersionAtLeast("19.2.0-ee", 19, 2), true);
36
+ assert.equal(isGitLabVersionAtLeast("19.3.1", 19, 2), true);
37
+ assert.equal(isGitLabVersionAtLeast("20.0.0", 19, 2), true);
38
+ });
39
+ });
40
+ describe("with a version below the floor", () => {
41
+ test("should return false", () => {
42
+ assert.equal(isGitLabVersionAtLeast("19.1.9-ee", 19, 2), false);
43
+ assert.equal(isGitLabVersionAtLeast("17.5.0", 19, 2), false);
44
+ });
45
+ });
46
+ describe("with an unparseable version", () => {
47
+ test("should return null", () => {
48
+ assert.equal(isGitLabVersionAtLeast("not-a-version", 19, 2), null);
49
+ });
50
+ });
51
+ });
52
+ describe("When assertGitLabVersionAtLeast runs", () => {
53
+ describe("with an older instance version", () => {
54
+ test("should throw a retryable error", async () => {
55
+ await assert.rejects(() => assertGitLabVersionAtLeast(bulkPublishRequirement(), versionFetcher("17.5.0-ee")), (error) => {
56
+ assert.ok(error instanceof Error);
57
+ assert.match(error.message, /GitLab 19\.2\+/);
58
+ assert.match(error.message, /17\.5\.0-ee/);
59
+ assert.match(error.message, /Omit reviewer_state/);
60
+ return true;
61
+ });
62
+ });
63
+ });
64
+ describe("with a new enough instance version", () => {
65
+ test("should resolve without throwing", async () => {
66
+ await assertGitLabVersionAtLeast(bulkPublishRequirement(), versionFetcher("19.2.0-ee"));
67
+ });
68
+ });
69
+ describe("with an unknown instance version", () => {
70
+ test("should fail open and resolve", async () => {
71
+ await assertGitLabVersionAtLeast(bulkPublishRequirement(), versionFetcher(null));
72
+ });
73
+ });
74
+ });
@@ -1,7 +1,7 @@
1
1
  import { zodToJsonSchema } from "zod-to-json-schema";
2
2
  import { toJSONSchema } from "../utils/schema.js";
3
3
  import { USE_GITLAB_WIKI, USE_MILESTONE, USE_PIPELINE, SSE, STREAMABLE_HTTP, } from "../config.js";
4
- import { ApproveMergeRequestSchema, BulkPublishDraftNotesSchema, CancelPipelineJobSchema, 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, 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, DeleteWikiPageSchema, DeleteWorkItemEmojiReactionSchema, DeleteWorkItemNoteEmojiReactionSchema, DownloadAttachmentSchema, DownloadAttachmentRemoteSchema, DownloadJobArtifactsSchema, DownloadJobArtifactsRemoteSchema, DownloadReleaseAssetSchema, EditProjectMilestoneSchema, EditGroupMilestoneSchema, ExecuteGraphQLSchema, ForkRepositorySchema, HealthCheckSchema, GetBranchSchema, GetBranchDiffsSchema, GetCommitDiffSchema, GetCommitSchema, GetFileBlameSchema, GetDeploymentSchema, GetDraftNoteSchema, GetEnvironmentSchema, GetFileContentsSchema, GetGroupWikiPageSchema, GetIssueLinkSchema, GetIssueSchema, GetJobArtifactFileSchema, GetLabelSchema, GetMergeRequestApprovalStateSchema, GetMergeRequestConflictsSchema, GetMergeRequestDiffsSchema, GetMergeRequestFileDiffSchema, GetMergeRequestNoteSchema, GetMergeRequestNotesSchema, GetMergeRequestSchema, GetMergeRequestVersionSchema, GetMilestoneBurndownEventsSchema, GetMilestoneIssuesSchema, GetMilestoneMergeRequestsSchema, GetGroupMilestoneSchema, GetGroupMilestoneIssuesSchema, GetGroupMilestoneMergeRequestsSchema, GetGroupMilestoneBurndownEventsSchema, GetNamespaceSchema, GetPipelineJobOutputSchema, PipelineJobControlSchema, GetPipelineSchema, 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, ListNamespacesSchema, ListPipelineJobsSchema, ListPipelineTriggerJobsSchema, ValidateCiLintSchema, ValidateProjectCiLintSchema, ListCiCatalogResourcesSchema, GetCiCatalogResourceSchema, ListPipelinesSchema, ListProjectMembersSchema, ListProjectMilestonesSchema, ListProjectsSchema, ListReleasesSchema, ListTagsSchema, ListWebhookEventsSchema, ListWebhooksSchema, ListWikiPagesSchema, ListWorkItemNotesSchema, ListWorkItemStatusesSchema, ListWorkItemsSchema, MarkdownUploadSchema, MarkdownUploadRemoteSchema, MergeMergeRequestSchema, MoveWorkItemSchema, MyIssuesSchema, PlayPipelineJobSchema, PromoteProjectMilestoneSchema, PublishDraftNoteSchema, PushFilesSchema, ResolveMergeRequestThreadSchema, RetryPipelineJobSchema, RetryPipelineSchema, SearchCodeSchema, SearchGroupCodeSchema, SearchProjectCodeSchema, SearchRepositoriesSchema, UnapproveMergeRequestSchema, UpdateDraftNoteSchema, UpdateGroupWikiPageSchema, UpdateIssueNoteSchema, UpdateIssueSchema, UpdateIssueDescriptionPatchSchema, UpdateLabelSchema, UpdateProjectSchema, UpdateMergeRequestDiscussionNoteSchema, UpdateMergeRequestNoteSchema, UpdateMergeRequestSchema, UpdateReleaseSchema, UpdateWikiPageSchema, UpdateWorkItemSchema, VerifyNamespaceSchema, ListProjectVariablesSchema, GetProjectVariableSchema, CreateProjectVariableSchema, UpdateProjectVariableSchema, DeleteProjectVariableSchema, ListGroupVariablesSchema, GetGroupVariableSchema, CreateGroupVariableSchema, UpdateGroupVariableSchema, DeleteGroupVariableSchema, GetDependencyProxySettingsSchema, UpdateDependencyProxySettingsSchema, ListDependencyProxyBlobsSchema, PurgeDependencyProxyCacheSchema, } from "../schemas.js";
4
+ import { ApproveMergeRequestSchema, BulkPublishDraftNotesSchema, CancelPipelineJobSchema, 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, 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, DeleteWikiPageSchema, DeleteWorkItemEmojiReactionSchema, DeleteWorkItemNoteEmojiReactionSchema, DownloadAttachmentSchema, DownloadAttachmentRemoteSchema, DownloadJobArtifactsSchema, DownloadJobArtifactsRemoteSchema, DownloadReleaseAssetSchema, EditProjectMilestoneSchema, EditGroupMilestoneSchema, ExecuteGraphQLSchema, ForkRepositorySchema, HealthCheckSchema, GetBranchSchema, GetBranchDiffsSchema, GetCommitDiffSchema, GetCommitSchema, GetFileBlameSchema, GetDeploymentSchema, GetDraftNoteSchema, GetEnvironmentSchema, GetFileContentsSchema, GetGroupWikiPageSchema, GetIssueLinkSchema, GetIssueSchema, GetJobArtifactFileSchema, GetLabelSchema, GetMergeRequestApprovalStateSchema, GetMergeRequestConflictsSchema, GetMergeRequestDiffsSchema, GetMergeRequestFileDiffSchema, GetMergeRequestNoteSchema, GetMergeRequestNotesSchema, GetMergeRequestSchema, GetMergeRequestVersionSchema, GetMilestoneBurndownEventsSchema, GetMilestoneIssuesSchema, GetMilestoneMergeRequestsSchema, GetGroupMilestoneSchema, GetGroupMilestoneIssuesSchema, GetGroupMilestoneMergeRequestsSchema, GetGroupMilestoneBurndownEventsSchema, GetNamespaceSchema, GetPipelineJobOutputSchema, PipelineJobControlSchema, GetPipelineSchema, 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, ListNamespacesSchema, ListPipelineJobsSchema, ListPipelineTriggerJobsSchema, ValidateCiLintSchema, ValidateProjectCiLintSchema, ListCiCatalogResourcesSchema, GetCiCatalogResourceSchema, ListPipelinesSchema, ListProjectMembersSchema, ListProjectMilestonesSchema, ListProjectsSchema, ListReleasesSchema, ListTagsSchema, ListWebhookEventsSchema, ListWebhooksSchema, ListWikiPagesSchema, ListWorkItemNotesSchema, ListWorkItemStatusesSchema, ListWorkItemsSchema, MarkdownUploadSchema, MarkdownUploadRemoteSchema, MergeMergeRequestSchema, MoveWorkItemSchema, MyIssuesSchema, PlayPipelineJobSchema, PromoteProjectMilestoneSchema, PublishDraftNoteSchema, PushFilesSchema, ResolveMergeRequestThreadSchema, RetryPipelineJobSchema, RetryPipelineSchema, SearchCodeSchema, SearchGroupCodeSchema, SearchProjectCodeSchema, SearchRepositoriesSchema, UnapproveMergeRequestSchema, UpdateDraftNoteSchema, UpdateGroupWikiPageSchema, UpdateIssueNoteSchema, UpdateIssueSchema, UpdateIssueDescriptionPatchSchema, UpdateLabelSchema, UpdateProjectSchema, UpdateMergeRequestDiscussionNoteSchema, UpdateMergeRequestNoteSchema, UpdateMergeRequestSchema, UpdateReleaseSchema, 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;
6
6
  // Define all available tools
7
7
  export const allTools = [
@@ -267,7 +267,7 @@ export const allTools = [
267
267
  },
268
268
  {
269
269
  name: "bulk_publish_draft_notes",
270
- description: "Publish all draft notes for a merge request",
270
+ description: "Publish all draft notes for a merge request. Optionally sets reviewer_state and posts a summary note (GitLab 19.2+). Can set reviewer_state even with no drafts.",
271
271
  inputSchema: toJSONSchema(BulkPublishDraftNotesSchema),
272
272
  },
273
273
  // --- Merge request emoji reaction tools ---
@@ -1083,6 +1083,27 @@ export const allTools = [
1083
1083
  description: "Schedule purge of all cached dependency proxy blobs for a group",
1084
1084
  inputSchema: toJSONSchema(PurgeDependencyProxyCacheSchema),
1085
1085
  },
1086
+ // --- Vulnerability tools ---
1087
+ {
1088
+ name: "list_project_vulnerabilities",
1089
+ description: "List vulnerabilities for a project with optional state, severity, and report type filters (GraphQL-backed, cursor pagination)",
1090
+ inputSchema: toJSONSchema(ListProjectVulnerabilitiesSchema),
1091
+ },
1092
+ {
1093
+ name: "get_vulnerability",
1094
+ description: "Get full details of a specific vulnerability",
1095
+ inputSchema: toJSONSchema(GetVulnerabilitySchema),
1096
+ },
1097
+ {
1098
+ name: "dismiss_vulnerability",
1099
+ description: "Dismiss a vulnerability with a reason (acceptable_risk, false_positive, used_in_tests, mitigating_control, not_applicable) and optional comment",
1100
+ inputSchema: toJSONSchema(DismissVulnerabilitySchema),
1101
+ },
1102
+ {
1103
+ name: "confirm_vulnerability",
1104
+ description: "Confirm a vulnerability as a real finding requiring remediation",
1105
+ inputSchema: toJSONSchema(ConfirmVulnerabilitySchema),
1106
+ },
1086
1107
  // --- Meta tool: Dynamic tool discovery ---
1087
1108
  {
1088
1109
  name: "discover_tools",
@@ -1217,6 +1238,8 @@ export const readOnlyTools = new Set([
1217
1238
  "get_group_variable",
1218
1239
  "get_dependency_proxy_settings",
1219
1240
  "list_dependency_proxy_blobs",
1241
+ "list_project_vulnerabilities",
1242
+ "get_vulnerability",
1220
1243
  ]);
1221
1244
  // Define which tools are destructive (data loss potential)
1222
1245
  export const destructiveTools = new Set([
@@ -1653,6 +1676,16 @@ export const TOOLSET_DEFINITIONS = [
1653
1676
  "purge_dependency_proxy_cache",
1654
1677
  ]),
1655
1678
  },
1679
+ {
1680
+ id: "vulnerabilities",
1681
+ isDefault: false,
1682
+ tools: new Set([
1683
+ "list_project_vulnerabilities",
1684
+ "get_vulnerability",
1685
+ "dismiss_vulnerability",
1686
+ "confirm_vulnerability",
1687
+ ]),
1688
+ },
1656
1689
  ];
1657
1690
  // Derived lookup: tool name → toolset ID
1658
1691
  export const TOOLSET_BY_TOOL_NAME = new Map();
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Build the POST body. Omit no-op defaults (`internal: false`, empty `note`)
3
+ * so older GitLab instances are not sent unknown fields.
4
+ */
5
+ export function buildBulkPublishDraftNotesBody(options) {
6
+ const body = {};
7
+ if (options.reviewer_state !== undefined) {
8
+ body.reviewer_state = options.reviewer_state;
9
+ }
10
+ if (options.note) {
11
+ body.note = options.note;
12
+ }
13
+ if (options.internal === true) {
14
+ body.internal = true;
15
+ }
16
+ return body;
17
+ }
18
+ /** True when the body needs GitLab 19.2+ bulk_publish fields. */
19
+ export function needsGitLab19_2BulkPublish(body) {
20
+ return Object.keys(body).length > 0;
21
+ }
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Call-time GitLab instance version gate.
3
+ *
4
+ * Use when a tool exposes optional params that only exist on newer GitLab.
5
+ * Schemas stay static; check before the API call and throw a retryable error.
6
+ * Fail-open when the instance version cannot be fetched or parsed.
7
+ */
8
+ const VERSION_CORE = /^(\d+)\.(\d+)(?:\.(\d+))?/;
9
+ /** Parse strings like "19.2.0-ee" / "17.5.3". Returns null if unparseable. */
10
+ export function parseGitLabVersion(version) {
11
+ const match = VERSION_CORE.exec(version.trim());
12
+ if (!match)
13
+ return null;
14
+ const major = Number.parseInt(match[1], 10);
15
+ const minor = Number.parseInt(match[2], 10);
16
+ const patch = match[3] ? Number.parseInt(match[3], 10) : 0;
17
+ if (!Number.isFinite(major) || !Number.isFinite(minor) || !Number.isFinite(patch)) {
18
+ return null;
19
+ }
20
+ return { major, minor, patch };
21
+ }
22
+ /**
23
+ * Compare a GitLab version string against a major.minor floor.
24
+ * Returns null when the version string cannot be parsed.
25
+ */
26
+ export function isGitLabVersionAtLeast(version, major, minor) {
27
+ const parsed = parseGitLabVersion(version);
28
+ if (!parsed)
29
+ return null;
30
+ if (parsed.major !== major)
31
+ return parsed.major > major;
32
+ return parsed.minor >= minor;
33
+ }
34
+ /**
35
+ * Throws when the instance is known to be older than `requirement`.
36
+ * Does nothing when the version is unknown (fail-open).
37
+ */
38
+ export async function assertGitLabVersionAtLeast(requirement, fetchVersion) {
39
+ const current = await fetchVersion();
40
+ if (current === null)
41
+ return;
42
+ const ok = isGitLabVersionAtLeast(current, requirement.major, requirement.minor);
43
+ if (ok === null || ok)
44
+ return;
45
+ throw new Error(`GitLab ${requirement.major}.${requirement.minor}+ required for ${requirement.feature} ` +
46
+ `(instance reports ${current}). ${requirement.retryHint}`);
47
+ }
@@ -0,0 +1,51 @@
1
+ import { pino } from "pino";
2
+ const REDACT_PATHS = [
3
+ "token",
4
+ "*.token",
5
+ "ctx.token",
6
+ "context.token",
7
+ "authData.token",
8
+ "auth.token",
9
+ "headers.authorization",
10
+ "headers.Authorization",
11
+ 'headers["private-token"]',
12
+ 'headers["Private-Token"]',
13
+ 'headers["job-token"]',
14
+ 'headers["JOB-TOKEN"]',
15
+ 'headers["mcp-session-id"]',
16
+ 'headers["Mcp-Session-Id"]',
17
+ "sessionId",
18
+ "*.sessionId",
19
+ "ctx.sessionId",
20
+ "context.sessionId",
21
+ ];
22
+ /**
23
+ * Create a pino logger with consistent redaction, level, format, and
24
+ * destination across the entire codebase.
25
+ *
26
+ * - LOG_LEVEL (default "info") controls the minimum severity.
27
+ * - LOG_FORMAT=json disables pino-pretty and outputs newline-delimited JSON
28
+ * to stderr.
29
+ * - All loggers redact the same set of sensitive fields.
30
+ */
31
+ export function createLogger(name) {
32
+ const isJson = process.env.LOG_FORMAT === "json";
33
+ return pino({
34
+ ...(name && { name }),
35
+ level: process.env.LOG_LEVEL || "info",
36
+ redact: {
37
+ paths: REDACT_PATHS,
38
+ censor: "[REDACTED]",
39
+ },
40
+ ...(!isJson && {
41
+ transport: {
42
+ target: "pino-pretty",
43
+ options: {
44
+ colorize: true,
45
+ levelFirst: true,
46
+ destination: 2,
47
+ },
48
+ },
49
+ }),
50
+ }, ...(isJson ? [pino.destination(2)] : []));
51
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zereight/mcp-gitlab",
3
- "version": "2.1.41",
3
+ "version": "2.1.43",
4
4
  "mcpName": "io.github.zereight/gitlab-mcp",
5
5
  "description": "GitLab MCP server for projects, merge requests, issues, pipelines, wiki, releases, and more",
6
6
  "keywords": [