@zereight/mcp-gitlab 2.0.35 → 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.
- package/README.md +171 -331
- package/build/config.js +75 -0
- package/build/customSchemas.js +0 -12
- package/build/gitlab-client-pool.js +0 -1
- package/build/index.js +357 -1687
- package/build/oauth-proxy.js +11 -4
- package/build/schemas.js +66 -48
- package/build/test/mcp-oauth-tests.js +109 -0
- package/build/test/schema-tests.js +77 -3
- package/build/test/test-token-optimizations.js +688 -0
- package/build/test/test-toolset-filtering.js +30 -30
- package/build/tools/registry.js +1172 -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 +21 -2
|
@@ -38,15 +38,13 @@ const DEFAULT_TOOLSETS = [
|
|
|
38
38
|
"branches",
|
|
39
39
|
"projects",
|
|
40
40
|
"labels",
|
|
41
|
-
"pipelines",
|
|
42
|
-
"milestones",
|
|
43
|
-
"wiki",
|
|
44
|
-
"releases",
|
|
45
41
|
"users",
|
|
46
42
|
];
|
|
47
|
-
const NON_DEFAULT_TOOLSETS = ["
|
|
48
|
-
|
|
49
|
-
const
|
|
43
|
+
const NON_DEFAULT_TOOLSETS = ["pipelines", "milestones", "wiki", "releases", "workitems", "webhooks", "search"];
|
|
44
|
+
// discover_tools meta-tool is always force-injected (Step 5.5)
|
|
45
|
+
const DISCOVER_TOOLS_COUNT = 1;
|
|
46
|
+
const DEFAULT_TOOL_COUNT = DEFAULT_TOOLSETS.reduce((sum, id) => sum + TOOLSET_TOOL_COUNTS[id], 0) + DISCOVER_TOOLS_COUNT;
|
|
47
|
+
const ALL_TOOLSET_TOOL_COUNT = Object.values(TOOLSET_TOOL_COUNTS).reduce((sum, c) => sum + c, 0) + DISCOVER_TOOLS_COUNT;
|
|
50
48
|
// Representative tools per toolset for spot-checking
|
|
51
49
|
const TOOLSET_SAMPLE_TOOLS = {
|
|
52
50
|
merge_requests: ["merge_merge_request", "create_merge_request_thread", "list_draft_notes"],
|
|
@@ -136,8 +134,10 @@ describe("Toolset Filtering", { concurrency: 1 }, () => {
|
|
|
136
134
|
assertContainsAll(tools, TOOLSET_SAMPLE_TOOLS[id], id);
|
|
137
135
|
}
|
|
138
136
|
});
|
|
139
|
-
test("excludes non-default toolsets (search)", () => {
|
|
137
|
+
test("excludes non-default toolsets (search, pipelines, wiki)", () => {
|
|
140
138
|
assertContainsNone(tools, TOOLSET_SAMPLE_TOOLS.search, "non-default search");
|
|
139
|
+
assertContainsNone(tools, TOOLSET_SAMPLE_TOOLS.pipelines, "non-default pipelines");
|
|
140
|
+
assertContainsNone(tools, TOOLSET_SAMPLE_TOOLS.wiki, "non-default wiki");
|
|
141
141
|
});
|
|
142
142
|
test("excludes execute_graphql (not in any toolset)", () => {
|
|
143
143
|
assertContainsNone(tools, ["execute_graphql"], "unassigned");
|
|
@@ -155,8 +155,8 @@ describe("Toolset Filtering", { concurrency: 1 }, () => {
|
|
|
155
155
|
tools = await getToolNames(`http://${HOST}:${port}/mcp`);
|
|
156
156
|
});
|
|
157
157
|
after(() => cleanupServers([server]));
|
|
158
|
-
test("returns only issue tools", () => {
|
|
159
|
-
assert.strictEqual(tools.length, TOOLSET_TOOL_COUNTS.issues);
|
|
158
|
+
test("returns only issue tools + discover_tools", () => {
|
|
159
|
+
assert.strictEqual(tools.length, TOOLSET_TOOL_COUNTS.issues + DISCOVER_TOOLS_COUNT);
|
|
160
160
|
});
|
|
161
161
|
test("includes issue sample tools", () => {
|
|
162
162
|
assertContainsAll(tools, TOOLSET_SAMPLE_TOOLS.issues, "issues");
|
|
@@ -201,14 +201,14 @@ describe("Toolset Filtering", { concurrency: 1 }, () => {
|
|
|
201
201
|
tools = await getToolNames(`http://${HOST}:${port}/mcp`);
|
|
202
202
|
});
|
|
203
203
|
after(() => cleanupServers([server]));
|
|
204
|
-
test("returns default tools plus execute_graphql (
|
|
205
|
-
assert.strictEqual(tools.length, DEFAULT_TOOL_COUNT +
|
|
204
|
+
test("returns default tools plus list_pipelines and execute_graphql (both not in default toolsets)", () => {
|
|
205
|
+
assert.strictEqual(tools.length, DEFAULT_TOOL_COUNT + 2);
|
|
206
206
|
});
|
|
207
207
|
test("includes the individually added tools", () => {
|
|
208
208
|
assertContainsAll(tools, ["list_pipelines", "execute_graphql"], "individual");
|
|
209
209
|
});
|
|
210
|
-
test("
|
|
211
|
-
|
|
210
|
+
test("excludes other pipeline tools (not individually enabled)", () => {
|
|
211
|
+
assertContainsNone(tools, ["create_pipeline", "cancel_pipeline"], "non-enabled pipelines");
|
|
212
212
|
});
|
|
213
213
|
});
|
|
214
214
|
// ---- 5. Toolset + individual tools combined ----
|
|
@@ -224,8 +224,8 @@ describe("Toolset Filtering", { concurrency: 1 }, () => {
|
|
|
224
224
|
tools = await getToolNames(`http://${HOST}:${port}/mcp`);
|
|
225
225
|
});
|
|
226
226
|
after(() => cleanupServers([server]));
|
|
227
|
-
test("returns issue tools + 2 individual pipeline tools", () => {
|
|
228
|
-
assert.strictEqual(tools.length, TOOLSET_TOOL_COUNTS.issues + 2);
|
|
227
|
+
test("returns issue tools + 2 individual pipeline tools + discover_tools", () => {
|
|
228
|
+
assert.strictEqual(tools.length, TOOLSET_TOOL_COUNTS.issues + 2 + DISCOVER_TOOLS_COUNT);
|
|
229
229
|
});
|
|
230
230
|
test("includes issue tools and the two pipeline tools", () => {
|
|
231
231
|
assertContainsAll(tools, TOOLSET_SAMPLE_TOOLS.issues, "issues");
|
|
@@ -248,8 +248,8 @@ describe("Toolset Filtering", { concurrency: 1 }, () => {
|
|
|
248
248
|
tools = await getToolNames(`http://${HOST}:${port}/mcp`);
|
|
249
249
|
});
|
|
250
250
|
after(() => cleanupServers([server]));
|
|
251
|
-
test("returns issue tools + all pipeline tools", () => {
|
|
252
|
-
assert.strictEqual(tools.length, TOOLSET_TOOL_COUNTS.issues + TOOLSET_TOOL_COUNTS.pipelines);
|
|
251
|
+
test("returns issue tools + all pipeline tools + discover_tools", () => {
|
|
252
|
+
assert.strictEqual(tools.length, TOOLSET_TOOL_COUNTS.issues + TOOLSET_TOOL_COUNTS.pipelines + DISCOVER_TOOLS_COUNT);
|
|
253
253
|
});
|
|
254
254
|
test("includes all pipeline tools via legacy flag", () => {
|
|
255
255
|
assertContainsAll(tools, TOOLSET_SAMPLE_TOOLS.pipelines, "pipelines");
|
|
@@ -267,8 +267,8 @@ describe("Toolset Filtering", { concurrency: 1 }, () => {
|
|
|
267
267
|
tools = await getToolNames(`http://${HOST}:${port}/mcp`);
|
|
268
268
|
});
|
|
269
269
|
after(() => cleanupServers([server]));
|
|
270
|
-
test("returns default
|
|
271
|
-
assert.strictEqual(tools.length, DEFAULT_TOOL_COUNT);
|
|
270
|
+
test("returns default tools + wiki tools (wiki is NOT default, USE_GITLAB_WIKI adds it)", () => {
|
|
271
|
+
assert.strictEqual(tools.length, DEFAULT_TOOL_COUNT + TOOLSET_TOOL_COUNTS.wiki);
|
|
272
272
|
});
|
|
273
273
|
test("includes wiki tools", () => {
|
|
274
274
|
assertContainsAll(tools, TOOLSET_SAMPLE_TOOLS.wiki, "wiki");
|
|
@@ -312,8 +312,8 @@ describe("Toolset Filtering", { concurrency: 1 }, () => {
|
|
|
312
312
|
test("excludes write issue tools", () => {
|
|
313
313
|
assertContainsNone(tools, writeIssueTools, "write issues");
|
|
314
314
|
});
|
|
315
|
-
test("returns correct count", () => {
|
|
316
|
-
assert.strictEqual(tools.length, readOnlyIssueTools.length);
|
|
315
|
+
test("returns correct count (read-only issues + discover_tools)", () => {
|
|
316
|
+
assert.strictEqual(tools.length, readOnlyIssueTools.length + DISCOVER_TOOLS_COUNT);
|
|
317
317
|
});
|
|
318
318
|
});
|
|
319
319
|
// ---- 9. GITLAB_DENIED_TOOLS_REGEX applied after toolset filter ----
|
|
@@ -378,8 +378,8 @@ describe("Toolset Filtering", { concurrency: 1 }, () => {
|
|
|
378
378
|
tools = await getToolNames(`http://${HOST}:${port}/mcp`);
|
|
379
379
|
});
|
|
380
380
|
after(() => cleanupServers([server]));
|
|
381
|
-
test("returns exactly pipeline tool count (no duplicates)", () => {
|
|
382
|
-
assert.strictEqual(tools.length, TOOLSET_TOOL_COUNTS.pipelines);
|
|
381
|
+
test("returns exactly pipeline tool count + discover_tools (no duplicates)", () => {
|
|
382
|
+
assert.strictEqual(tools.length, TOOLSET_TOOL_COUNTS.pipelines + DISCOVER_TOOLS_COUNT);
|
|
383
383
|
});
|
|
384
384
|
});
|
|
385
385
|
// ---- 12. GITLAB_TOOLS with tool already in enabled toolset (no dupes) ----
|
|
@@ -395,8 +395,8 @@ describe("Toolset Filtering", { concurrency: 1 }, () => {
|
|
|
395
395
|
tools = await getToolNames(`http://${HOST}:${port}/mcp`);
|
|
396
396
|
});
|
|
397
397
|
after(() => cleanupServers([server]));
|
|
398
|
-
test("returns exactly issue tool count (no duplicates)", () => {
|
|
399
|
-
assert.strictEqual(tools.length, TOOLSET_TOOL_COUNTS.issues);
|
|
398
|
+
test("returns exactly issue tool count + discover_tools (no duplicates)", () => {
|
|
399
|
+
assert.strictEqual(tools.length, TOOLSET_TOOL_COUNTS.issues + DISCOVER_TOOLS_COUNT);
|
|
400
400
|
});
|
|
401
401
|
});
|
|
402
402
|
// ---- 13. Invalid toolset ID is silently ignored ----
|
|
@@ -411,8 +411,8 @@ describe("Toolset Filtering", { concurrency: 1 }, () => {
|
|
|
411
411
|
tools = await getToolNames(`http://${HOST}:${port}/mcp`);
|
|
412
412
|
});
|
|
413
413
|
after(() => cleanupServers([server]));
|
|
414
|
-
test("returns only issue tools (invalid toolset ignored)", () => {
|
|
415
|
-
assert.strictEqual(tools.length, TOOLSET_TOOL_COUNTS.issues);
|
|
414
|
+
test("returns only issue tools + discover_tools (invalid toolset ignored)", () => {
|
|
415
|
+
assert.strictEqual(tools.length, TOOLSET_TOOL_COUNTS.issues + DISCOVER_TOOLS_COUNT);
|
|
416
416
|
});
|
|
417
417
|
});
|
|
418
418
|
// ---- 14. GITLAB_TOOLS case-insensitive matching ----
|
|
@@ -430,8 +430,8 @@ describe("Toolset Filtering", { concurrency: 1 }, () => {
|
|
|
430
430
|
test("resolves mixed-case tool names to lowercase equivalents", () => {
|
|
431
431
|
assertContainsAll(tools, ["list_pipelines", "execute_graphql"], "case-insensitive tools");
|
|
432
432
|
});
|
|
433
|
-
test("returns default tools plus
|
|
434
|
-
assert.strictEqual(tools.length, DEFAULT_TOOL_COUNT +
|
|
433
|
+
test("returns default tools plus list_pipelines and execute_graphql", () => {
|
|
434
|
+
assert.strictEqual(tools.length, DEFAULT_TOOL_COUNT + 2);
|
|
435
435
|
});
|
|
436
436
|
});
|
|
437
437
|
// ---- 15. GITLAB_TOOLS with unknown tool names ----
|