@zereight/mcp-gitlab 2.0.36 → 2.1.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.
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Estimate the number of merge commits that will be added based on the merge method.
3
+ */
4
+ export function estimateMergeCommitCount(mergeMethod, sourceCommitCount) {
5
+ if (sourceCommitCount === 0) {
6
+ return 0;
7
+ }
8
+ if (mergeMethod === "merge") {
9
+ return 1;
10
+ }
11
+ if (mergeMethod === "ff" || mergeMethod === "rebase_merge") {
12
+ return 0;
13
+ }
14
+ return null;
15
+ }
16
+ /**
17
+ * Summarize webhook events by stripping heavy payload fields.
18
+ */
19
+ export function summarizeWebhookEvents(events) {
20
+ return events.map(event => ({
21
+ id: event.id,
22
+ url: event.url,
23
+ trigger: event.trigger,
24
+ response_status: event.response_status,
25
+ execution_duration: event.execution_duration,
26
+ }));
27
+ }
28
+ /**
29
+ * Filter MR diffs by excluding files matching regex patterns.
30
+ *
31
+ * @param diffs - Array of diff objects with new_path property
32
+ * @param excludedFilePatterns - Array of regex patterns to exclude
33
+ * @returns Filtered array of diffs
34
+ */
35
+ export function filterDiffsByPatterns(diffs, excludedFilePatterns) {
36
+ if (!excludedFilePatterns?.length)
37
+ return diffs;
38
+ const regexPatterns = excludedFilePatterns
39
+ .map(pattern => {
40
+ try {
41
+ return new RegExp(pattern);
42
+ }
43
+ catch (e) {
44
+ console.warn(`Invalid regex pattern ignored: ${pattern}`);
45
+ return null;
46
+ }
47
+ })
48
+ .filter((regex) => regex !== null);
49
+ if (regexPatterns.length === 0)
50
+ return diffs;
51
+ const matchesAnyPattern = (path) => {
52
+ if (!path)
53
+ return false;
54
+ return regexPatterns.some(regex => regex.test(path));
55
+ };
56
+ return diffs.filter(diff => !matchesAnyPattern(diff.new_path));
57
+ }
@@ -0,0 +1,49 @@
1
+ import { zodToJsonSchema } from "zod-to-json-schema";
2
+ /**
3
+ * Convert a Zod schema to JSON Schema, fixing nullable/optional fields
4
+ * so they are not marked as required.
5
+ */
6
+ export const toJSONSchema = (schema) => {
7
+ const jsonSchema = zodToJsonSchema(schema, { $refStrategy: "none" });
8
+ // Post-process to fix nullable/optional fields and strip verbose keys
9
+ function fixNullableOptional(obj) {
10
+ if (obj && typeof obj === "object") {
11
+ // Strip $schema (meta-only, not needed for tool input validation)
12
+ delete obj.$schema;
13
+ // Strip additionalProperties (MCP clients ignore it, saves tokens)
14
+ delete obj.additionalProperties;
15
+ // If this object has properties, process them
16
+ if (obj.properties) {
17
+ const requiredSet = new Set(obj.required || []);
18
+ Object.keys(obj.properties).forEach(key => {
19
+ const prop = obj.properties[key];
20
+ // Handle fields that can be null or omitted
21
+ // If a property has type: ["object", "null"] or anyOf with null, it should not be required
22
+ if (prop.anyOf && prop.anyOf.some((t) => t.type === "null")) {
23
+ requiredSet.delete(key);
24
+ }
25
+ else if (Array.isArray(prop.type) && prop.type.includes("null")) {
26
+ requiredSet.delete(key);
27
+ }
28
+ // Recursively process nested objects
29
+ obj.properties[key] = fixNullableOptional(prop);
30
+ });
31
+ // Normalize the required array after processing all properties
32
+ if (requiredSet.size > 0) {
33
+ obj.required = Array.from(requiredSet);
34
+ }
35
+ else if (Object.prototype.hasOwnProperty.call(obj, "required")) {
36
+ delete obj.required;
37
+ }
38
+ }
39
+ // Process anyOf/allOf/oneOf
40
+ ["anyOf", "allOf", "oneOf"].forEach(combiner => {
41
+ if (obj[combiner]) {
42
+ obj[combiner] = obj[combiner].map(fixNullableOptional);
43
+ }
44
+ });
45
+ }
46
+ return obj;
47
+ }
48
+ return fixNullableOptional(jsonSchema);
49
+ };
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Smart URL handling for GitLab API
3
+ *
4
+ * @param {string | undefined} url - Input GitLab API URL
5
+ * @returns {string} Normalized GitLab API URL with /api/v4 path
6
+ */
7
+ export function normalizeGitLabApiUrl(url) {
8
+ if (!url) {
9
+ return "https://gitlab.com/api/v4";
10
+ }
11
+ let normalizedUrl = url.trim();
12
+ if (normalizedUrl.endsWith("/")) {
13
+ normalizedUrl = normalizedUrl.slice(0, -1);
14
+ }
15
+ if (!normalizedUrl.endsWith("/api/v4")) {
16
+ normalizedUrl = `${normalizedUrl}/api/v4`;
17
+ }
18
+ return normalizedUrl;
19
+ }
package/package.json CHANGED
@@ -1,7 +1,26 @@
1
1
  {
2
2
  "name": "@zereight/mcp-gitlab",
3
- "version": "2.0.36",
4
- "description": "MCP server for using the GitLab API",
3
+ "version": "2.1.0",
4
+ "description": "GitLab MCP server for projects, merge requests, issues, pipelines, wiki, releases, and more",
5
+ "keywords": [
6
+ "gitlab",
7
+ "gitlab-mcp",
8
+ "mcp",
9
+ "mcp-server",
10
+ "model-context-protocol",
11
+ "gitlab-api",
12
+ "claude",
13
+ "cursor",
14
+ "vscode",
15
+ "copilot",
16
+ "ai-agent",
17
+ "merge-requests",
18
+ "pipelines",
19
+ "oauth",
20
+ "stdio",
21
+ "sse",
22
+ "streamable-http"
23
+ ],
5
24
  "license": "MIT",
6
25
  "author": "zereight",
7
26
  "type": "module",