@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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zereight/mcp-gitlab",
3
- "version": "2.1.70",
3
+ "version": "2.2.1",
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": [
@@ -44,10 +44,10 @@
44
44
  "npm": ">=9.0.0"
45
45
  },
46
46
  "scripts": {
47
- "build": "tsc && node -e \"require('fs').chmodSync('build/index.js', '755')\"",
47
+ "build": "node -e \"require('fs').rmSync('build',{recursive:true,force:true})\" && tsc -p tsconfig.build.json && node -e \"require('fs').chmodSync('build/index.js', '755')\"",
48
48
  "prepare": "npm run build",
49
49
  "dev": "npm run build && node build/index.js",
50
- "watch": "tsc --watch",
50
+ "watch": "tsc -p tsconfig.build.json --watch",
51
51
  "deploy": "npm publish --access public",
52
52
  "changelog": "auto-changelog -p",
53
53
  "test": "npm run test:all",
@@ -1,143 +0,0 @@
1
- #!/usr/bin/env tsx
2
- /**
3
- * Verify skills/gitlab-mcp/ stays in sync with tools/registry.ts.
4
- *
5
- * Run with: npm run check:skill-sync
6
- */
7
- import { readFileSync, readdirSync } from "node:fs";
8
- import { dirname, join } from "node:path";
9
- import { fileURLToPath } from "node:url";
10
- import { TOOLSET_DEFINITIONS, allTools, destructiveTools, DEFAULT_TOOLSET_IDS, } from "../tools/registry.js";
11
- const __dirname = dirname(fileURLToPath(import.meta.url));
12
- const REPO_ROOT = join(__dirname, "..");
13
- const SKILL_PATH = join(REPO_ROOT, "skills", "gitlab-mcp", "SKILL.md");
14
- const REF_DIR = join(REPO_ROOT, "skills", "gitlab-mcp", "reference");
15
- // Response field names in reference docs — not MCP tools.
16
- const REFERENCE_FIELD_ALLOWLIST = new Set([
17
- "after",
18
- "allow_multiple",
19
- "deleted_file",
20
- "excluded_file_patterns",
21
- "group_id",
22
- "new_file",
23
- "new_path",
24
- "old_path",
25
- "name",
26
- "page",
27
- "per_page",
28
- "pipeline_id",
29
- "job_inputs",
30
- "project_id",
31
- "renamed_file",
32
- ]);
33
- function fail(message) {
34
- console.error(`::error::${message}`);
35
- process.exit(1);
36
- }
37
- function parseToolsetTable(skill) {
38
- const rows = new Map();
39
- const rowRe = /^\| ([a-z_]+) \((\d+) tools?\) \| (yes|no) \|/gm;
40
- let match;
41
- while ((match = rowRe.exec(skill)) !== null) {
42
- rows.set(match[1], {
43
- count: Number(match[2]),
44
- isDefault: match[3] === "yes",
45
- });
46
- }
47
- return rows;
48
- }
49
- function parseIntroCounts(skill) {
50
- const match = skill.match(/providing (\d+) tools: (\d+) tools across (\d+) toolsets/);
51
- if (!match) {
52
- fail("skills/gitlab-mcp/SKILL.md intro line is missing or malformed");
53
- }
54
- return {
55
- totalTools: Number(match[1]),
56
- uniqueInToolsets: Number(match[2]),
57
- toolsetCount: Number(match[3]),
58
- };
59
- }
60
- function parseDestructiveTools(skill) {
61
- const section = skill.match(/## Destructive Tools[^\n]*\n\n(`[^`]+`(?:, `[^`]+`)*)$/m);
62
- if (!section) {
63
- fail("skills/gitlab-mcp/SKILL.md destructive tools section is missing or malformed");
64
- }
65
- return new Set([...section[1].matchAll(/`([a-z_]+)`/g)].map((m) => m[1]));
66
- }
67
- function collectReferenceToolNames() {
68
- const toolNames = new Set();
69
- for (const file of readdirSync(REF_DIR).filter((name) => name.endsWith(".md"))) {
70
- const text = readFileSync(join(REF_DIR, file), "utf8");
71
- for (const match of text.matchAll(/`([a-z][a-z0-9_]*)`/g)) {
72
- const name = match[1];
73
- if (!REFERENCE_FIELD_ALLOWLIST.has(name)) {
74
- toolNames.add(name);
75
- }
76
- }
77
- }
78
- return toolNames;
79
- }
80
- const skill = readFileSync(SKILL_PATH, "utf8");
81
- const errors = [];
82
- const registryCounts = Object.fromEntries(TOOLSET_DEFINITIONS.map((definition) => [definition.id, definition.tools.size]));
83
- const skillRows = parseToolsetTable(skill);
84
- if (skillRows.size !== TOOLSET_DEFINITIONS.length) {
85
- errors.push(`toolset table has ${skillRows.size} rows; registry has ${TOOLSET_DEFINITIONS.length}`);
86
- }
87
- for (const definition of TOOLSET_DEFINITIONS) {
88
- const row = skillRows.get(definition.id);
89
- if (!row) {
90
- errors.push(`missing toolset row for ${definition.id}`);
91
- continue;
92
- }
93
- const actualCount = registryCounts[definition.id];
94
- if (row.count !== actualCount) {
95
- errors.push(`${definition.id}: skill says ${row.count}, registry has ${actualCount}`);
96
- }
97
- const expectedDefault = DEFAULT_TOOLSET_IDS.has(definition.id);
98
- if (row.isDefault !== expectedDefault) {
99
- errors.push(`${definition.id}: skill default=${row.isDefault}, registry default=${expectedDefault}`);
100
- }
101
- }
102
- for (const id of skillRows.keys()) {
103
- if (!registryCounts[id]) {
104
- errors.push(`unknown toolset in skill table: ${id}`);
105
- }
106
- }
107
- const uniqueInToolsets = new Set(TOOLSET_DEFINITIONS.flatMap((definition) => [...definition.tools]))
108
- .size;
109
- const intro = parseIntroCounts(skill);
110
- if (intro.totalTools !== allTools.length) {
111
- errors.push(`intro total tools: skill says ${intro.totalTools}, registry has ${allTools.length}`);
112
- }
113
- if (intro.uniqueInToolsets !== uniqueInToolsets) {
114
- errors.push(`intro unique toolset tools: skill says ${intro.uniqueInToolsets}, registry has ${uniqueInToolsets}`);
115
- }
116
- if (intro.toolsetCount !== TOOLSET_DEFINITIONS.length) {
117
- errors.push(`intro toolset count: skill says ${intro.toolsetCount}, registry has ${TOOLSET_DEFINITIONS.length}`);
118
- }
119
- const skillDestructive = parseDestructiveTools(skill);
120
- for (const tool of skillDestructive) {
121
- if (!destructiveTools.has(tool)) {
122
- errors.push(`destructive list includes non-destructive tool: ${tool}`);
123
- }
124
- }
125
- for (const tool of destructiveTools) {
126
- if (!skillDestructive.has(tool)) {
127
- errors.push(`destructive list missing registry tool: ${tool}`);
128
- }
129
- }
130
- const registryToolNames = new Set(allTools.map((tool) => tool.name));
131
- for (const tool of collectReferenceToolNames()) {
132
- if (!registryToolNames.has(tool)) {
133
- errors.push(`reference mentions unknown tool: ${tool}`);
134
- }
135
- }
136
- if (errors.length > 0) {
137
- console.error("skills/gitlab-mcp/ is out of sync with tools/registry.ts:");
138
- for (const error of errors) {
139
- console.error(`- ${error}`);
140
- }
141
- process.exit(1);
142
- }
143
- console.log("skills/gitlab-mcp/ is in sync with tools/registry.ts");
@@ -1,39 +0,0 @@
1
- import fs from "node:fs";
2
- import path from "node:path";
3
- import { allTools } from "../tools/registry.js";
4
- async function main() {
5
- const pkgPath = path.resolve(process.cwd(), "package.json");
6
- const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
7
- const serverCard = {
8
- serverInfo: {
9
- name: pkg.mcpName || pkg.name,
10
- version: pkg.version,
11
- },
12
- authentication: {
13
- required: true,
14
- schemes: ["bearer", "oauth2"],
15
- },
16
- tools: allTools.map(t => {
17
- const tool = { ...t };
18
- if (tool.inputSchema &&
19
- typeof tool.inputSchema === "object" &&
20
- "$schema" in tool.inputSchema) {
21
- const schema = { ...tool.inputSchema };
22
- delete schema["$schema"];
23
- tool.inputSchema = schema;
24
- }
25
- return tool;
26
- }),
27
- resources: [],
28
- prompts: [],
29
- };
30
- const outDir = path.resolve(process.cwd(), ".well-known", "mcp");
31
- fs.mkdirSync(outDir, { recursive: true });
32
- const outFile = path.join(outDir, "server-card.json");
33
- fs.writeFileSync(outFile, JSON.stringify(serverCard, null, 2), "utf8");
34
- console.log(`Successfully generated ${outFile} (${allTools.length} tools)`);
35
- }
36
- main().catch(err => {
37
- console.error("Failed to generate server card:", err);
38
- process.exit(1);
39
- });
@@ -1,58 +0,0 @@
1
- #!/usr/bin/env tsx
2
- /**
3
- * Generate docs/reference/tool-coverage.md from tools/registry.ts + test/ MCP calls.
4
- *
5
- * Detection rules live in ./tool-coverage/coverage.ts (AST-scoped): a tool is
6
- * invoked when test source sends that name as a `callTool*` argument, as the
7
- * `name` of a first-argument params object (`client.callTool({ name })`), or as
8
- * the `name` of a `params` object inside a `tools/call` payload literal.
9
- *
10
- * Name-only mentions (toolset tables, description-quality) do not count.
11
- * callTool(variable) loops are missed unless the name is also a literal in that call.
12
- *
13
- * Run with: npm run docs:tools
14
- */
15
- import { readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
16
- import { dirname, join, relative } from "node:path";
17
- import { fileURLToPath } from "node:url";
18
- import { allTools, TOOLSET_DEFINITIONS } from "../tools/registry.js";
19
- import { assertDetectorHealthy, buildCoverageMarkdown, collectInvocations, countInvoked, groupToolsByToolset, percent, SKIP_FILES, } from "./tool-coverage/coverage.js";
20
- const __dirname = dirname(fileURLToPath(import.meta.url));
21
- const REPO_ROOT = join(__dirname, "..");
22
- const TEST_DIR = join(REPO_ROOT, "test");
23
- const OUT_PATH = join(REPO_ROOT, "docs", "reference", "tool-coverage.md");
24
- function walkTestFiles(dir) {
25
- const out = [];
26
- for (const name of readdirSync(dir)) {
27
- const full = join(dir, name);
28
- const stat = statSync(full);
29
- if (stat.isDirectory()) {
30
- out.push(...walkTestFiles(full));
31
- continue;
32
- }
33
- if (/\.(ts|js)$/.test(name) && !SKIP_FILES.has(name)) {
34
- out.push(full);
35
- }
36
- }
37
- return out;
38
- }
39
- function repoPath(abs) {
40
- return relative(REPO_ROOT, abs).split("\\").join("/");
41
- }
42
- function readScannedFiles() {
43
- return walkTestFiles(TEST_DIR).map(abs => ({
44
- path: repoPath(abs),
45
- text: readFileSync(abs, "utf8"),
46
- }));
47
- }
48
- function main() {
49
- const toolNames = allTools.map(tool => tool.name);
50
- const toolNameSet = new Set(toolNames);
51
- const hits = collectInvocations(readScannedFiles(), toolNameSet);
52
- const invokedCount = countInvoked(toolNames, hits);
53
- assertDetectorHealthy(hits, invokedCount);
54
- const grouped = groupToolsByToolset(toolNames, TOOLSET_DEFINITIONS);
55
- writeFileSync(OUT_PATH, buildCoverageMarkdown(toolNames, hits, grouped));
56
- console.log(`generated docs/reference/tool-coverage.md — ${invokedCount}/${toolNames.length} (${percent(invokedCount, toolNames.length)})`);
57
- }
58
- main();