@zereight/mcp-gitlab 2.0.36 → 2.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +69 -332
- package/build/auth-retry.js +81 -0
- package/build/config.js +75 -0
- package/build/customSchemas.js +0 -12
- package/build/gitlab-client-pool.js +0 -1
- package/build/index.js +472 -1650
- package/build/oauth.js +4 -4
- package/build/schemas.js +160 -48
- package/build/test/mcp-oauth-tests.js +49 -0
- package/build/test/schema-tests.js +59 -3
- package/build/test/test-auth-retry.js +188 -0
- package/build/test/test-search-code.js +7 -4
- package/build/test/test-token-optimizations.js +691 -0
- package/build/test/test-toolset-filtering.js +39 -33
- package/build/tools/registry.js +1295 -0
- package/build/utils/helpers.js +57 -0
- package/build/utils/schema.js +49 -0
- package/build/utils/url.js +19 -0
- package/package.json +24 -5
|
@@ -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.
|
|
4
|
-
"description": "MCP server for
|
|
3
|
+
"version": "2.1.1",
|
|
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",
|
|
@@ -29,10 +48,10 @@
|
|
|
29
48
|
"changelog": "auto-changelog -p",
|
|
30
49
|
"test": "npm run test:all",
|
|
31
50
|
"test:all": "npm run build && npm run test:mock && npm run test:live",
|
|
32
|
-
"test:mock": "
|
|
33
|
-
"test:mcp-oauth": "npm run build &&
|
|
51
|
+
"test:mock": "node --import tsx/esm --test test/remote-auth-simple-test.ts && node --import tsx/esm --test test/mcp-oauth-tests.ts && tsx test/oauth-tests.ts && tsx test/test-list-merge-requests.ts && tsx test/test-list-project-members.ts && tsx test/test-download-attachment.ts && node --import tsx/esm --test test/test-job-artifacts.ts && node --import tsx/esm --test test/test-deployment-tools.ts && node --import tsx/esm --test test/test-merge-request-approval-state-tools.ts && node --import tsx/esm --test test/test-search-code.ts && node --import tsx/esm --test test/test-toolset-filtering.ts && node --import tsx/esm --test test/test-auth-retry.ts",
|
|
52
|
+
"test:mcp-oauth": "npm run build && node --import tsx/esm --test test/mcp-oauth-tests.ts",
|
|
34
53
|
"test:live": "node test/validate-api.js",
|
|
35
|
-
"test:remote-auth": "npm run build &&
|
|
54
|
+
"test:remote-auth": "npm run build && node --import tsx/esm --test test/remote-auth-simple-test.ts",
|
|
36
55
|
"test:schema": "tsx test/schema-tests.ts",
|
|
37
56
|
"test:oauth": "tsx test/oauth-tests.ts",
|
|
38
57
|
"test:list-merge-requests": "npm run build && tsx test/test-list-merge-requests.ts",
|