@structured-world/gitlab-mcp 6.8.0 → 6.10.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/LICENSE +202 -21
- package/LICENSE.MIT +21 -0
- package/README.md +169 -1
- package/dist/src/cli/list-tools.d.ts +2 -0
- package/dist/src/cli/list-tools.js +768 -0
- package/dist/src/cli/list-tools.js.map +1 -0
- package/dist/src/config.d.ts +7 -0
- package/dist/src/config.js +96 -1
- package/dist/src/config.js.map +1 -1
- package/dist/src/entities/core/registry.js +68 -63
- package/dist/src/entities/core/registry.js.map +1 -1
- package/dist/src/entities/core/schema-readonly.d.ts +93 -36
- package/dist/src/entities/core/schema-readonly.js +146 -121
- package/dist/src/entities/core/schema-readonly.js.map +1 -1
- package/dist/src/entities/core/schema.d.ts +33 -23
- package/dist/src/entities/core/schema.js +65 -60
- package/dist/src/entities/core/schema.js.map +1 -1
- package/dist/src/entities/files/registry.js +14 -21
- package/dist/src/entities/files/registry.js.map +1 -1
- package/dist/src/entities/files/schema-readonly.d.ts +8 -7
- package/dist/src/entities/files/schema-readonly.js +20 -25
- package/dist/src/entities/files/schema-readonly.js.map +1 -1
- package/dist/src/entities/files/schema.d.ts +22 -15
- package/dist/src/entities/files/schema.js +32 -73
- package/dist/src/entities/files/schema.js.map +1 -1
- package/dist/src/entities/integrations/registry.js +3 -0
- package/dist/src/entities/integrations/registry.js.map +1 -1
- package/dist/src/entities/integrations/schema.d.ts +114 -8
- package/dist/src/entities/integrations/schema.js +27 -9
- package/dist/src/entities/integrations/schema.js.map +1 -1
- package/dist/src/entities/labels/registry.js +8 -7
- package/dist/src/entities/labels/registry.js.map +1 -1
- package/dist/src/entities/labels/schema-readonly.d.ts +8 -7
- package/dist/src/entities/labels/schema-readonly.js +20 -18
- package/dist/src/entities/labels/schema-readonly.js.map +1 -1
- package/dist/src/entities/labels/schema.d.ts +15 -8
- package/dist/src/entities/labels/schema.js +36 -27
- package/dist/src/entities/labels/schema.js.map +1 -1
- package/dist/src/entities/milestones/registry.js +7 -8
- package/dist/src/entities/milestones/registry.js.map +1 -1
- package/dist/src/entities/milestones/schema-readonly.d.ts +25 -10
- package/dist/src/entities/milestones/schema-readonly.js +47 -26
- package/dist/src/entities/milestones/schema-readonly.js.map +1 -1
- package/dist/src/entities/milestones/schema.d.ts +19 -9
- package/dist/src/entities/milestones/schema.js +31 -20
- package/dist/src/entities/milestones/schema.js.map +1 -1
- package/dist/src/entities/mrs/registry.js +75 -79
- package/dist/src/entities/mrs/registry.js.map +1 -1
- package/dist/src/entities/mrs/schema-readonly.d.ts +36 -23
- package/dist/src/entities/mrs/schema-readonly.js +197 -338
- package/dist/src/entities/mrs/schema-readonly.js.map +1 -1
- package/dist/src/entities/mrs/schema.d.ts +113 -37
- package/dist/src/entities/mrs/schema.js +140 -258
- package/dist/src/entities/mrs/schema.js.map +1 -1
- package/dist/src/entities/pipelines/registry.js +10 -4
- package/dist/src/entities/pipelines/registry.js.map +1 -1
- package/dist/src/entities/pipelines/schema-readonly.d.ts +30 -14
- package/dist/src/entities/pipelines/schema-readonly.js +62 -52
- package/dist/src/entities/pipelines/schema-readonly.js.map +1 -1
- package/dist/src/entities/pipelines/schema.d.ts +23 -16
- package/dist/src/entities/pipelines/schema.js +44 -26
- package/dist/src/entities/pipelines/schema.js.map +1 -1
- package/dist/src/entities/snippets/registry.js +79 -67
- package/dist/src/entities/snippets/registry.js.map +1 -1
- package/dist/src/entities/snippets/schema-readonly.d.ts +8 -9
- package/dist/src/entities/snippets/schema-readonly.js +30 -35
- package/dist/src/entities/snippets/schema-readonly.js.map +1 -1
- package/dist/src/entities/snippets/schema.d.ts +7 -11
- package/dist/src/entities/snippets/schema.js +31 -65
- package/dist/src/entities/snippets/schema.js.map +1 -1
- package/dist/src/entities/variables/registry.js +9 -5
- package/dist/src/entities/variables/registry.js.map +1 -1
- package/dist/src/entities/variables/schema-readonly.d.ts +9 -9
- package/dist/src/entities/variables/schema-readonly.js +22 -18
- package/dist/src/entities/variables/schema-readonly.js.map +1 -1
- package/dist/src/entities/variables/schema.d.ts +24 -7
- package/dist/src/entities/variables/schema.js +67 -38
- package/dist/src/entities/variables/schema.js.map +1 -1
- package/dist/src/entities/webhooks/registry.js +48 -46
- package/dist/src/entities/webhooks/registry.js.map +1 -1
- package/dist/src/entities/webhooks/schema-readonly.d.ts +9 -8
- package/dist/src/entities/webhooks/schema-readonly.js +14 -9
- package/dist/src/entities/webhooks/schema-readonly.js.map +1 -1
- package/dist/src/entities/webhooks/schema.d.ts +79 -26
- package/dist/src/entities/webhooks/schema.js +70 -61
- package/dist/src/entities/webhooks/schema.js.map +1 -1
- package/dist/src/entities/wiki/registry.js +7 -4
- package/dist/src/entities/wiki/registry.js.map +1 -1
- package/dist/src/entities/wiki/schema-readonly.d.ts +7 -7
- package/dist/src/entities/wiki/schema-readonly.js +11 -15
- package/dist/src/entities/wiki/schema-readonly.js.map +1 -1
- package/dist/src/entities/wiki/schema.d.ts +19 -8
- package/dist/src/entities/wiki/schema.js +32 -29
- package/dist/src/entities/wiki/schema.js.map +1 -1
- package/dist/src/entities/workitems/registry.js +7 -8
- package/dist/src/entities/workitems/registry.js.map +1 -1
- package/dist/src/entities/workitems/schema-readonly.d.ts +7 -8
- package/dist/src/entities/workitems/schema-readonly.js +12 -14
- package/dist/src/entities/workitems/schema-readonly.js.map +1 -1
- package/dist/src/entities/workitems/schema.d.ts +17 -11
- package/dist/src/entities/workitems/schema.js +25 -25
- package/dist/src/entities/workitems/schema.js.map +1 -1
- package/dist/src/registry-manager.d.ts +1 -0
- package/dist/src/registry-manager.js +45 -11
- package/dist/src/registry-manager.js.map +1 -1
- package/dist/src/utils/schema-utils.d.ts +28 -0
- package/dist/src/utils/schema-utils.js +240 -0
- package/dist/src/utils/schema-utils.js.map +1 -0
- package/dist/structured-world-gitlab-mcp-6.10.0.tgz +0 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +4 -4
- package/dist/structured-world-gitlab-mcp-6.8.0.tgz +0 -0
|
@@ -0,0 +1,768 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
|
+
if (k2 === undefined) k2 = k;
|
|
5
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
6
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
7
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
8
|
+
}
|
|
9
|
+
Object.defineProperty(o, k2, desc);
|
|
10
|
+
}) : (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
o[k2] = m[k];
|
|
13
|
+
}));
|
|
14
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
15
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
16
|
+
}) : function(o, v) {
|
|
17
|
+
o["default"] = v;
|
|
18
|
+
});
|
|
19
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
20
|
+
var ownKeys = function(o) {
|
|
21
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
22
|
+
var ar = [];
|
|
23
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
24
|
+
return ar;
|
|
25
|
+
};
|
|
26
|
+
return ownKeys(o);
|
|
27
|
+
};
|
|
28
|
+
return function (mod) {
|
|
29
|
+
if (mod && mod.__esModule) return mod;
|
|
30
|
+
var result = {};
|
|
31
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
32
|
+
__setModuleDefault(result, mod);
|
|
33
|
+
return result;
|
|
34
|
+
};
|
|
35
|
+
})();
|
|
36
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
37
|
+
exports.main = main;
|
|
38
|
+
const fs = __importStar(require("fs"));
|
|
39
|
+
const path = __importStar(require("path"));
|
|
40
|
+
const registry_manager_1 = require("../registry-manager");
|
|
41
|
+
const ToolAvailability_1 = require("../services/ToolAvailability");
|
|
42
|
+
function parseArgs() {
|
|
43
|
+
const args = process.argv.slice(2);
|
|
44
|
+
const options = {
|
|
45
|
+
format: "markdown",
|
|
46
|
+
showEnv: false,
|
|
47
|
+
verbose: false,
|
|
48
|
+
detail: false,
|
|
49
|
+
noExamples: false,
|
|
50
|
+
toc: false,
|
|
51
|
+
};
|
|
52
|
+
for (let i = 0; i < args.length; i++) {
|
|
53
|
+
const arg = args[i];
|
|
54
|
+
switch (arg) {
|
|
55
|
+
case "--json":
|
|
56
|
+
options.format = "json";
|
|
57
|
+
break;
|
|
58
|
+
case "--simple":
|
|
59
|
+
options.format = "simple";
|
|
60
|
+
break;
|
|
61
|
+
case "--export":
|
|
62
|
+
options.format = "export";
|
|
63
|
+
break;
|
|
64
|
+
case "--entity":
|
|
65
|
+
if (i + 1 >= args.length) {
|
|
66
|
+
console.error("Error: --entity flag requires a value.");
|
|
67
|
+
console.error("Usage: yarn list-tools --entity <entity_name>");
|
|
68
|
+
process.exit(1);
|
|
69
|
+
}
|
|
70
|
+
options.entity = args[++i];
|
|
71
|
+
break;
|
|
72
|
+
case "--tool":
|
|
73
|
+
if (i + 1 >= args.length) {
|
|
74
|
+
console.error("Error: --tool flag requires a value.");
|
|
75
|
+
console.error("Usage: yarn list-tools --tool <tool_name>");
|
|
76
|
+
process.exit(1);
|
|
77
|
+
}
|
|
78
|
+
options.tool = args[++i];
|
|
79
|
+
break;
|
|
80
|
+
case "--env":
|
|
81
|
+
options.showEnv = true;
|
|
82
|
+
break;
|
|
83
|
+
case "--verbose":
|
|
84
|
+
case "-v":
|
|
85
|
+
options.verbose = true;
|
|
86
|
+
break;
|
|
87
|
+
case "--detail":
|
|
88
|
+
options.detail = true;
|
|
89
|
+
break;
|
|
90
|
+
case "--no-examples":
|
|
91
|
+
options.noExamples = true;
|
|
92
|
+
break;
|
|
93
|
+
case "--toc":
|
|
94
|
+
options.toc = true;
|
|
95
|
+
break;
|
|
96
|
+
case "--help":
|
|
97
|
+
case "-h":
|
|
98
|
+
printHelp();
|
|
99
|
+
process.exit(0);
|
|
100
|
+
break;
|
|
101
|
+
default:
|
|
102
|
+
if (arg.startsWith("-")) {
|
|
103
|
+
console.error(`Error: Unrecognized option '${arg}'.`);
|
|
104
|
+
console.error("Use '--help' to see available options.");
|
|
105
|
+
process.exit(1);
|
|
106
|
+
}
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return options;
|
|
111
|
+
}
|
|
112
|
+
function printHelp() {
|
|
113
|
+
console.log(`
|
|
114
|
+
GitLab MCP Tool Lister
|
|
115
|
+
|
|
116
|
+
Usage: yarn list-tools [options]
|
|
117
|
+
|
|
118
|
+
Options:
|
|
119
|
+
--json Output in JSON format
|
|
120
|
+
--simple Simple list of tool names
|
|
121
|
+
--export Generate complete TOOLS.md documentation
|
|
122
|
+
--entity <name> Filter by entity (e.g., workitems, labels, mrs)
|
|
123
|
+
--tool <name> Show details for specific tool
|
|
124
|
+
--env Show environment configuration
|
|
125
|
+
--verbose, -v Show additional details
|
|
126
|
+
--detail Show all tools with their input schemas
|
|
127
|
+
--no-examples Skip example JSON blocks (for --export)
|
|
128
|
+
--toc Include table of contents (for --export)
|
|
129
|
+
--help, -h Show this help
|
|
130
|
+
|
|
131
|
+
Examples:
|
|
132
|
+
yarn list-tools # List all tools in markdown
|
|
133
|
+
yarn list-tools --json # JSON output
|
|
134
|
+
yarn list-tools --export # Generate TOOLS.md to stdout
|
|
135
|
+
yarn list-tools --export > docs/TOOLS.md # Generate TOOLS.md to file
|
|
136
|
+
yarn list-tools --export --toc # With table of contents
|
|
137
|
+
yarn list-tools --export --no-examples # Skip example JSON blocks
|
|
138
|
+
yarn list-tools --entity workitems # Only work items tools
|
|
139
|
+
yarn list-tools --tool list_work_items # Specific tool details
|
|
140
|
+
GITLAB_READONLY=true yarn list-tools # Show read-only tools
|
|
141
|
+
GITLAB_DENIED_TOOLS_REGEX="^create" yarn list-tools # Test filtering
|
|
142
|
+
|
|
143
|
+
Environment Variables:
|
|
144
|
+
GITLAB_READONLY Show only read-only tools
|
|
145
|
+
GITLAB_DENIED_TOOLS_REGEX Regex pattern to exclude tools
|
|
146
|
+
GITLAB_ALLOWED_TOOLS_REGEX Regex pattern to include tools
|
|
147
|
+
`);
|
|
148
|
+
}
|
|
149
|
+
function resolveJsonSchemaType(prop, schema) {
|
|
150
|
+
if (prop.$ref) {
|
|
151
|
+
const refPath = prop.$ref.replace("#/properties/", "");
|
|
152
|
+
const referencedProp = schema.properties?.[refPath];
|
|
153
|
+
if (referencedProp) {
|
|
154
|
+
return resolveJsonSchemaType(referencedProp, schema);
|
|
155
|
+
}
|
|
156
|
+
return "reference";
|
|
157
|
+
}
|
|
158
|
+
if (prop.type) {
|
|
159
|
+
if (prop.type === "array" && prop.items) {
|
|
160
|
+
const itemType = resolveJsonSchemaType(prop.items, schema);
|
|
161
|
+
return `${itemType}[]`;
|
|
162
|
+
}
|
|
163
|
+
return prop.type;
|
|
164
|
+
}
|
|
165
|
+
if (prop.enum) {
|
|
166
|
+
return "enum";
|
|
167
|
+
}
|
|
168
|
+
if (prop.oneOf ?? prop.anyOf) {
|
|
169
|
+
const unionTypes = (prop.oneOf ?? prop.anyOf)?.map(option => resolveJsonSchemaType(option, schema)) ?? [];
|
|
170
|
+
return unionTypes.join(" | ");
|
|
171
|
+
}
|
|
172
|
+
return "unknown";
|
|
173
|
+
}
|
|
174
|
+
function getParameterDescription(schema) {
|
|
175
|
+
const params = [];
|
|
176
|
+
if (schema.properties) {
|
|
177
|
+
for (const [key, value] of Object.entries(schema.properties)) {
|
|
178
|
+
const prop = value;
|
|
179
|
+
const required = schema.required?.includes(key) ?? false;
|
|
180
|
+
const type = resolveJsonSchemaType(prop, schema);
|
|
181
|
+
const description = prop.description ?? "";
|
|
182
|
+
let paramStr = ` - \`${key}\` (${type}${required ? ", required" : ", optional"})`;
|
|
183
|
+
if (description) {
|
|
184
|
+
paramStr += `: ${description}`;
|
|
185
|
+
}
|
|
186
|
+
params.push(paramStr);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
if (schema._def?.schema?._def?.checks) {
|
|
190
|
+
const checks = schema._def.schema._def.checks;
|
|
191
|
+
for (const check of checks) {
|
|
192
|
+
if (check.message) {
|
|
193
|
+
params.push(` - **Validation**: ${check.message}`);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
return params;
|
|
198
|
+
}
|
|
199
|
+
function printEnvironmentInfo() {
|
|
200
|
+
console.log("=== Environment Configuration ===\n");
|
|
201
|
+
console.log(`GITLAB_READONLY: ${process.env.GITLAB_READONLY ?? "false"}`);
|
|
202
|
+
console.log(`GITLAB_DENIED_TOOLS_REGEX: ${process.env.GITLAB_DENIED_TOOLS_REGEX ?? "(not set)"}`);
|
|
203
|
+
console.log(`GITLAB_ALLOWED_TOOLS_REGEX: ${process.env.GITLAB_ALLOWED_TOOLS_REGEX ?? "(not set)"}`);
|
|
204
|
+
console.log(`GITLAB_API_URL: ${process.env.GITLAB_API_URL ?? "https://gitlab.com"}`);
|
|
205
|
+
console.log();
|
|
206
|
+
}
|
|
207
|
+
function getToolTierInfo(toolName) {
|
|
208
|
+
const requirement = ToolAvailability_1.ToolAvailability.getToolRequirement(toolName);
|
|
209
|
+
if (!requirement)
|
|
210
|
+
return "";
|
|
211
|
+
const tierBadge = {
|
|
212
|
+
free: "Free",
|
|
213
|
+
premium: "Premium",
|
|
214
|
+
ultimate: "Ultimate",
|
|
215
|
+
}[requirement.requiredTier] ?? requirement.requiredTier;
|
|
216
|
+
return `[tier: ${tierBadge}]`;
|
|
217
|
+
}
|
|
218
|
+
const ENTITY_TOOLS = {
|
|
219
|
+
Core: [
|
|
220
|
+
"browse_projects",
|
|
221
|
+
"browse_namespaces",
|
|
222
|
+
"browse_commits",
|
|
223
|
+
"browse_events",
|
|
224
|
+
"create_branch",
|
|
225
|
+
"create_group",
|
|
226
|
+
"manage_repository",
|
|
227
|
+
"list_project_members",
|
|
228
|
+
"list_group_iterations",
|
|
229
|
+
"download_attachment",
|
|
230
|
+
"get_users",
|
|
231
|
+
],
|
|
232
|
+
"Work Items": ["browse_work_items", "manage_work_item"],
|
|
233
|
+
"Merge Requests": [
|
|
234
|
+
"browse_merge_requests",
|
|
235
|
+
"browse_mr_discussions",
|
|
236
|
+
"manage_merge_request",
|
|
237
|
+
"manage_mr_discussion",
|
|
238
|
+
"manage_draft_notes",
|
|
239
|
+
],
|
|
240
|
+
Labels: ["browse_labels", "manage_label"],
|
|
241
|
+
Wiki: ["browse_wiki", "manage_wiki"],
|
|
242
|
+
Pipelines: ["browse_pipelines", "manage_pipeline", "manage_pipeline_job"],
|
|
243
|
+
Variables: ["browse_variables", "manage_variable"],
|
|
244
|
+
Milestones: ["browse_milestones", "manage_milestone"],
|
|
245
|
+
Files: ["browse_files", "manage_files"],
|
|
246
|
+
Snippets: ["browse_snippets", "manage_snippet"],
|
|
247
|
+
Webhooks: ["list_webhooks", "manage_webhook"],
|
|
248
|
+
Integrations: ["list_integrations", "manage_integration"],
|
|
249
|
+
Todos: ["list_todos", "manage_todos"],
|
|
250
|
+
};
|
|
251
|
+
function groupToolsByEntity(tools) {
|
|
252
|
+
const grouped = new Map();
|
|
253
|
+
const toolToEntity = new Map();
|
|
254
|
+
for (const [entity, toolNames] of Object.entries(ENTITY_TOOLS)) {
|
|
255
|
+
for (const toolName of toolNames) {
|
|
256
|
+
toolToEntity.set(toolName, entity);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
for (const tool of tools) {
|
|
260
|
+
const entity = toolToEntity.get(tool.name) ?? "Other";
|
|
261
|
+
if (!grouped.has(entity)) {
|
|
262
|
+
grouped.set(entity, []);
|
|
263
|
+
}
|
|
264
|
+
grouped.get(entity).push(tool);
|
|
265
|
+
}
|
|
266
|
+
const entityOrder = [
|
|
267
|
+
"Core",
|
|
268
|
+
"Work Items",
|
|
269
|
+
"Merge Requests",
|
|
270
|
+
"Labels",
|
|
271
|
+
"Milestones",
|
|
272
|
+
"Pipelines",
|
|
273
|
+
"Variables",
|
|
274
|
+
"Files",
|
|
275
|
+
"Wiki",
|
|
276
|
+
"Snippets",
|
|
277
|
+
"Webhooks",
|
|
278
|
+
"Integrations",
|
|
279
|
+
"Todos",
|
|
280
|
+
"Other",
|
|
281
|
+
];
|
|
282
|
+
const sortedGrouped = new Map();
|
|
283
|
+
for (const entity of entityOrder) {
|
|
284
|
+
if (grouped.has(entity)) {
|
|
285
|
+
sortedGrouped.set(entity, grouped.get(entity));
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
return sortedGrouped;
|
|
289
|
+
}
|
|
290
|
+
const ACTION_DESCRIPTIONS = {
|
|
291
|
+
list: "List items with filtering and pagination",
|
|
292
|
+
get: "Get a single item by ID",
|
|
293
|
+
create: "Create a new item",
|
|
294
|
+
update: "Update an existing item",
|
|
295
|
+
delete: "Delete an item",
|
|
296
|
+
search: "Search for items",
|
|
297
|
+
diffs: "Get file changes/diffs",
|
|
298
|
+
compare: "Compare two branches or commits",
|
|
299
|
+
merge: "Merge a merge request",
|
|
300
|
+
approve: "Approve a merge request",
|
|
301
|
+
unapprove: "Remove approval from a merge request",
|
|
302
|
+
rebase: "Rebase a merge request",
|
|
303
|
+
cancel: "Cancel a running operation",
|
|
304
|
+
retry: "Retry a failed operation",
|
|
305
|
+
play: "Run a manual job",
|
|
306
|
+
publish: "Publish draft notes",
|
|
307
|
+
drafts: "List draft notes",
|
|
308
|
+
draft: "Get a single draft note",
|
|
309
|
+
resolve: "Resolve a discussion thread",
|
|
310
|
+
unresolve: "Unresolve a discussion thread",
|
|
311
|
+
note: "Add a note/comment",
|
|
312
|
+
mark_done: "Mark as done",
|
|
313
|
+
mark_pending: "Mark as pending",
|
|
314
|
+
disable: "Disable the integration",
|
|
315
|
+
test: "Test a webhook",
|
|
316
|
+
read: "Read item details",
|
|
317
|
+
};
|
|
318
|
+
function extractActions(schema) {
|
|
319
|
+
const actions = [];
|
|
320
|
+
if (schema.oneOf && Array.isArray(schema.oneOf)) {
|
|
321
|
+
for (const branch of schema.oneOf) {
|
|
322
|
+
const actionProp = branch.properties?.action;
|
|
323
|
+
const actionName = actionProp?.const;
|
|
324
|
+
if (actionName) {
|
|
325
|
+
const description = actionProp?.description ??
|
|
326
|
+
ACTION_DESCRIPTIONS[actionName] ??
|
|
327
|
+
`Perform ${actionName} operation`;
|
|
328
|
+
actions.push({ name: actionName, description });
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
return actions;
|
|
332
|
+
}
|
|
333
|
+
const actionProp = schema.properties?.action;
|
|
334
|
+
if (actionProp?.enum && Array.isArray(actionProp.enum)) {
|
|
335
|
+
for (const actionName of actionProp.enum) {
|
|
336
|
+
if (typeof actionName === "string") {
|
|
337
|
+
const description = ACTION_DESCRIPTIONS[actionName] ?? `Perform ${actionName} operation`;
|
|
338
|
+
actions.push({ name: actionName, description });
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
return actions;
|
|
343
|
+
}
|
|
344
|
+
function extractParameters(schema) {
|
|
345
|
+
if (!schema.properties)
|
|
346
|
+
return [];
|
|
347
|
+
const requiredFields = schema.required ?? [];
|
|
348
|
+
const params = [];
|
|
349
|
+
for (const [name, prop] of Object.entries(schema.properties)) {
|
|
350
|
+
params.push({
|
|
351
|
+
name,
|
|
352
|
+
type: resolveJsonSchemaType(prop, schema),
|
|
353
|
+
required: requiredFields.includes(name),
|
|
354
|
+
description: prop.description ?? "",
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
return sortParameters(params);
|
|
358
|
+
}
|
|
359
|
+
function sortParameters(params) {
|
|
360
|
+
return params.sort((a, b) => {
|
|
361
|
+
if (a.required && !b.required)
|
|
362
|
+
return -1;
|
|
363
|
+
if (!a.required && b.required)
|
|
364
|
+
return 1;
|
|
365
|
+
if (a.name === "action")
|
|
366
|
+
return -1;
|
|
367
|
+
if (b.name === "action")
|
|
368
|
+
return 1;
|
|
369
|
+
return a.name.localeCompare(b.name);
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
function extractParametersGrouped(schema) {
|
|
373
|
+
const result = {
|
|
374
|
+
common: [],
|
|
375
|
+
byAction: new Map(),
|
|
376
|
+
};
|
|
377
|
+
if (!schema.oneOf || !Array.isArray(schema.oneOf)) {
|
|
378
|
+
result.common = extractParameters(schema);
|
|
379
|
+
return result;
|
|
380
|
+
}
|
|
381
|
+
const totalActions = schema.oneOf.length;
|
|
382
|
+
const paramOccurrences = new Map();
|
|
383
|
+
for (const branch of schema.oneOf) {
|
|
384
|
+
const actionName = branch.properties?.action?.const;
|
|
385
|
+
if (!actionName || !branch.properties)
|
|
386
|
+
continue;
|
|
387
|
+
const requiredFields = branch.required ?? [];
|
|
388
|
+
for (const [name, prop] of Object.entries(branch.properties)) {
|
|
389
|
+
if (name === "action")
|
|
390
|
+
continue;
|
|
391
|
+
const type = resolveJsonSchemaType(prop, branch);
|
|
392
|
+
const required = requiredFields.includes(name);
|
|
393
|
+
const description = prop.description ?? "";
|
|
394
|
+
if (!paramOccurrences.has(name)) {
|
|
395
|
+
paramOccurrences.set(name, {
|
|
396
|
+
actions: new Map(),
|
|
397
|
+
type,
|
|
398
|
+
description,
|
|
399
|
+
});
|
|
400
|
+
}
|
|
401
|
+
const occurrence = paramOccurrences.get(name);
|
|
402
|
+
occurrence.actions.set(actionName, { required, type, description });
|
|
403
|
+
if (description.length > occurrence.description.length) {
|
|
404
|
+
occurrence.description = description;
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
for (const [name, data] of paramOccurrences) {
|
|
409
|
+
if (data.actions.size === totalActions) {
|
|
410
|
+
const requiredInAll = Array.from(data.actions.values()).every(a => a.required);
|
|
411
|
+
result.common.push({
|
|
412
|
+
name,
|
|
413
|
+
type: data.type,
|
|
414
|
+
required: requiredInAll,
|
|
415
|
+
description: data.description,
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
else {
|
|
419
|
+
for (const [actionName, actionData] of data.actions) {
|
|
420
|
+
if (!result.byAction.has(actionName)) {
|
|
421
|
+
result.byAction.set(actionName, []);
|
|
422
|
+
}
|
|
423
|
+
result.byAction.get(actionName).push({
|
|
424
|
+
name,
|
|
425
|
+
type: actionData.type,
|
|
426
|
+
required: actionData.required,
|
|
427
|
+
requiredForAction: actionData.required,
|
|
428
|
+
description: actionData.description || data.description,
|
|
429
|
+
});
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
result.common = sortParameters(result.common);
|
|
434
|
+
for (const [action, params] of result.byAction) {
|
|
435
|
+
result.byAction.set(action, params.sort((a, b) => {
|
|
436
|
+
if (a.requiredForAction && !b.requiredForAction)
|
|
437
|
+
return -1;
|
|
438
|
+
if (!a.requiredForAction && b.requiredForAction)
|
|
439
|
+
return 1;
|
|
440
|
+
return a.name.localeCompare(b.name);
|
|
441
|
+
}));
|
|
442
|
+
}
|
|
443
|
+
return result;
|
|
444
|
+
}
|
|
445
|
+
function generateExample(schema) {
|
|
446
|
+
const example = {};
|
|
447
|
+
const actions = extractActions(schema);
|
|
448
|
+
if (actions.length > 0) {
|
|
449
|
+
example.action = actions[0].name;
|
|
450
|
+
}
|
|
451
|
+
let targetSchema = schema;
|
|
452
|
+
let requiredFields = [];
|
|
453
|
+
if (schema.oneOf && Array.isArray(schema.oneOf) && schema.oneOf.length > 0) {
|
|
454
|
+
targetSchema = schema.oneOf[0];
|
|
455
|
+
requiredFields = targetSchema.required ?? [];
|
|
456
|
+
}
|
|
457
|
+
else if (schema.properties) {
|
|
458
|
+
requiredFields = schema.required ?? [];
|
|
459
|
+
}
|
|
460
|
+
else {
|
|
461
|
+
return example;
|
|
462
|
+
}
|
|
463
|
+
if (!targetSchema.properties)
|
|
464
|
+
return example;
|
|
465
|
+
for (const [name, prop] of Object.entries(targetSchema.properties)) {
|
|
466
|
+
if (name === "action")
|
|
467
|
+
continue;
|
|
468
|
+
const isRequired = requiredFields.includes(name);
|
|
469
|
+
const description = (prop.description ?? "").toLowerCase();
|
|
470
|
+
if (!isRequired)
|
|
471
|
+
continue;
|
|
472
|
+
if (prop.enum && Array.isArray(prop.enum) && prop.enum.length > 0) {
|
|
473
|
+
example[name] = prop.enum[0];
|
|
474
|
+
}
|
|
475
|
+
else if (name.includes("project_id") || name === "projectId") {
|
|
476
|
+
example[name] = "my-group/my-project";
|
|
477
|
+
}
|
|
478
|
+
else if (name.includes("group_id") || name === "groupId") {
|
|
479
|
+
example[name] = "my-group";
|
|
480
|
+
}
|
|
481
|
+
else if (name.includes("namespace")) {
|
|
482
|
+
example[name] = "my-group/my-project";
|
|
483
|
+
}
|
|
484
|
+
else if (name.includes("_iid") || name === "iid") {
|
|
485
|
+
example[name] = "1";
|
|
486
|
+
}
|
|
487
|
+
else if (name.includes("_id") || name === "id") {
|
|
488
|
+
example[name] = "123";
|
|
489
|
+
}
|
|
490
|
+
else if (name === "title") {
|
|
491
|
+
example[name] = "Example title";
|
|
492
|
+
}
|
|
493
|
+
else if (name === "description") {
|
|
494
|
+
example[name] = "Example description";
|
|
495
|
+
}
|
|
496
|
+
else if (name === "url") {
|
|
497
|
+
example[name] = "https://example.com/webhook";
|
|
498
|
+
}
|
|
499
|
+
else if (name === "content") {
|
|
500
|
+
example[name] = "File content here";
|
|
501
|
+
}
|
|
502
|
+
else if (name === "file_path" || name === "path") {
|
|
503
|
+
example[name] = "path/to/file.txt";
|
|
504
|
+
}
|
|
505
|
+
else if (name === "ref" || name === "branch") {
|
|
506
|
+
example[name] = "main";
|
|
507
|
+
}
|
|
508
|
+
else if (name === "from" || name === "to") {
|
|
509
|
+
example[name] = name === "from" ? "main" : "feature-branch";
|
|
510
|
+
}
|
|
511
|
+
else if (description.includes("boolean") || prop.type === "boolean") {
|
|
512
|
+
example[name] = true;
|
|
513
|
+
}
|
|
514
|
+
else if (prop.type === "number" || prop.type === "integer") {
|
|
515
|
+
example[name] = 10;
|
|
516
|
+
}
|
|
517
|
+
else if (prop.type === "array") {
|
|
518
|
+
example[name] = [];
|
|
519
|
+
}
|
|
520
|
+
else {
|
|
521
|
+
example[name] = `example_${name}`;
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
return example;
|
|
525
|
+
}
|
|
526
|
+
function getPackageVersion() {
|
|
527
|
+
try {
|
|
528
|
+
let dir = process.cwd();
|
|
529
|
+
let fallbackVersion = null;
|
|
530
|
+
for (let i = 0; i < 5; i++) {
|
|
531
|
+
const pkgPath = path.join(dir, "package.json");
|
|
532
|
+
if (fs.existsSync(pkgPath)) {
|
|
533
|
+
const content = fs.readFileSync(pkgPath, "utf8");
|
|
534
|
+
const pkg = JSON.parse(content);
|
|
535
|
+
if (fallbackVersion === null && pkg.version) {
|
|
536
|
+
fallbackVersion = pkg.version;
|
|
537
|
+
}
|
|
538
|
+
if (pkg.name === "@structured-world/gitlab-mcp") {
|
|
539
|
+
return pkg.version ?? "unknown";
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
const parent = path.dirname(dir);
|
|
543
|
+
if (parent === dir)
|
|
544
|
+
break;
|
|
545
|
+
dir = parent;
|
|
546
|
+
}
|
|
547
|
+
return fallbackVersion ?? "unknown";
|
|
548
|
+
}
|
|
549
|
+
catch {
|
|
550
|
+
return "unknown";
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
function generateExportMarkdown(tools, options) {
|
|
554
|
+
const lines = [];
|
|
555
|
+
const version = getPackageVersion();
|
|
556
|
+
const timestamp = new Date().toISOString().split("T")[0];
|
|
557
|
+
lines.push("# GitLab MCP Tools Reference");
|
|
558
|
+
lines.push("");
|
|
559
|
+
lines.push("> Auto-generated from source code. Do not edit manually.");
|
|
560
|
+
lines.push(`> Generated: ${timestamp} | Tools: ${tools.length} | Version: ${version}`);
|
|
561
|
+
lines.push("");
|
|
562
|
+
const grouped = groupToolsByEntity(tools);
|
|
563
|
+
if (options.toc) {
|
|
564
|
+
lines.push("## Table of Contents");
|
|
565
|
+
lines.push("");
|
|
566
|
+
for (const [entity, entityTools] of grouped) {
|
|
567
|
+
const anchor = entity.toLowerCase().replace(/\s+/g, "-");
|
|
568
|
+
lines.push(`- [${entity} (${entityTools.length})](#${anchor})`);
|
|
569
|
+
}
|
|
570
|
+
lines.push("");
|
|
571
|
+
lines.push("---");
|
|
572
|
+
lines.push("");
|
|
573
|
+
}
|
|
574
|
+
for (const [entity, entityTools] of grouped) {
|
|
575
|
+
lines.push(`## ${entity}`);
|
|
576
|
+
lines.push("");
|
|
577
|
+
for (const tool of entityTools) {
|
|
578
|
+
const tierInfo = getToolTierInfo(tool.name);
|
|
579
|
+
const tierDisplay = tierInfo ? ` ${tierInfo}` : "";
|
|
580
|
+
lines.push(`### ${tool.name}${tierDisplay}`);
|
|
581
|
+
lines.push("");
|
|
582
|
+
lines.push(tool.description);
|
|
583
|
+
lines.push("");
|
|
584
|
+
const actions = extractActions(tool.inputSchema);
|
|
585
|
+
if (actions.length > 0) {
|
|
586
|
+
lines.push("#### Actions");
|
|
587
|
+
lines.push("");
|
|
588
|
+
lines.push("| Action | Description |");
|
|
589
|
+
lines.push("|--------|-------------|");
|
|
590
|
+
for (const action of actions) {
|
|
591
|
+
lines.push(`| \`${action.name}\` | ${action.description} |`);
|
|
592
|
+
}
|
|
593
|
+
lines.push("");
|
|
594
|
+
}
|
|
595
|
+
const groupedParams = extractParametersGrouped(tool.inputSchema);
|
|
596
|
+
const hasParams = groupedParams.common.length > 0 || groupedParams.byAction.size > 0;
|
|
597
|
+
if (hasParams) {
|
|
598
|
+
lines.push("#### Parameters");
|
|
599
|
+
lines.push("");
|
|
600
|
+
if (groupedParams.common.length > 0) {
|
|
601
|
+
if (groupedParams.byAction.size > 0) {
|
|
602
|
+
lines.push("**Common** (all actions):");
|
|
603
|
+
lines.push("");
|
|
604
|
+
}
|
|
605
|
+
lines.push("| Parameter | Type | Required | Description |");
|
|
606
|
+
lines.push("|-----------|------|----------|-------------|");
|
|
607
|
+
for (const param of groupedParams.common) {
|
|
608
|
+
const req = param.required ? "Yes" : "No";
|
|
609
|
+
const desc = param.description || "-";
|
|
610
|
+
lines.push(`| \`${param.name}\` | ${param.type} | ${req} | ${desc} |`);
|
|
611
|
+
}
|
|
612
|
+
lines.push("");
|
|
613
|
+
}
|
|
614
|
+
if (groupedParams.byAction.size > 0) {
|
|
615
|
+
const sortedActions = Array.from(groupedParams.byAction.keys()).sort();
|
|
616
|
+
for (const actionName of sortedActions) {
|
|
617
|
+
const actionParams = groupedParams.byAction.get(actionName);
|
|
618
|
+
if (actionParams.length === 0)
|
|
619
|
+
continue;
|
|
620
|
+
lines.push(`**Action \`${actionName}\`**:`);
|
|
621
|
+
lines.push("");
|
|
622
|
+
lines.push("| Parameter | Type | Required | Description |");
|
|
623
|
+
lines.push("|-----------|------|----------|-------------|");
|
|
624
|
+
for (const param of actionParams) {
|
|
625
|
+
const req = param.requiredForAction ? "Yes" : "No";
|
|
626
|
+
const desc = param.description || "-";
|
|
627
|
+
lines.push(`| \`${param.name}\` | ${param.type} | ${req} | ${desc} |`);
|
|
628
|
+
}
|
|
629
|
+
lines.push("");
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
if (!options.noExamples && tool.inputSchema) {
|
|
634
|
+
const example = generateExample(tool.inputSchema);
|
|
635
|
+
if (Object.keys(example).length > 0) {
|
|
636
|
+
lines.push("#### Example");
|
|
637
|
+
lines.push("");
|
|
638
|
+
lines.push("```json");
|
|
639
|
+
lines.push(JSON.stringify(example, null, 2));
|
|
640
|
+
lines.push("```");
|
|
641
|
+
lines.push("");
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
lines.push("---");
|
|
645
|
+
lines.push("");
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
return lines.join("\n");
|
|
649
|
+
}
|
|
650
|
+
async function main() {
|
|
651
|
+
const options = parseArgs();
|
|
652
|
+
if (options.showEnv) {
|
|
653
|
+
printEnvironmentInfo();
|
|
654
|
+
}
|
|
655
|
+
const registryManager = registry_manager_1.RegistryManager.getInstance();
|
|
656
|
+
const toolDefinitions = options.format === "export"
|
|
657
|
+
? registryManager.getAllToolDefinitionsUnfiltered()
|
|
658
|
+
: registryManager.getAllToolDefinitionsTierless();
|
|
659
|
+
const tools = toolDefinitions.map(def => ({
|
|
660
|
+
name: def.name,
|
|
661
|
+
description: def.description,
|
|
662
|
+
inputSchema: def.inputSchema,
|
|
663
|
+
}));
|
|
664
|
+
let filteredTools = tools;
|
|
665
|
+
if (options.entity) {
|
|
666
|
+
const grouped = groupToolsByEntity(tools);
|
|
667
|
+
const entityKey = Array.from(grouped.keys()).find(k => k.toLowerCase().replace(/ /g, "") === options.entity.toLowerCase().replace(/ /g, ""));
|
|
668
|
+
filteredTools = entityKey ? (grouped.get(entityKey) ?? []) : [];
|
|
669
|
+
if (filteredTools.length === 0) {
|
|
670
|
+
console.error(`No tools found for entity: ${options.entity}`);
|
|
671
|
+
process.exit(1);
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
if (options.tool) {
|
|
675
|
+
filteredTools = filteredTools.filter(t => t.name === options.tool);
|
|
676
|
+
if (filteredTools.length === 0) {
|
|
677
|
+
console.error(`Tool not found: ${options.tool}`);
|
|
678
|
+
process.exit(1);
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
switch (options.format) {
|
|
682
|
+
case "json":
|
|
683
|
+
const output = filteredTools.map(tool => ({
|
|
684
|
+
name: tool.name,
|
|
685
|
+
description: tool.description,
|
|
686
|
+
tier: ToolAvailability_1.ToolAvailability.getToolRequirement(tool.name)?.requiredTier ?? "unknown",
|
|
687
|
+
minVersion: ToolAvailability_1.ToolAvailability.getToolRequirement(tool.name)?.minVersion,
|
|
688
|
+
parameters: tool.inputSchema,
|
|
689
|
+
}));
|
|
690
|
+
console.log(JSON.stringify(output, null, 2));
|
|
691
|
+
break;
|
|
692
|
+
case "simple":
|
|
693
|
+
filteredTools.forEach(tool => {
|
|
694
|
+
console.log(tool.name);
|
|
695
|
+
});
|
|
696
|
+
break;
|
|
697
|
+
case "export":
|
|
698
|
+
const markdown = generateExportMarkdown(filteredTools, {
|
|
699
|
+
noExamples: options.noExamples,
|
|
700
|
+
toc: options.toc,
|
|
701
|
+
});
|
|
702
|
+
console.log(markdown);
|
|
703
|
+
break;
|
|
704
|
+
case "markdown":
|
|
705
|
+
default:
|
|
706
|
+
if (!options.entity && !options.tool) {
|
|
707
|
+
console.log("# GitLab MCP Tools\n");
|
|
708
|
+
console.log(`Total tools available: ${filteredTools.length}\n`);
|
|
709
|
+
const grouped = groupToolsByEntity(filteredTools);
|
|
710
|
+
console.log("## Categories\n");
|
|
711
|
+
for (const [entity, entityTools] of grouped) {
|
|
712
|
+
console.log(`- **${entity}**: ${entityTools.length} tools`);
|
|
713
|
+
}
|
|
714
|
+
console.log();
|
|
715
|
+
for (const [entity, entityTools] of grouped) {
|
|
716
|
+
console.log(`## ${entity}\n`);
|
|
717
|
+
for (const tool of entityTools) {
|
|
718
|
+
const tierInfo = getToolTierInfo(tool.name);
|
|
719
|
+
const tierDisplay = tierInfo ? ` ${tierInfo}` : "";
|
|
720
|
+
console.log(`### ${tool.name}${tierDisplay}`);
|
|
721
|
+
console.log(`**Description**: ${tool.description}\n`);
|
|
722
|
+
if ((options.verbose || options.detail) && tool.inputSchema) {
|
|
723
|
+
console.log("**Parameters**:");
|
|
724
|
+
const params = getParameterDescription(tool.inputSchema);
|
|
725
|
+
if (params.length > 0) {
|
|
726
|
+
params.forEach(p => console.log(p));
|
|
727
|
+
}
|
|
728
|
+
else {
|
|
729
|
+
console.log(" (no parameters)");
|
|
730
|
+
}
|
|
731
|
+
console.log();
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
else {
|
|
737
|
+
for (const tool of filteredTools) {
|
|
738
|
+
const tierInfo = getToolTierInfo(tool.name);
|
|
739
|
+
const tierDisplay = tierInfo ? ` ${tierInfo}` : "";
|
|
740
|
+
console.log(`## ${tool.name}${tierDisplay}\n`);
|
|
741
|
+
console.log(`**Description**: ${tool.description}\n`);
|
|
742
|
+
if (tool.inputSchema) {
|
|
743
|
+
console.log("**Parameters**:\n");
|
|
744
|
+
const params = getParameterDescription(tool.inputSchema);
|
|
745
|
+
if (params.length > 0) {
|
|
746
|
+
params.forEach(p => console.log(p));
|
|
747
|
+
}
|
|
748
|
+
else {
|
|
749
|
+
console.log("(no parameters)");
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
console.log();
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
break;
|
|
756
|
+
}
|
|
757
|
+
if (options.showEnv && options.format === "markdown") {
|
|
758
|
+
console.log("\n---\n");
|
|
759
|
+
console.log("*Note: Tool availability may be affected by environment variables shown above.*");
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
if (!process.env.NODE_ENV || process.env.NODE_ENV !== "test") {
|
|
763
|
+
main().catch(error => {
|
|
764
|
+
console.error("Error:", error);
|
|
765
|
+
process.exit(1);
|
|
766
|
+
});
|
|
767
|
+
}
|
|
768
|
+
//# sourceMappingURL=list-tools.js.map
|