@structured-world/gitlab-mcp 6.1.0 → 6.2.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 +14 -13
- package/dist/src/entities/workitems/registry.js +240 -252
- package/dist/src/entities/workitems/registry.js.map +1 -1
- package/dist/src/entities/workitems/schema-readonly.d.ts +25 -1
- package/dist/src/entities/workitems/schema-readonly.js +33 -6
- package/dist/src/entities/workitems/schema-readonly.js.map +1 -1
- package/dist/src/entities/workitems/schema.d.ts +35 -0
- package/dist/src/entities/workitems/schema.js +32 -1
- package/dist/src/entities/workitems/schema.js.map +1 -1
- package/dist/structured-world-gitlab-mcp-6.2.0.tgz +0 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/dist/structured-world-gitlab-mcp-6.1.0.tgz +0 -0
package/README.md
CHANGED
|
@@ -464,6 +464,7 @@ When OAuth is enabled, the following endpoints are available:
|
|
|
464
464
|
- `USE_MRS`: When set to 'true', enables the merge request-related tools (browse_merge_requests, browse_mr_discussions, manage_merge_request, manage_mr_discussion, manage_draft_notes). These 5 CQRS tools consolidate all MR operations. By default, merge request features are enabled.
|
|
465
465
|
- `USE_FILES`: When set to 'true', enables the file-related tools (browse_files, manage_files). These 2 CQRS tools consolidate all file operations. By default, file operation features are enabled.
|
|
466
466
|
- `USE_VARIABLES`: When set to 'true', enables the CI/CD variables-related tools (list_variables, get_variable, create_variable, update_variable, delete_variable). Supports both project-level and group-level variables. By default, variables features are enabled.
|
|
467
|
+
- `USE_WORKITEMS`: When set to 'true', enables the work items-related tools (browse_work_items, manage_work_item). These 2 CQRS tools consolidate all work item operations using GitLab GraphQL API. By default, work items features are enabled.
|
|
467
468
|
- `GITLAB_AUTH_COOKIE_PATH`: Path to an authentication cookie file for GitLab instances that require cookie-based authentication. When provided, the cookie will be included in all GitLab API requests.
|
|
468
469
|
- `SKIP_TLS_VERIFY`: When set to 'true', skips TLS certificate verification for all GitLab API requests (both REST and GraphQL). **WARNING**: This bypasses SSL certificate validation and should only be used for testing with self-signed certificates or trusted internal GitLab instances. Never use this in production environments.
|
|
469
470
|
- `SSL_CERT_PATH`: Path to PEM certificate file for direct HTTPS/TLS termination. Requires `SSL_KEY_PATH` to also be set.
|
|
@@ -502,7 +503,7 @@ export GITLAB_TOOL_GET_FILE_CONTENTS="Read source code files from the repository
|
|
|
502
503
|
# Multiple customizations
|
|
503
504
|
export GITLAB_TOOL_LIST_PROJECTS="List user projects"
|
|
504
505
|
export GITLAB_TOOL_GET_PROJECT="Get project details including settings"
|
|
505
|
-
export
|
|
506
|
+
export GITLAB_TOOL_MANAGE_WORK_ITEM="Create and manage tickets for our sprint planning"
|
|
506
507
|
```
|
|
507
508
|
|
|
508
509
|
#### Usage in Configuration Files
|
|
@@ -532,11 +533,11 @@ export GITLAB_TOOL_CREATE_WORK_ITEM="Create tickets for our sprint planning"
|
|
|
532
533
|
- **Case Sensitivity**: Tool names in environment variables must be UPPERCASE (e.g., `LIST_PROJECTS` not `list_projects`)
|
|
533
534
|
- **Invalid Names**: Invalid tool names in environment variables are ignored with a warning in debug logs
|
|
534
535
|
- **Content Guidelines**: Descriptions can be any valid string but should be kept concise for better UX
|
|
535
|
-
- **Scope**: Works with all
|
|
536
|
+
- **Scope**: Works with all 58 available tools across all entities (Core, Work Items, Merge Requests, Files, etc.)
|
|
536
537
|
|
|
537
538
|
## Tools 🛠️
|
|
538
539
|
|
|
539
|
-
**
|
|
540
|
+
**58 Tools Available** - Organized by entity and functionality below.
|
|
540
541
|
|
|
541
542
|
### Key Features:
|
|
542
543
|
- **CQRS Pattern** - Consolidated action-based tools: `browse_*` for reads, `manage_*` for writes
|
|
@@ -617,14 +618,14 @@ Requires USE_VARIABLES=true environment variable (enabled by default). Supports
|
|
|
617
618
|
- ✏️ **`update_variable`**: Update an existing CI/CD variable's value, security settings, or configuration in a project or group
|
|
618
619
|
- ✏️ **`delete_variable`**: Remove a CI/CD variable from a project or group
|
|
619
620
|
|
|
620
|
-
### Work Items (
|
|
621
|
-
Modern GraphQL API for issues, epics, tasks, and more. Requires USE_WORKITEMS=true (enabled by default).
|
|
621
|
+
### Work Items (2 CQRS tools)
|
|
622
|
+
Modern GraphQL API for issues, epics, tasks, and more. Requires USE_WORKITEMS=true (enabled by default). Uses CQRS pattern with action-based tools.
|
|
622
623
|
|
|
623
|
-
|
|
624
|
-
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
-
|
|
624
|
+
#### Work Item Browsing (Query)
|
|
625
|
+
- 📖 **`browse_work_items`**: BROWSE work items. Actions: "list" shows work items with filtering (groups return epics, projects return issues/tasks), "get" retrieves single work item by ID with full widget details.
|
|
626
|
+
|
|
627
|
+
#### Work Item Management (Command)
|
|
628
|
+
- ✏️ **`manage_work_item`**: MANAGE work items. Actions: "create" creates new work item (Epics need GROUP namespace, Issues/Tasks need PROJECT), "update" modifies properties/widgets, "delete" permanently removes.
|
|
628
629
|
|
|
629
630
|
### Wiki Management (5 tools)
|
|
630
631
|
Requires USE_GITLAB_WIKI=true environment variable. Supports both project-level and group-level wikis.
|
|
@@ -775,9 +776,9 @@ For rapid testing of individual MCP tools:
|
|
|
775
776
|
|
|
776
777
|
```bash
|
|
777
778
|
# Test specific tools directly
|
|
778
|
-
./scripts/test_mcp.sh '{"name": "
|
|
779
|
-
./scripts/test_mcp.sh '{"name": "
|
|
780
|
-
./scripts/test_mcp.sh '{"name": "
|
|
779
|
+
./scripts/test_mcp.sh '{"name": "browse_work_items", "arguments": {"action": "list", "namespace": "test"}}'
|
|
780
|
+
./scripts/test_mcp.sh '{"name": "browse_work_items", "arguments": {"action": "get", "id": "gid://gitlab/WorkItem/123"}}'
|
|
781
|
+
./scripts/test_mcp.sh '{"name": "manage_work_item", "arguments": {"action": "create", "namespace": "test", "workItemType": "EPIC", "title": "Test Epic"}}'
|
|
781
782
|
```
|
|
782
783
|
|
|
783
784
|
The `test_mcp.sh` script automatically:
|
|
@@ -44,278 +44,266 @@ const ConnectionManager_1 = require("../../services/ConnectionManager");
|
|
|
44
44
|
const workItemTypes_1 = require("../../utils/workItemTypes");
|
|
45
45
|
const idConversion_1 = require("../../utils/idConversion");
|
|
46
46
|
const workItems_1 = require("../../graphql/workItems");
|
|
47
|
+
const simplifyWorkItem = (workItem, simple) => {
|
|
48
|
+
if (!simple)
|
|
49
|
+
return workItem;
|
|
50
|
+
const simplified = {
|
|
51
|
+
id: workItem.id,
|
|
52
|
+
iid: workItem.iid,
|
|
53
|
+
title: workItem.title,
|
|
54
|
+
state: workItem.state,
|
|
55
|
+
workItemType: typeof workItem.workItemType === "string"
|
|
56
|
+
? workItem.workItemType
|
|
57
|
+
: workItem.workItemType?.name || "Unknown",
|
|
58
|
+
webUrl: workItem.webUrl,
|
|
59
|
+
createdAt: workItem.createdAt,
|
|
60
|
+
updatedAt: workItem.updatedAt,
|
|
61
|
+
};
|
|
62
|
+
if (workItem.description && typeof workItem.description === "string") {
|
|
63
|
+
simplified.description =
|
|
64
|
+
workItem.description.length > 200
|
|
65
|
+
? workItem.description.substring(0, 200) + "..."
|
|
66
|
+
: workItem.description;
|
|
67
|
+
}
|
|
68
|
+
if (workItem.widgets && Array.isArray(workItem.widgets)) {
|
|
69
|
+
const essentialWidgets = [];
|
|
70
|
+
for (const widget of workItem.widgets) {
|
|
71
|
+
const flexWidget = widget;
|
|
72
|
+
switch (flexWidget.type) {
|
|
73
|
+
case "ASSIGNEES":
|
|
74
|
+
if (flexWidget.assignees?.nodes && flexWidget.assignees.nodes.length > 0) {
|
|
75
|
+
essentialWidgets.push({
|
|
76
|
+
type: "ASSIGNEES",
|
|
77
|
+
assignees: flexWidget.assignees.nodes.map(assignee => ({
|
|
78
|
+
id: assignee.id,
|
|
79
|
+
username: assignee.username,
|
|
80
|
+
name: assignee.name,
|
|
81
|
+
})),
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
break;
|
|
85
|
+
case "LABELS":
|
|
86
|
+
if (flexWidget.labels?.nodes && flexWidget.labels.nodes.length > 0) {
|
|
87
|
+
essentialWidgets.push({
|
|
88
|
+
type: "LABELS",
|
|
89
|
+
labels: flexWidget.labels.nodes.map(label => ({
|
|
90
|
+
id: label.id,
|
|
91
|
+
title: label.title,
|
|
92
|
+
color: label.color,
|
|
93
|
+
})),
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
break;
|
|
97
|
+
case "MILESTONE":
|
|
98
|
+
if (flexWidget.milestone) {
|
|
99
|
+
essentialWidgets.push({
|
|
100
|
+
type: "MILESTONE",
|
|
101
|
+
milestone: {
|
|
102
|
+
id: flexWidget.milestone.id,
|
|
103
|
+
title: flexWidget.milestone.title,
|
|
104
|
+
state: flexWidget.milestone.state,
|
|
105
|
+
},
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
break;
|
|
109
|
+
case "HIERARCHY":
|
|
110
|
+
if (flexWidget.parent || flexWidget.hasChildren) {
|
|
111
|
+
essentialWidgets.push({
|
|
112
|
+
type: "HIERARCHY",
|
|
113
|
+
parent: flexWidget.parent
|
|
114
|
+
? {
|
|
115
|
+
id: flexWidget.parent.id,
|
|
116
|
+
iid: flexWidget.parent.iid,
|
|
117
|
+
title: flexWidget.parent.title,
|
|
118
|
+
workItemType: flexWidget.parent.workItemType,
|
|
119
|
+
}
|
|
120
|
+
: null,
|
|
121
|
+
hasChildren: flexWidget.hasChildren,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
break;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
if (essentialWidgets && essentialWidgets.length > 0) {
|
|
128
|
+
simplified.widgets = essentialWidgets;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return simplified;
|
|
132
|
+
};
|
|
47
133
|
exports.workitemsToolRegistry = new Map([
|
|
48
134
|
[
|
|
49
|
-
"
|
|
135
|
+
"browse_work_items",
|
|
50
136
|
{
|
|
51
|
-
name: "
|
|
52
|
-
description:
|
|
53
|
-
inputSchema: z.toJSONSchema(schema_readonly_1.
|
|
137
|
+
name: "browse_work_items",
|
|
138
|
+
description: 'BROWSE work items. Actions: "list" shows work items with filtering (groups return epics, projects return issues/tasks), "get" retrieves single work item by ID with full widget details.',
|
|
139
|
+
inputSchema: z.toJSONSchema(schema_readonly_1.BrowseWorkItemsSchema),
|
|
54
140
|
handler: async (args) => {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
141
|
+
const input = schema_readonly_1.BrowseWorkItemsSchema.parse(args);
|
|
142
|
+
switch (input.action) {
|
|
143
|
+
case "list": {
|
|
144
|
+
const { namespace, types, state, first, after, simple } = input;
|
|
145
|
+
console.log("browse_work_items list called with:", {
|
|
146
|
+
namespace,
|
|
147
|
+
types,
|
|
148
|
+
state,
|
|
149
|
+
first,
|
|
150
|
+
after,
|
|
151
|
+
simple,
|
|
152
|
+
});
|
|
153
|
+
const connectionManager = ConnectionManager_1.ConnectionManager.getInstance();
|
|
154
|
+
const client = connectionManager.getClient();
|
|
155
|
+
const resolvedTypes = types;
|
|
156
|
+
const workItemsResponse = await client.request(workItems_1.GET_NAMESPACE_WORK_ITEMS, {
|
|
157
|
+
namespacePath: namespace,
|
|
158
|
+
types: resolvedTypes,
|
|
159
|
+
first: first || 20,
|
|
160
|
+
after: after,
|
|
161
|
+
});
|
|
162
|
+
const workItemsData = workItemsResponse.namespace?.workItems;
|
|
163
|
+
const allItems = workItemsData?.nodes ?? [];
|
|
164
|
+
const pageInfo = {
|
|
165
|
+
hasNextPage: workItemsData?.pageInfo?.hasNextPage ?? false,
|
|
166
|
+
endCursor: workItemsData?.pageInfo?.endCursor ?? null,
|
|
167
|
+
};
|
|
168
|
+
const namespaceType = workItemsResponse.namespace?.__typename ?? "Unknown";
|
|
169
|
+
console.log(`Found ${allItems.length} work items from ${namespaceType} query`);
|
|
170
|
+
const filteredItems = allItems.filter((item) => {
|
|
171
|
+
return state.includes(item.state);
|
|
172
|
+
});
|
|
173
|
+
console.log(`State filtering: ${allItems.length} -> ${filteredItems.length} items (keeping: ${state.join(", ")})`);
|
|
174
|
+
const finalResults = filteredItems.map((item) => {
|
|
175
|
+
const cleanedItem = (0, idConversion_1.cleanWorkItemResponse)(item);
|
|
176
|
+
return simplifyWorkItem(cleanedItem, simple);
|
|
177
|
+
});
|
|
178
|
+
console.log("Final result - total work items found:", finalResults.length);
|
|
179
|
+
return {
|
|
180
|
+
items: finalResults,
|
|
181
|
+
hasMore: pageInfo.hasNextPage ?? false,
|
|
182
|
+
endCursor: pageInfo.endCursor ?? null,
|
|
183
|
+
};
|
|
87
184
|
}
|
|
88
|
-
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
type: "ASSIGNEES",
|
|
97
|
-
assignees: flexWidget.assignees.nodes.map(assignee => ({
|
|
98
|
-
id: assignee.id,
|
|
99
|
-
username: assignee.username,
|
|
100
|
-
name: assignee.name,
|
|
101
|
-
})),
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
break;
|
|
105
|
-
case "LABELS":
|
|
106
|
-
if (flexWidget.labels?.nodes && flexWidget.labels.nodes.length > 0) {
|
|
107
|
-
essentialWidgets.push({
|
|
108
|
-
type: "LABELS",
|
|
109
|
-
labels: flexWidget.labels.nodes.map(label => ({
|
|
110
|
-
id: label.id,
|
|
111
|
-
title: label.title,
|
|
112
|
-
color: label.color,
|
|
113
|
-
})),
|
|
114
|
-
});
|
|
115
|
-
}
|
|
116
|
-
break;
|
|
117
|
-
case "MILESTONE":
|
|
118
|
-
if (flexWidget.milestone) {
|
|
119
|
-
essentialWidgets.push({
|
|
120
|
-
type: "MILESTONE",
|
|
121
|
-
milestone: {
|
|
122
|
-
id: flexWidget.milestone.id,
|
|
123
|
-
title: flexWidget.milestone.title,
|
|
124
|
-
state: flexWidget.milestone.state,
|
|
125
|
-
},
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
|
-
break;
|
|
129
|
-
case "HIERARCHY":
|
|
130
|
-
if (flexWidget.parent || flexWidget.hasChildren) {
|
|
131
|
-
essentialWidgets.push({
|
|
132
|
-
type: "HIERARCHY",
|
|
133
|
-
parent: flexWidget.parent
|
|
134
|
-
? {
|
|
135
|
-
id: flexWidget.parent.id,
|
|
136
|
-
iid: flexWidget.parent.iid,
|
|
137
|
-
title: flexWidget.parent.title,
|
|
138
|
-
workItemType: flexWidget.parent.workItemType,
|
|
139
|
-
}
|
|
140
|
-
: null,
|
|
141
|
-
hasChildren: flexWidget.hasChildren,
|
|
142
|
-
});
|
|
143
|
-
}
|
|
144
|
-
break;
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
if (essentialWidgets && essentialWidgets.length > 0) {
|
|
148
|
-
simplified.widgets = essentialWidgets;
|
|
185
|
+
case "get": {
|
|
186
|
+
const { id } = input;
|
|
187
|
+
const connectionManager = ConnectionManager_1.ConnectionManager.getInstance();
|
|
188
|
+
const client = connectionManager.getClient();
|
|
189
|
+
const workItemGid = (0, idConversion_1.toGid)(id, "WorkItem");
|
|
190
|
+
const response = await client.request(workItems_1.GET_WORK_ITEM, { id: workItemGid });
|
|
191
|
+
if (!response.workItem) {
|
|
192
|
+
throw new Error(`Work item with ID "${id}" not found`);
|
|
149
193
|
}
|
|
194
|
+
return (0, idConversion_1.cleanWorkItemResponse)(response.workItem);
|
|
195
|
+
}
|
|
196
|
+
default: {
|
|
197
|
+
const _exhaustive = input;
|
|
198
|
+
throw new Error(`Unknown action: ${_exhaustive.action}`);
|
|
150
199
|
}
|
|
151
|
-
return simplified;
|
|
152
|
-
};
|
|
153
|
-
const connectionManager = ConnectionManager_1.ConnectionManager.getInstance();
|
|
154
|
-
const client = connectionManager.getClient();
|
|
155
|
-
console.log("Querying namespace:", namespace);
|
|
156
|
-
let resolvedTypes = types;
|
|
157
|
-
const workItemsResponse = await client.request(workItems_1.GET_NAMESPACE_WORK_ITEMS, {
|
|
158
|
-
namespacePath: namespace,
|
|
159
|
-
types: resolvedTypes,
|
|
160
|
-
first: first || 20,
|
|
161
|
-
after: after,
|
|
162
|
-
});
|
|
163
|
-
const workItemsData = workItemsResponse.namespace?.workItems;
|
|
164
|
-
const allItems = workItemsData?.nodes ?? [];
|
|
165
|
-
const pageInfo = {
|
|
166
|
-
hasNextPage: workItemsData?.pageInfo?.hasNextPage ?? false,
|
|
167
|
-
endCursor: workItemsData?.pageInfo?.endCursor ?? null,
|
|
168
|
-
};
|
|
169
|
-
const namespaceType = workItemsResponse.namespace?.__typename ?? "Unknown";
|
|
170
|
-
console.log(`Found ${allItems.length} work items from ${namespaceType} query`);
|
|
171
|
-
const filteredItems = allItems.filter((item) => {
|
|
172
|
-
return state.includes(item.state);
|
|
173
|
-
});
|
|
174
|
-
console.log(`State filtering: ${allItems.length} → ${filteredItems.length} items (keeping: ${state.join(", ")})`);
|
|
175
|
-
const finalResults = filteredItems.map((item) => {
|
|
176
|
-
const cleanedItem = (0, idConversion_1.cleanWorkItemResponse)(item);
|
|
177
|
-
return simplifyWorkItem(cleanedItem);
|
|
178
|
-
});
|
|
179
|
-
console.log("Final result - total work items found:", finalResults.length);
|
|
180
|
-
if (simple) {
|
|
181
|
-
console.log("Using simplified structure for agent consumption");
|
|
182
|
-
}
|
|
183
|
-
return {
|
|
184
|
-
items: finalResults,
|
|
185
|
-
hasMore: pageInfo.hasNextPage ?? false,
|
|
186
|
-
endCursor: pageInfo.endCursor ?? null,
|
|
187
|
-
};
|
|
188
|
-
},
|
|
189
|
-
},
|
|
190
|
-
],
|
|
191
|
-
[
|
|
192
|
-
"get_work_item",
|
|
193
|
-
{
|
|
194
|
-
name: "get_work_item",
|
|
195
|
-
description: "Get complete work item details by ID. Returns full data including widgets (assignees, labels, milestones, hierarchy, time tracking, custom fields). Essential for issue/epic management and tracking project progress. Each work item type has different widget capabilities.",
|
|
196
|
-
inputSchema: z.toJSONSchema(schema_readonly_1.GetWorkItemSchema),
|
|
197
|
-
handler: async (args) => {
|
|
198
|
-
const options = schema_readonly_1.GetWorkItemSchema.parse(args);
|
|
199
|
-
const { id } = options;
|
|
200
|
-
const connectionManager = ConnectionManager_1.ConnectionManager.getInstance();
|
|
201
|
-
const client = connectionManager.getClient();
|
|
202
|
-
const workItemGid = (0, idConversion_1.toGid)(id, "WorkItem");
|
|
203
|
-
const response = await client.request(workItems_1.GET_WORK_ITEM, { id: workItemGid });
|
|
204
|
-
if (!response.workItem) {
|
|
205
|
-
throw new Error(`Work item with ID "${id}" not found`);
|
|
206
|
-
}
|
|
207
|
-
return (0, idConversion_1.cleanWorkItemResponse)(response.workItem);
|
|
208
|
-
},
|
|
209
|
-
},
|
|
210
|
-
],
|
|
211
|
-
[
|
|
212
|
-
"create_work_item",
|
|
213
|
-
{
|
|
214
|
-
name: "create_work_item",
|
|
215
|
-
description: "Create work items for issue tracking and project management. LABEL WORKFLOW: Run list_labels first to discover existing labels, then use label IDs from response. CRITICAL: Epics require GROUP namespace, Issues/Tasks/Incidents require PROJECT namespace. Supports 9 types: Epic, Issue, Task, Incident, Test Case, Requirement, Objective, Key Result, Ticket. NOTE: Test Cases and Requirements do not support labels widget. Automatically assigns widgets (assignees, labels, milestones) based on type capabilities.",
|
|
216
|
-
inputSchema: z.toJSONSchema(schema_1.CreateWorkItemSchema),
|
|
217
|
-
handler: async (args) => {
|
|
218
|
-
const options = schema_1.CreateWorkItemSchema.parse(args);
|
|
219
|
-
const { namespace, title, workItemType, description, assigneeIds, labelIds, milestoneId } = options;
|
|
220
|
-
const connectionManager = ConnectionManager_1.ConnectionManager.getInstance();
|
|
221
|
-
const client = connectionManager.getClient();
|
|
222
|
-
const workItemTypes = await (0, workItemTypes_1.getWorkItemTypes)(namespace);
|
|
223
|
-
const workItemTypeObj = workItemTypes.find((t) => t.name.toUpperCase().replace(/\s+/g, "_") ===
|
|
224
|
-
workItemType.toUpperCase().replace(/\s+/g, "_"));
|
|
225
|
-
if (!workItemTypeObj) {
|
|
226
|
-
throw new Error(`Work item type "${workItemType}" not found in namespace "${namespace}". Available types: ${workItemTypes.map(t => t.name).join(", ")}`);
|
|
227
|
-
}
|
|
228
|
-
const input = {
|
|
229
|
-
namespacePath: namespace,
|
|
230
|
-
title,
|
|
231
|
-
workItemTypeId: workItemTypeObj.id,
|
|
232
|
-
};
|
|
233
|
-
if (description !== undefined) {
|
|
234
|
-
input.description = description;
|
|
235
|
-
}
|
|
236
|
-
if (assigneeIds !== undefined && assigneeIds.length > 0) {
|
|
237
|
-
input.assigneesWidget = { assigneeIds: (0, idConversion_1.toGids)(assigneeIds, "User") };
|
|
238
|
-
}
|
|
239
|
-
if (labelIds !== undefined && labelIds.length > 0) {
|
|
240
|
-
input.labelsWidget = { labelIds: (0, idConversion_1.toGids)(labelIds, "Label") };
|
|
241
|
-
}
|
|
242
|
-
if (milestoneId !== undefined) {
|
|
243
|
-
input.milestoneWidget = { milestoneId: (0, idConversion_1.toGid)(milestoneId, "Milestone") };
|
|
244
|
-
}
|
|
245
|
-
const response = await client.request(workItems_1.CREATE_WORK_ITEM_WITH_WIDGETS, { input });
|
|
246
|
-
if (response.workItemCreate?.errors?.length && response.workItemCreate.errors.length > 0) {
|
|
247
|
-
throw new Error(`GitLab GraphQL errors: ${response.workItemCreate.errors.join(", ")}`);
|
|
248
|
-
}
|
|
249
|
-
if (!response.workItemCreate?.workItem) {
|
|
250
|
-
throw new Error("Work item creation failed - no work item returned");
|
|
251
|
-
}
|
|
252
|
-
return (0, idConversion_1.cleanWorkItemResponse)(response.workItemCreate.workItem);
|
|
253
|
-
},
|
|
254
|
-
},
|
|
255
|
-
],
|
|
256
|
-
[
|
|
257
|
-
"update_work_item",
|
|
258
|
-
{
|
|
259
|
-
name: "update_work_item",
|
|
260
|
-
description: "Update work item properties for issue/epic management. LABEL WORKFLOW: Run list_labels first to discover existing labels, then use label IDs from response. Modify title, description, assignees, labels, milestones, and state (open/close). Supports widget updates including clearing assignees with empty arrays. NOTE: Test Cases and Requirements do not support labels widget. Essential for project workflow and status tracking.",
|
|
261
|
-
inputSchema: z.toJSONSchema(schema_1.UpdateWorkItemSchema),
|
|
262
|
-
handler: async (args) => {
|
|
263
|
-
const options = schema_1.UpdateWorkItemSchema.parse(args);
|
|
264
|
-
const { id, title, description, state, assigneeIds, labelIds, milestoneId } = options;
|
|
265
|
-
const connectionManager = ConnectionManager_1.ConnectionManager.getInstance();
|
|
266
|
-
const client = connectionManager.getClient();
|
|
267
|
-
const workItemGid = (0, idConversion_1.toGid)(id, "WorkItem");
|
|
268
|
-
const input = { id: workItemGid };
|
|
269
|
-
if (title !== undefined)
|
|
270
|
-
input.title = title;
|
|
271
|
-
if (state !== undefined)
|
|
272
|
-
input.stateEvent = state;
|
|
273
|
-
if (description !== undefined) {
|
|
274
|
-
input.descriptionWidget = { description };
|
|
275
|
-
}
|
|
276
|
-
if (assigneeIds !== undefined) {
|
|
277
|
-
input.assigneesWidget = { assigneeIds: (0, idConversion_1.toGids)(assigneeIds, "User") };
|
|
278
|
-
}
|
|
279
|
-
if (labelIds !== undefined) {
|
|
280
|
-
input.labelsWidget = { addLabelIds: (0, idConversion_1.toGids)(labelIds, "Label") };
|
|
281
|
-
}
|
|
282
|
-
if (milestoneId !== undefined) {
|
|
283
|
-
input.milestoneWidget = { milestoneId: (0, idConversion_1.toGid)(milestoneId, "Milestone") };
|
|
284
|
-
}
|
|
285
|
-
const response = await client.request(workItems_1.UPDATE_WORK_ITEM, { input });
|
|
286
|
-
if (response.workItemUpdate?.errors?.length && response.workItemUpdate.errors.length > 0) {
|
|
287
|
-
throw new Error(`GitLab GraphQL errors: ${response.workItemUpdate.errors.join(", ")}`);
|
|
288
|
-
}
|
|
289
|
-
if (!response.workItemUpdate?.workItem) {
|
|
290
|
-
throw new Error("Work item update failed - no work item returned");
|
|
291
200
|
}
|
|
292
|
-
return (0, idConversion_1.cleanWorkItemResponse)(response.workItemUpdate.workItem);
|
|
293
201
|
},
|
|
294
202
|
},
|
|
295
203
|
],
|
|
296
204
|
[
|
|
297
|
-
"
|
|
205
|
+
"manage_work_item",
|
|
298
206
|
{
|
|
299
|
-
name: "
|
|
300
|
-
description:
|
|
301
|
-
inputSchema: z.toJSONSchema(schema_1.
|
|
207
|
+
name: "manage_work_item",
|
|
208
|
+
description: 'MANAGE work items. Actions: "create" creates new work item (Epics need GROUP namespace, Issues/Tasks need PROJECT), "update" modifies properties/widgets, "delete" permanently removes.',
|
|
209
|
+
inputSchema: z.toJSONSchema(schema_1.ManageWorkItemSchema),
|
|
302
210
|
handler: async (args) => {
|
|
303
|
-
const
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
211
|
+
const input = schema_1.ManageWorkItemSchema.parse(args);
|
|
212
|
+
switch (input.action) {
|
|
213
|
+
case "create": {
|
|
214
|
+
const { namespace, title, workItemType, description, assigneeIds, labelIds, milestoneId, } = input;
|
|
215
|
+
const connectionManager = ConnectionManager_1.ConnectionManager.getInstance();
|
|
216
|
+
const client = connectionManager.getClient();
|
|
217
|
+
const workItemTypes = await (0, workItemTypes_1.getWorkItemTypes)(namespace);
|
|
218
|
+
const workItemTypeObj = workItemTypes.find((t) => t.name.toUpperCase().replace(/\s+/g, "_") ===
|
|
219
|
+
workItemType.toUpperCase().replace(/\s+/g, "_"));
|
|
220
|
+
if (!workItemTypeObj) {
|
|
221
|
+
throw new Error(`Work item type "${workItemType}" not found in namespace "${namespace}". Available types: ${workItemTypes.map(t => t.name).join(", ")}`);
|
|
222
|
+
}
|
|
223
|
+
const createInput = {
|
|
224
|
+
namespacePath: namespace,
|
|
225
|
+
title,
|
|
226
|
+
workItemTypeId: workItemTypeObj.id,
|
|
227
|
+
};
|
|
228
|
+
if (description !== undefined) {
|
|
229
|
+
createInput.description = description;
|
|
230
|
+
}
|
|
231
|
+
if (assigneeIds !== undefined && assigneeIds.length > 0) {
|
|
232
|
+
createInput.assigneesWidget = { assigneeIds: (0, idConversion_1.toGids)(assigneeIds, "User") };
|
|
233
|
+
}
|
|
234
|
+
if (labelIds !== undefined && labelIds.length > 0) {
|
|
235
|
+
createInput.labelsWidget = { labelIds: (0, idConversion_1.toGids)(labelIds, "Label") };
|
|
236
|
+
}
|
|
237
|
+
if (milestoneId !== undefined) {
|
|
238
|
+
createInput.milestoneWidget = { milestoneId: (0, idConversion_1.toGid)(milestoneId, "Milestone") };
|
|
239
|
+
}
|
|
240
|
+
const response = await client.request(workItems_1.CREATE_WORK_ITEM_WITH_WIDGETS, {
|
|
241
|
+
input: createInput,
|
|
242
|
+
});
|
|
243
|
+
if (response.workItemCreate?.errors?.length &&
|
|
244
|
+
response.workItemCreate.errors.length > 0) {
|
|
245
|
+
throw new Error(`GitLab GraphQL errors: ${response.workItemCreate.errors.join(", ")}`);
|
|
246
|
+
}
|
|
247
|
+
if (!response.workItemCreate?.workItem) {
|
|
248
|
+
throw new Error("Work item creation failed - no work item returned");
|
|
249
|
+
}
|
|
250
|
+
return (0, idConversion_1.cleanWorkItemResponse)(response.workItemCreate.workItem);
|
|
251
|
+
}
|
|
252
|
+
case "update": {
|
|
253
|
+
const { id, title, description, state, assigneeIds, labelIds, milestoneId } = input;
|
|
254
|
+
const connectionManager = ConnectionManager_1.ConnectionManager.getInstance();
|
|
255
|
+
const client = connectionManager.getClient();
|
|
256
|
+
const workItemGid = (0, idConversion_1.toGid)(id, "WorkItem");
|
|
257
|
+
const updateInput = { id: workItemGid };
|
|
258
|
+
if (title !== undefined)
|
|
259
|
+
updateInput.title = title;
|
|
260
|
+
if (state !== undefined)
|
|
261
|
+
updateInput.stateEvent = state;
|
|
262
|
+
if (description !== undefined) {
|
|
263
|
+
updateInput.descriptionWidget = { description };
|
|
264
|
+
}
|
|
265
|
+
if (assigneeIds !== undefined) {
|
|
266
|
+
updateInput.assigneesWidget = { assigneeIds: (0, idConversion_1.toGids)(assigneeIds, "User") };
|
|
267
|
+
}
|
|
268
|
+
if (labelIds !== undefined) {
|
|
269
|
+
updateInput.labelsWidget = { addLabelIds: (0, idConversion_1.toGids)(labelIds, "Label") };
|
|
270
|
+
}
|
|
271
|
+
if (milestoneId !== undefined) {
|
|
272
|
+
updateInput.milestoneWidget = { milestoneId: (0, idConversion_1.toGid)(milestoneId, "Milestone") };
|
|
273
|
+
}
|
|
274
|
+
const response = await client.request(workItems_1.UPDATE_WORK_ITEM, { input: updateInput });
|
|
275
|
+
if (response.workItemUpdate?.errors?.length &&
|
|
276
|
+
response.workItemUpdate.errors.length > 0) {
|
|
277
|
+
throw new Error(`GitLab GraphQL errors: ${response.workItemUpdate.errors.join(", ")}`);
|
|
278
|
+
}
|
|
279
|
+
if (!response.workItemUpdate?.workItem) {
|
|
280
|
+
throw new Error("Work item update failed - no work item returned");
|
|
281
|
+
}
|
|
282
|
+
return (0, idConversion_1.cleanWorkItemResponse)(response.workItemUpdate.workItem);
|
|
283
|
+
}
|
|
284
|
+
case "delete": {
|
|
285
|
+
const { id } = input;
|
|
286
|
+
const connectionManager = ConnectionManager_1.ConnectionManager.getInstance();
|
|
287
|
+
const client = connectionManager.getClient();
|
|
288
|
+
const workItemGid = (0, idConversion_1.toGid)(id, "WorkItem");
|
|
289
|
+
const response = await client.request(workItems_1.DELETE_WORK_ITEM, { id: workItemGid });
|
|
290
|
+
if (response.workItemDelete?.errors?.length &&
|
|
291
|
+
response.workItemDelete.errors.length > 0) {
|
|
292
|
+
throw new Error(`GitLab GraphQL errors: ${response.workItemDelete.errors.join(", ")}`);
|
|
293
|
+
}
|
|
294
|
+
return { deleted: true };
|
|
295
|
+
}
|
|
296
|
+
default: {
|
|
297
|
+
const _exhaustive = input;
|
|
298
|
+
throw new Error(`Unknown action: ${_exhaustive.action}`);
|
|
299
|
+
}
|
|
311
300
|
}
|
|
312
|
-
return { deleted: true };
|
|
313
301
|
},
|
|
314
302
|
},
|
|
315
303
|
],
|
|
316
304
|
]);
|
|
317
305
|
function getWorkitemsReadOnlyToolNames() {
|
|
318
|
-
return ["
|
|
306
|
+
return ["browse_work_items"];
|
|
319
307
|
}
|
|
320
308
|
function getWorkitemsToolDefinitions() {
|
|
321
309
|
return Array.from(exports.workitemsToolRegistry.values());
|