@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
@@ -1,430 +0,0 @@
1
- #!/usr/bin/env tsx
2
- /**
3
- * Generate per-group tool reference pages under docs/tools/ from the
4
- * authoritative tool registry (tools/registry.ts).
5
- *
6
- * Run with: npx tsx scripts/generate-tool-docs.ts
7
- * Or via: make tools-docs
8
- */
9
- import { writeFileSync, mkdirSync, readdirSync, unlinkSync, statSync } from "node:fs";
10
- import { join, dirname } from "node:path";
11
- import { fileURLToPath } from "node:url";
12
- import { allTools, readOnlyTools, TOOLSET_DEFINITIONS } from "../tools/registry.js";
13
- const __dirname = dirname(fileURLToPath(import.meta.url));
14
- const REPO_ROOT = join(__dirname, "..");
15
- const OUT_DIR = join(REPO_ROOT, "docs", "tools");
16
- // Legacy single-group env flags that pre-date GITLAB_TOOLSETS.
17
- // Only three groups have these for backward compatibility; everything else
18
- // opt-in is configured via GITLAB_TOOLSETS / GITLAB_TOOLS / discover_tools.
19
- const LEGACY_TOGGLE_ENV = {
20
- pipelines: "USE_PIPELINE",
21
- milestones: "USE_MILESTONE",
22
- wiki: "USE_GITLAB_WIKI",
23
- };
24
- function isDefaultToolset(id) {
25
- return TOOLSET_DEFINITIONS.find(d => d.id === id)?.isDefault ?? false;
26
- }
27
- /** Returns the availability note for a toolset group, or undefined when it is on by default. */
28
- function computeToggleNote(id) {
29
- if (isDefaultToolset(id))
30
- return undefined;
31
- // Synthetic group for tools not in any TOOLSET_DEFINITIONS entry.
32
- // discover_tools is always exposed; execute_graphql is opt-in via GITLAB_TOOLS.
33
- if (id === "meta") {
34
- return "Mixed availability. `discover_tools` is always exposed (the server re-adds it after every toolset filter). `execute_graphql` is not part of any toolset — enable it explicitly with `GITLAB_TOOLS=execute_graphql`. Tools excluded from the list (toolset / `GITLAB_TOOLS` / `GITLAB_DENIED_TOOLS_REGEX`) are also rejected on direct calls; `GITLAB_TOOL_POLICY_HIDDEN` tools stay callable unless they match `GITLAB_DENIED_TOOLS_REGEX`.";
35
- }
36
- const legacy = LEGACY_TOGGLE_ENV[id];
37
- if (legacy) {
38
- return `Opt-in. Enable via \`GITLAB_TOOLSETS=${id}\` (or \`GITLAB_TOOLSETS=all\`), or use the legacy \`${legacy}=true\` flag for backward compatibility.`;
39
- }
40
- return `Opt-in. Enable via \`GITLAB_TOOLSETS=${id}\` (or \`GITLAB_TOOLSETS=all\`), list individual tools in \`GITLAB_TOOLS=\`, or activate at runtime with the \`discover_tools\` MCP tool.`;
41
- }
42
- const GROUP_META = {
43
- merge_requests: {
44
- title: "Merge Requests",
45
- blurb: "MR lifecycle — create, update, merge, approve, plus diff/conflict inspection and the full discussion/note/draft API.",
46
- },
47
- issues: {
48
- title: "Issues",
49
- blurb: "Issue CRUD, links, discussions and notes, todos, and emoji reactions.",
50
- },
51
- repositories: {
52
- title: "Projects & Files",
53
- blurb: "Project search/creation/fork plus the Files API for reading and writing repository content without shelling out to git.",
54
- },
55
- branches: {
56
- title: "Branches & Commits",
57
- blurb: "Branch management, commit listing/inspection, file blame, and CI commit-status manipulation.",
58
- },
59
- projects: {
60
- title: "Projects & Namespaces",
61
- blurb: "Project/namespace listing, member queries, group iterations, and server health.",
62
- },
63
- labels: {
64
- title: "Labels",
65
- blurb: "Project label CRUD.",
66
- },
67
- ci: {
68
- title: "CI Lint",
69
- blurb: "Validate `.gitlab-ci.yml` snippets and project pipeline configs.",
70
- },
71
- groups: {
72
- title: "Groups",
73
- blurb: "Create new groups and subgroups.",
74
- },
75
- pipelines: {
76
- title: "Pipelines, Jobs & Deployments",
77
- blurb: "Pipeline + job control (trigger, retry, cancel, play manual jobs, fetch logs/artifacts), and the deployments/environments view.",
78
- },
79
- milestones: {
80
- title: "Milestones",
81
- blurb: "Project and group milestone CRUD plus associated issues/MRs and burndown events.",
82
- },
83
- wiki: {
84
- title: "Wiki",
85
- blurb: "Project and group wiki page CRUD. Attachment uploads where supported.",
86
- },
87
- releases: {
88
- title: "Releases",
89
- blurb: "Release lifecycle, release evidence, and asset download.",
90
- },
91
- tags: {
92
- title: "Tags",
93
- blurb: "Tag listing, creation, deletion, and signature inspection.",
94
- },
95
- users: {
96
- title: "Users & Events",
97
- blurb: "User lookup, the authenticated user (`whoami`), event streams, and markdown attachment upload/download.",
98
- },
99
- workitems: {
100
- title: "Work Items",
101
- blurb: "Modern unified API for issues, tasks, incidents, and other typed work items — including notes, emoji reactions, and incident timeline events.",
102
- },
103
- webhooks: {
104
- title: "Webhooks",
105
- blurb: "Create, update, and delete project or group webhooks, and inspect recent webhook events.",
106
- },
107
- search: {
108
- title: "Search",
109
- blurb: "Code search across all visible projects, a specific project, or a specific group.",
110
- },
111
- variables: {
112
- title: "Variables",
113
- blurb: "Project and group CI/CD variable CRUD.",
114
- },
115
- dependency_proxy: {
116
- title: "Dependency Proxy",
117
- blurb: "Inspect and manage the GitLab dependency proxy cache settings, blob storage, and purge operations.",
118
- },
119
- vulnerabilities: {
120
- title: "Vulnerabilities",
121
- blurb: "AI-assisted vulnerability triage — list findings, inspect details, dismiss with reason, or confirm for remediation. Backed by the GitLab GraphQL API; requires GitLab Ultimate.",
122
- },
123
- orbit: {
124
- title: "GitLab Orbit",
125
- blurb: "Query the Orbit SDLC knowledge graph (Beta; Premium/Ultimate). Graph queries consume GitLab credits; schema, status, and tool listing are free.",
126
- },
127
- snippets: {
128
- title: "Snippets",
129
- blurb: "Snippet CRUD — list, get (with optional file content), create, update, and delete personal or project snippets.",
130
- },
131
- };
132
- const GROUP_ORDER = [
133
- "projects",
134
- "repositories",
135
- "branches",
136
- "groups",
137
- "merge_requests",
138
- "issues",
139
- "labels",
140
- "workitems",
141
- "ci",
142
- "pipelines",
143
- "milestones",
144
- "wiki",
145
- "releases",
146
- "tags",
147
- "users",
148
- "variables",
149
- "webhooks",
150
- "search",
151
- "dependency_proxy",
152
- "vulnerabilities",
153
- "orbit",
154
- "snippets",
155
- ];
156
- // Authoritative classification — uses the `readOnlyTools` set from
157
- // tools/registry.ts. That set is what the server itself consults to decide
158
- // which tools survive `GITLAB_READ_ONLY_MODE=true`, so the badges here
159
- // match real runtime behavior exactly (no prefix heuristics).
160
- function classify(name) {
161
- return readOnlyTools.has(name) ? "read" : "write";
162
- }
163
- function rwBadge(name) {
164
- return classify(name) === "read" ? "📖 Read-only" : "✏️ Writes";
165
- }
166
- function describeType(prop) {
167
- if (prop.enum) {
168
- return `enum (\`${prop.enum.map(String).join("` \\| `")}\`)`;
169
- }
170
- if (prop.anyOf || prop.oneOf) {
171
- const variants = (prop.anyOf || prop.oneOf || []).map(describeType).filter(Boolean);
172
- return variants.join(" \\| ") || "any";
173
- }
174
- if (Array.isArray(prop.type)) {
175
- return prop.type.join(" \\| ");
176
- }
177
- if (prop.type === "array") {
178
- return `array<${prop.items ? describeType(prop.items) : "any"}>`;
179
- }
180
- if (prop.format && prop.type) {
181
- return `${prop.type} (${prop.format})`;
182
- }
183
- return prop.type || "any";
184
- }
185
- function escapePipe(text) {
186
- return text.replace(/\|/g, "\\|").replace(/\n/g, " ");
187
- }
188
- function paramTable(schema) {
189
- if (!schema || !schema.properties || Object.keys(schema.properties).length === 0) {
190
- return "_No parameters._";
191
- }
192
- const required = new Set(schema.required || []);
193
- const rows = ["| Parameter | Type | Required | Description |", "|---|---|:-:|---|"];
194
- for (const [name, prop] of Object.entries(schema.properties)) {
195
- const type = describeType(prop);
196
- const req = required.has(name) ? "✓" : "";
197
- const desc = escapePipe(prop.description || "");
198
- rows.push(`| \`${name}\` | ${type} | ${req} | ${desc} |`);
199
- }
200
- return rows.join("\n");
201
- }
202
- function toolSection(name, description, schema) {
203
- return [
204
- `### \`${name}\``,
205
- "",
206
- `*${rwBadge(name)}*`,
207
- "",
208
- description,
209
- "",
210
- "**Parameters**",
211
- "",
212
- paramTable(schema),
213
- "",
214
- ].join("\n");
215
- }
216
- function buildGroupPage(id, toolNames) {
217
- const meta = GROUP_META[id];
218
- const lines = [`# ${meta.title}`, "", meta.blurb, ""];
219
- const toggle = computeToggleNote(id);
220
- if (toggle) {
221
- lines.push(`!!! note "Feature toggle"`);
222
- lines.push(` ${toggle}`);
223
- lines.push("");
224
- }
225
- // Quick index
226
- lines.push("## Tools in this group");
227
- lines.push("");
228
- for (const name of toolNames) {
229
- lines.push(`- [\`${name}\`](#${name}) — ${rwBadge(name)}`);
230
- }
231
- lines.push("");
232
- lines.push("---");
233
- lines.push("");
234
- for (const name of toolNames) {
235
- const tool = allTools.find(t => t.name === name);
236
- if (!tool) {
237
- throw new Error(`Tool '${name}' referenced in toolset '${id}' but missing from allTools registry`);
238
- }
239
- lines.push(toolSection(name, tool.description, tool.inputSchema));
240
- }
241
- return lines.join("\n");
242
- }
243
- function buildToggleSection(groupedToolsList) {
244
- const grouped = groupedToolsList.filter(([id]) => GROUP_META[id]);
245
- const defaults = grouped.filter(([id]) => isDefaultToolset(id));
246
- const optins = grouped.filter(([id]) => !isDefaultToolset(id));
247
- const formatList = (items) => items
248
- .map(([id]) => {
249
- const slug = id.replace(/_/g, "-");
250
- const legacy = LEGACY_TOGGLE_ENV[id];
251
- const suffix = legacy ? ` (also \`${legacy}=true\`)` : "";
252
- return `[${GROUP_META[id].title}](${slug}.md)${suffix}`;
253
- })
254
- .join(", ");
255
- return [
256
- "| Status | Groups |",
257
- "|---|---|",
258
- `| **Default** — always exposed | ${formatList(defaults)} |`,
259
- `| **Opt-in** — must be enabled | ${formatList(optins)} |`,
260
- "",
261
- "**How to enable opt-in groups** (any one is sufficient):",
262
- "",
263
- "- `GITLAB_TOOLSETS=<group,…>` — comma-separated toolset IDs.",
264
- "- `GITLAB_TOOLSETS=all` — enables every group.",
265
- "- `GITLAB_TOOLS=<tool,…>` — enables individual tools regardless of group.",
266
- "- `USE_PIPELINE=true` / `USE_MILESTONE=true` / `USE_GITLAB_WIKI=true` —" +
267
- " legacy single-group flags (Pipelines, Milestones, Wiki only).",
268
- "- Call the `discover_tools` MCP tool at runtime to activate categories" +
269
- " for the current session.",
270
- ];
271
- }
272
- function buildIndexPage(groupedToolsList) {
273
- const lines = [
274
- "# Tools Reference",
275
- "",
276
- "Complete catalog of every tool the GitLab MCP server exposes.",
277
- "",
278
- "Which of these have an MCP `tools/call` test is tracked in",
279
- "[Tool invocation coverage](../reference/tool-coverage.md).",
280
- "",
281
- "> **Setup first** — if you haven't connected your Personal Access Token or",
282
- "> OAuth credentials yet, follow one of the [client setup guides](../clients/claude-code.md)",
283
- "> or read [Getting Started](../getting-started/index.md). Tools listed below",
284
- "> will be unavailable until the server is authenticated.",
285
- "",
286
- "## Feature toggles",
287
- "",
288
- "Toolsets are split into a **default** set (exposed automatically) and an",
289
- "**opt-in** set (must be explicitly enabled). The lists below are derived",
290
- "directly from `TOOLSET_DEFINITIONS` in",
291
- "[`tools/registry.ts`](https://github.com/zereight/gitlab-mcp/blob/main/tools/registry.ts).",
292
- "",
293
- ...buildToggleSection(groupedToolsList),
294
- "",
295
- "Permission modes control which tools are exposed:",
296
- "",
297
- "- `GITLAB_PERMISSION_MODE=readonly` — hides every write tool regardless of toggles.",
298
- "- `GITLAB_PERMISSION_MODE=modify` — allows create/update but blocks delete and teardown tools: every `delete_*` tool, `erase_pipeline_job`, `purge_dependency_proxy_cache`, the destructive teardown verbs `cancel_pipeline`, `cancel_pipeline_job`, `stop_environment`, `stop_stale_environments`, `unprotect_branch`, plus `push_files` `delete`/`move` actions.",
299
- "- `GITLAB_READ_ONLY_MODE=true` (deprecated) — same as `readonly`; prefer `GITLAB_PERMISSION_MODE=readonly`.",
300
- "",
301
- "The `modify` guard applies to typed tools (`tools/list` and `tools/call`) and to destructive mutations sent through `execute_graphql`: any top-level mutation field whose name contains a deletion verb (`delete`, `destroy`, `remove`, `prune`, `purge`, `erase`) or a teardown verb (`revoke`, `cancel`, `stop`, `terminate`, `unprotect`, `disable`, `deactivate`, `drop`, `unschedule`). See [Environment Variables](../configuration/environment-variables.md#gitlab_permission_mode).",
302
- "",
303
- "See [Environment Variables](../configuration/environment-variables.md)",
304
- "and [CLI Arguments](../getting-started/cli-arguments.md) for the full list.",
305
- "",
306
- "## Legend",
307
- "",
308
- "| Marker | Meaning |",
309
- "|---|---|",
310
- "| 📖 | **Read-only** — fetches data, does not modify GitLab state. Safe to invoke freely. |",
311
- "| ✏️ | **Writes** — creates, updates, or deletes data on GitLab. Confirm intent before running. |",
312
- "",
313
- "## Browse by group",
314
- "",
315
- "Each group has its own page with full parameter tables — click any tool name to jump to its details, or click the group title for the per-group view.",
316
- "",
317
- ];
318
- for (const [id, tools] of groupedToolsList) {
319
- const meta = GROUP_META[id];
320
- const slug = id.replace(/_/g, "-");
321
- lines.push(`### [${meta.title}](${slug}.md)`);
322
- lines.push("");
323
- lines.push(`${meta.blurb} *(${tools.length} tools)*`);
324
- lines.push("");
325
- const toggle = computeToggleNote(id);
326
- if (toggle) {
327
- lines.push(`> ${toggle}`);
328
- lines.push("");
329
- }
330
- lines.push("| Tool | What it does | R/W |");
331
- lines.push("|---|---|:-:|");
332
- for (const name of tools) {
333
- const tool = allTools.find(t => t.name === name);
334
- if (!tool)
335
- continue;
336
- const desc = escapePipe(tool.description);
337
- const marker = classify(name) === "read" ? "📖" : "✏️";
338
- lines.push(`| [\`${name}\`](${slug}.md#${name}) | ${desc} | ${marker} |`);
339
- }
340
- lines.push("");
341
- }
342
- lines.push("---");
343
- lines.push("");
344
- lines.push("## Argument schemas");
345
- lines.push("");
346
- lines.push("Each group page includes a parameter table per tool, generated from");
347
- lines.push("the authoritative Zod schemas in");
348
- lines.push("[`schemas.ts`](https://github.com/zereight/gitlab-mcp/blob/main/schemas.ts).");
349
- lines.push("For runtime schema inspection from a connected MCP client, call the");
350
- lines.push("`discover_tools` tool.");
351
- return lines.join("\n");
352
- }
353
- // --- Main -----------------------------------------------------------------
354
- function main() {
355
- mkdirSync(OUT_DIR, { recursive: true });
356
- // Clean previously generated per-group files (keep index.md until last)
357
- for (const file of readdirSync(OUT_DIR)) {
358
- const full = join(OUT_DIR, file);
359
- if (statSync(full).isFile() && file.endsWith(".md")) {
360
- unlinkSync(full);
361
- }
362
- }
363
- const grouped = [];
364
- const allCategorizedNames = new Set();
365
- for (const id of GROUP_ORDER) {
366
- const def = TOOLSET_DEFINITIONS.find(d => d.id === id);
367
- if (!def) {
368
- throw new Error(`Toolset '${id}' listed in GROUP_ORDER but missing from TOOLSET_DEFINITIONS — keep them in sync`);
369
- }
370
- // Preserve insertion order from TOOLSET_DEFINITIONS
371
- const tools = [...def.tools];
372
- for (const t of tools)
373
- allCategorizedNames.add(t);
374
- grouped.push([id, tools]);
375
- const page = buildGroupPage(id, tools);
376
- const slug = id.replace(/_/g, "-");
377
- writeFileSync(join(OUT_DIR, `${slug}.md`), page);
378
- console.log(`generated docs/tools/${slug}.md — ${tools.length} tools`);
379
- }
380
- // Tools NOT in any toolset (e.g., execute_graphql, discover_tools)
381
- const uncategorized = allTools.map(t => t.name).filter(n => !allCategorizedNames.has(n));
382
- if (uncategorized.length > 0) {
383
- const metaToggle = computeToggleNote("meta");
384
- const lines = [
385
- `# Meta & GraphQL`,
386
- "",
387
- "Tools the MCP exposes that aren't tied to a specific GitLab feature group — server diagnostics and the GraphQL escape hatch.",
388
- "",
389
- ];
390
- if (metaToggle) {
391
- lines.push(`!!! note "Feature toggle"`);
392
- lines.push(` ${metaToggle}`);
393
- lines.push("");
394
- }
395
- lines.push("## Tools in this group");
396
- lines.push("");
397
- for (const name of uncategorized) {
398
- lines.push(`- [\`${name}\`](#${name}) — ${rwBadge(name)}`);
399
- }
400
- lines.push("");
401
- lines.push("---");
402
- lines.push("");
403
- for (const name of uncategorized) {
404
- const tool = allTools.find(t => t.name === name);
405
- if (!tool) {
406
- throw new Error(`Uncategorized tool '${name}' missing from allTools registry`);
407
- }
408
- lines.push(toolSection(name, tool.description, tool.inputSchema));
409
- }
410
- writeFileSync(join(OUT_DIR, "meta.md"), lines.join("\n"));
411
- console.log(`generated docs/tools/meta.md — ${uncategorized.length} tools`);
412
- grouped.push(["meta", uncategorized]);
413
- GROUP_META["meta"] = {
414
- title: "Meta & GraphQL",
415
- blurb: "Server diagnostics, tool discovery, and the GraphQL escape hatch.",
416
- };
417
- }
418
- writeFileSync(join(OUT_DIR, "index.md"), buildIndexPage(grouped));
419
- console.log(`generated docs/tools/index.md`);
420
- // Emit nav fragment so you can paste it into mkdocs.yml if needed
421
- console.log("\n--- mkdocs.yml nav fragment ---");
422
- console.log(" - Tools:");
423
- console.log(" - Overview: tools/index.md");
424
- for (const [id] of grouped) {
425
- const meta = GROUP_META[id];
426
- const slug = id.replace(/_/g, "-");
427
- console.log(` - ${meta.title}: tools/${slug}.md`);
428
- }
429
- }
430
- main();