@zereight/mcp-gitlab 1.0.17 β 1.0.19
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 +7 -0
- package/build/index.js +509 -15
- package/build/schemas.js +169 -44
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -174,6 +174,13 @@ env GITLAB_PERSONAL_ACCESS_TOKEN=your_gitlab_token GITLAB_API_URL=your_gitlab_ap
|
|
|
174
174
|
- `body` (string): Note content
|
|
175
175
|
- Returns: Details of the created note
|
|
176
176
|
|
|
177
|
+
| **`list_projects`** | List accessible projects with rich filtering options π | β’ Search/filtering: `search`, `owned`, `membership`, `archived`, `visibility`<br>β’ Features filtering: `with_issues_enabled`, `with_merge_requests_enabled`<br>β’ Sorting: `order_by`, `sort`<br>β’ Access control: `min_access_level`<br>β’ Pagination: `page`, `per_page`, `simple` | Array of projects |
|
|
178
|
+
| **`list_labels`** | List all labels for a project with filtering options π·οΈ | β’ `project_id` (string): Project ID or path<br>β’ `with_counts` (optional): Include issue and merge request counts<br>β’ `include_ancestor_groups` (optional): Include ancestor groups<br>β’ `search` (optional): Filter labels by keyword | Array of labels |
|
|
179
|
+
| **`get_label`** | Get a single label from a project π·οΈ | β’ `project_id` (string): Project ID or path<br>β’ `label_id` (number/string): Label ID or name<br>β’ `include_ancestor_groups` (optional): Include ancestor groups | Label details |
|
|
180
|
+
| **`create_label`** | Create a new label in a project π·οΈβ | β’ `project_id` (string): Project ID or path<br>β’ `name` (string): Label name<br>β’ `color` (string): Color in hex format (e.g., "#FF0000")<br>β’ `description` (optional): Label description<br>β’ `priority` (optional): Label priority | Created label details |
|
|
181
|
+
| **`update_label`** | Update an existing label in a project π·οΈβοΈ | β’ `project_id` (string): Project ID or path<br>β’ `label_id` (number/string): Label ID or name<br>β’ `new_name` (optional): New label name<br>β’ `color` (optional): New color in hex format<br>β’ `description` (optional): New description<br>β’ `priority` (optional): New priority | Updated label details |
|
|
182
|
+
| **`delete_label`** | Delete a label from a project π·οΈβ | β’ `project_id` (string): Project ID or path<br>β’ `label_id` (number/string): Label ID or name | Success message |
|
|
183
|
+
|
|
177
184
|
## Environment Variable Configuration
|
|
178
185
|
|
|
179
186
|
Before running the server, you need to set the following environment variables:
|
package/build/index.js
CHANGED
|
@@ -9,7 +9,7 @@ import { fileURLToPath } from "url";
|
|
|
9
9
|
import { dirname } from "path";
|
|
10
10
|
import fs from "fs";
|
|
11
11
|
import path from "path";
|
|
12
|
-
import { GitLabForkSchema, GitLabReferenceSchema, GitLabRepositorySchema, GitLabIssueSchema, GitLabMergeRequestSchema, GitLabContentSchema, GitLabCreateUpdateFileResponseSchema, GitLabSearchResponseSchema, GitLabTreeSchema, GitLabCommitSchema, GitLabNamespaceSchema, GitLabNamespaceExistsResponseSchema, CreateOrUpdateFileSchema, SearchRepositoriesSchema, CreateRepositorySchema, GetFileContentsSchema, PushFilesSchema, CreateIssueSchema, CreateMergeRequestSchema, ForkRepositorySchema, CreateBranchSchema, GitLabMergeRequestDiffSchema, GetMergeRequestSchema, GetMergeRequestDiffsSchema, UpdateMergeRequestSchema, ListNamespacesSchema, GetNamespaceSchema, VerifyNamespaceSchema, GetProjectSchema, ListProjectsSchema, CreateNoteSchema, } from "./schemas.js";
|
|
12
|
+
import { GitLabForkSchema, GitLabReferenceSchema, GitLabRepositorySchema, GitLabIssueSchema, GitLabMergeRequestSchema, GitLabContentSchema, GitLabCreateUpdateFileResponseSchema, GitLabSearchResponseSchema, GitLabTreeSchema, GitLabCommitSchema, GitLabNamespaceSchema, GitLabNamespaceExistsResponseSchema, GitLabProjectSchema, CreateOrUpdateFileSchema, SearchRepositoriesSchema, CreateRepositorySchema, GetFileContentsSchema, PushFilesSchema, CreateIssueSchema, CreateMergeRequestSchema, ForkRepositorySchema, CreateBranchSchema, GitLabMergeRequestDiffSchema, GetMergeRequestSchema, GetMergeRequestDiffsSchema, UpdateMergeRequestSchema, ListIssuesSchema, GetIssueSchema, UpdateIssueSchema, DeleteIssueSchema, GitLabIssueLinkSchema, GitLabIssueWithLinkDetailsSchema, ListIssueLinksSchema, GetIssueLinkSchema, CreateIssueLinkSchema, DeleteIssueLinkSchema, ListNamespacesSchema, GetNamespaceSchema, VerifyNamespaceSchema, GetProjectSchema, ListProjectsSchema, ListLabelsSchema, GetLabelSchema, CreateLabelSchema, UpdateLabelSchema, DeleteLabelSchema, CreateNoteSchema, } from "./schemas.js";
|
|
13
13
|
/**
|
|
14
14
|
* Read version from package.json
|
|
15
15
|
*/
|
|
@@ -215,6 +215,171 @@ async function createIssue(projectId, options) {
|
|
|
215
215
|
const data = await response.json();
|
|
216
216
|
return GitLabIssueSchema.parse(data);
|
|
217
217
|
}
|
|
218
|
+
/**
|
|
219
|
+
* List issues in a GitLab project
|
|
220
|
+
* νλ‘μ νΈμ μ΄μ λͺ©λ‘ μ‘°ν
|
|
221
|
+
*
|
|
222
|
+
* @param {string} projectId - The ID or URL-encoded path of the project
|
|
223
|
+
* @param {Object} options - Options for listing issues
|
|
224
|
+
* @returns {Promise<GitLabIssue[]>} List of issues
|
|
225
|
+
*/
|
|
226
|
+
async function listIssues(projectId, options = {}) {
|
|
227
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/issues`);
|
|
228
|
+
// Add all query parameters
|
|
229
|
+
Object.entries(options).forEach(([key, value]) => {
|
|
230
|
+
if (value !== undefined) {
|
|
231
|
+
if (key === 'label_name' && Array.isArray(value)) {
|
|
232
|
+
// Handle array of labels
|
|
233
|
+
url.searchParams.append(key, value.join(','));
|
|
234
|
+
}
|
|
235
|
+
else {
|
|
236
|
+
url.searchParams.append(key, value.toString());
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
const response = await fetch(url.toString(), {
|
|
241
|
+
headers: DEFAULT_HEADERS,
|
|
242
|
+
});
|
|
243
|
+
await handleGitLabError(response);
|
|
244
|
+
const data = await response.json();
|
|
245
|
+
return z.array(GitLabIssueSchema).parse(data);
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Get a single issue from a GitLab project
|
|
249
|
+
* λ¨μΌ μ΄μ μ‘°ν
|
|
250
|
+
*
|
|
251
|
+
* @param {string} projectId - The ID or URL-encoded path of the project
|
|
252
|
+
* @param {number} issueIid - The internal ID of the project issue
|
|
253
|
+
* @returns {Promise<GitLabIssue>} The issue
|
|
254
|
+
*/
|
|
255
|
+
async function getIssue(projectId, issueIid) {
|
|
256
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/issues/${issueIid}`);
|
|
257
|
+
const response = await fetch(url.toString(), {
|
|
258
|
+
headers: DEFAULT_HEADERS,
|
|
259
|
+
});
|
|
260
|
+
await handleGitLabError(response);
|
|
261
|
+
const data = await response.json();
|
|
262
|
+
return GitLabIssueSchema.parse(data);
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Update an issue in a GitLab project
|
|
266
|
+
* μ΄μ μ
λ°μ΄νΈ
|
|
267
|
+
*
|
|
268
|
+
* @param {string} projectId - The ID or URL-encoded path of the project
|
|
269
|
+
* @param {number} issueIid - The internal ID of the project issue
|
|
270
|
+
* @param {Object} options - Update options for the issue
|
|
271
|
+
* @returns {Promise<GitLabIssue>} The updated issue
|
|
272
|
+
*/
|
|
273
|
+
async function updateIssue(projectId, issueIid, options) {
|
|
274
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/issues/${issueIid}`);
|
|
275
|
+
// Convert labels array to comma-separated string if present
|
|
276
|
+
const body = { ...options };
|
|
277
|
+
if (body.labels && Array.isArray(body.labels)) {
|
|
278
|
+
body.labels = body.labels.join(',');
|
|
279
|
+
}
|
|
280
|
+
const response = await fetch(url.toString(), {
|
|
281
|
+
method: "PUT",
|
|
282
|
+
headers: DEFAULT_HEADERS,
|
|
283
|
+
body: JSON.stringify(body),
|
|
284
|
+
});
|
|
285
|
+
await handleGitLabError(response);
|
|
286
|
+
const data = await response.json();
|
|
287
|
+
return GitLabIssueSchema.parse(data);
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Delete an issue from a GitLab project
|
|
291
|
+
* μ΄μ μμ
|
|
292
|
+
*
|
|
293
|
+
* @param {string} projectId - The ID or URL-encoded path of the project
|
|
294
|
+
* @param {number} issueIid - The internal ID of the project issue
|
|
295
|
+
* @returns {Promise<void>}
|
|
296
|
+
*/
|
|
297
|
+
async function deleteIssue(projectId, issueIid) {
|
|
298
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/issues/${issueIid}`);
|
|
299
|
+
const response = await fetch(url.toString(), {
|
|
300
|
+
method: "DELETE",
|
|
301
|
+
headers: DEFAULT_HEADERS,
|
|
302
|
+
});
|
|
303
|
+
await handleGitLabError(response);
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* List all issue links for a specific issue
|
|
307
|
+
* μ΄μ κ΄κ³ λͺ©λ‘ μ‘°ν
|
|
308
|
+
*
|
|
309
|
+
* @param {string} projectId - The ID or URL-encoded path of the project
|
|
310
|
+
* @param {number} issueIid - The internal ID of the project issue
|
|
311
|
+
* @returns {Promise<GitLabIssueWithLinkDetails[]>} List of issues with link details
|
|
312
|
+
*/
|
|
313
|
+
async function listIssueLinks(projectId, issueIid) {
|
|
314
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/issues/${issueIid}/links`);
|
|
315
|
+
const response = await fetch(url.toString(), {
|
|
316
|
+
headers: DEFAULT_HEADERS,
|
|
317
|
+
});
|
|
318
|
+
await handleGitLabError(response);
|
|
319
|
+
const data = await response.json();
|
|
320
|
+
return z.array(GitLabIssueWithLinkDetailsSchema).parse(data);
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Get a specific issue link
|
|
324
|
+
* νΉμ μ΄μ κ΄κ³ μ‘°ν
|
|
325
|
+
*
|
|
326
|
+
* @param {string} projectId - The ID or URL-encoded path of the project
|
|
327
|
+
* @param {number} issueIid - The internal ID of the project issue
|
|
328
|
+
* @param {number} issueLinkId - The ID of the issue link
|
|
329
|
+
* @returns {Promise<GitLabIssueLink>} The issue link
|
|
330
|
+
*/
|
|
331
|
+
async function getIssueLink(projectId, issueIid, issueLinkId) {
|
|
332
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/issues/${issueIid}/links/${issueLinkId}`);
|
|
333
|
+
const response = await fetch(url.toString(), {
|
|
334
|
+
headers: DEFAULT_HEADERS,
|
|
335
|
+
});
|
|
336
|
+
await handleGitLabError(response);
|
|
337
|
+
const data = await response.json();
|
|
338
|
+
return GitLabIssueLinkSchema.parse(data);
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* Create an issue link between two issues
|
|
342
|
+
* μ΄μ κ΄κ³ μμ±
|
|
343
|
+
*
|
|
344
|
+
* @param {string} projectId - The ID or URL-encoded path of the project
|
|
345
|
+
* @param {number} issueIid - The internal ID of the project issue
|
|
346
|
+
* @param {string} targetProjectId - The ID or URL-encoded path of the target project
|
|
347
|
+
* @param {number} targetIssueIid - The internal ID of the target project issue
|
|
348
|
+
* @param {string} linkType - The type of the relation (relates_to, blocks, is_blocked_by)
|
|
349
|
+
* @returns {Promise<GitLabIssueLink>} The created issue link
|
|
350
|
+
*/
|
|
351
|
+
async function createIssueLink(projectId, issueIid, targetProjectId, targetIssueIid, linkType = 'relates_to') {
|
|
352
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/issues/${issueIid}/links`);
|
|
353
|
+
const response = await fetch(url.toString(), {
|
|
354
|
+
method: "POST",
|
|
355
|
+
headers: DEFAULT_HEADERS,
|
|
356
|
+
body: JSON.stringify({
|
|
357
|
+
target_project_id: targetProjectId,
|
|
358
|
+
target_issue_iid: targetIssueIid,
|
|
359
|
+
link_type: linkType
|
|
360
|
+
}),
|
|
361
|
+
});
|
|
362
|
+
await handleGitLabError(response);
|
|
363
|
+
const data = await response.json();
|
|
364
|
+
return GitLabIssueLinkSchema.parse(data);
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* Delete an issue link
|
|
368
|
+
* μ΄μ κ΄κ³ μμ
|
|
369
|
+
*
|
|
370
|
+
* @param {string} projectId - The ID or URL-encoded path of the project
|
|
371
|
+
* @param {number} issueIid - The internal ID of the project issue
|
|
372
|
+
* @param {number} issueLinkId - The ID of the issue link
|
|
373
|
+
* @returns {Promise<void>}
|
|
374
|
+
*/
|
|
375
|
+
async function deleteIssueLink(projectId, issueIid, issueLinkId) {
|
|
376
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/issues/${issueIid}/links/${issueLinkId}`);
|
|
377
|
+
const response = await fetch(url.toString(), {
|
|
378
|
+
method: "DELETE",
|
|
379
|
+
headers: DEFAULT_HEADERS,
|
|
380
|
+
});
|
|
381
|
+
await handleGitLabError(response);
|
|
382
|
+
}
|
|
218
383
|
/**
|
|
219
384
|
* Create a new merge request in a GitLab project
|
|
220
385
|
* λ³ν© μμ² μμ±
|
|
@@ -661,19 +826,139 @@ async function getProject(projectId, options = {}) {
|
|
|
661
826
|
* @returns {Promise<GitLabProject[]>} List of projects
|
|
662
827
|
*/
|
|
663
828
|
async function listProjects(options = {}) {
|
|
664
|
-
|
|
665
|
-
|
|
829
|
+
// Construct the query parameters
|
|
830
|
+
const params = new URLSearchParams();
|
|
831
|
+
for (const [key, value] of Object.entries(options)) {
|
|
832
|
+
if (value !== undefined && value !== null) {
|
|
833
|
+
if (typeof value === "boolean") {
|
|
834
|
+
params.append(key, value ? "true" : "false");
|
|
835
|
+
}
|
|
836
|
+
else {
|
|
837
|
+
params.append(key, String(value));
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
// Make the API request
|
|
842
|
+
const response = await fetch(`${GITLAB_API_URL}/projects?${params.toString()}`, {
|
|
843
|
+
method: "GET",
|
|
844
|
+
headers: DEFAULT_HEADERS,
|
|
845
|
+
});
|
|
846
|
+
// Handle errors
|
|
847
|
+
await handleGitLabError(response);
|
|
848
|
+
// Parse and return the data
|
|
849
|
+
const data = await response.json();
|
|
850
|
+
return z.array(GitLabProjectSchema).parse(data);
|
|
851
|
+
}
|
|
852
|
+
/**
|
|
853
|
+
* List labels for a project
|
|
854
|
+
*
|
|
855
|
+
* @param projectId The ID or URL-encoded path of the project
|
|
856
|
+
* @param options Optional parameters for listing labels
|
|
857
|
+
* @returns Array of GitLab labels
|
|
858
|
+
*/
|
|
859
|
+
async function listLabels(projectId, options = {}) {
|
|
860
|
+
// Construct the URL with project path
|
|
861
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/labels`);
|
|
862
|
+
// Add query parameters
|
|
666
863
|
Object.entries(options).forEach(([key, value]) => {
|
|
667
864
|
if (value !== undefined) {
|
|
668
|
-
|
|
865
|
+
if (typeof value === "boolean") {
|
|
866
|
+
url.searchParams.append(key, value ? "true" : "false");
|
|
867
|
+
}
|
|
868
|
+
else {
|
|
869
|
+
url.searchParams.append(key, String(value));
|
|
870
|
+
}
|
|
669
871
|
}
|
|
670
872
|
});
|
|
873
|
+
// Make the API request
|
|
671
874
|
const response = await fetch(url.toString(), {
|
|
672
875
|
headers: DEFAULT_HEADERS,
|
|
673
876
|
});
|
|
877
|
+
// Handle errors
|
|
674
878
|
await handleGitLabError(response);
|
|
879
|
+
// Parse and return the data
|
|
675
880
|
const data = await response.json();
|
|
676
|
-
return
|
|
881
|
+
return data;
|
|
882
|
+
}
|
|
883
|
+
/**
|
|
884
|
+
* Get a single label from a project
|
|
885
|
+
*
|
|
886
|
+
* @param projectId The ID or URL-encoded path of the project
|
|
887
|
+
* @param labelId The ID or name of the label
|
|
888
|
+
* @param includeAncestorGroups Whether to include ancestor groups
|
|
889
|
+
* @returns GitLab label
|
|
890
|
+
*/
|
|
891
|
+
async function getLabel(projectId, labelId, includeAncestorGroups) {
|
|
892
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/labels/${encodeURIComponent(String(labelId))}`);
|
|
893
|
+
// Add query parameters
|
|
894
|
+
if (includeAncestorGroups !== undefined) {
|
|
895
|
+
url.searchParams.append("include_ancestor_groups", includeAncestorGroups ? "true" : "false");
|
|
896
|
+
}
|
|
897
|
+
// Make the API request
|
|
898
|
+
const response = await fetch(url.toString(), {
|
|
899
|
+
headers: DEFAULT_HEADERS,
|
|
900
|
+
});
|
|
901
|
+
// Handle errors
|
|
902
|
+
await handleGitLabError(response);
|
|
903
|
+
// Parse and return the data
|
|
904
|
+
const data = await response.json();
|
|
905
|
+
return data;
|
|
906
|
+
}
|
|
907
|
+
/**
|
|
908
|
+
* Create a new label in a project
|
|
909
|
+
*
|
|
910
|
+
* @param projectId The ID or URL-encoded path of the project
|
|
911
|
+
* @param options Options for creating the label
|
|
912
|
+
* @returns Created GitLab label
|
|
913
|
+
*/
|
|
914
|
+
async function createLabel(projectId, options) {
|
|
915
|
+
// Make the API request
|
|
916
|
+
const response = await fetch(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/labels`, {
|
|
917
|
+
method: "POST",
|
|
918
|
+
headers: DEFAULT_HEADERS,
|
|
919
|
+
body: JSON.stringify(options),
|
|
920
|
+
});
|
|
921
|
+
// Handle errors
|
|
922
|
+
await handleGitLabError(response);
|
|
923
|
+
// Parse and return the data
|
|
924
|
+
const data = await response.json();
|
|
925
|
+
return data;
|
|
926
|
+
}
|
|
927
|
+
/**
|
|
928
|
+
* Update an existing label in a project
|
|
929
|
+
*
|
|
930
|
+
* @param projectId The ID or URL-encoded path of the project
|
|
931
|
+
* @param labelId The ID or name of the label to update
|
|
932
|
+
* @param options Options for updating the label
|
|
933
|
+
* @returns Updated GitLab label
|
|
934
|
+
*/
|
|
935
|
+
async function updateLabel(projectId, labelId, options) {
|
|
936
|
+
// Make the API request
|
|
937
|
+
const response = await fetch(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/labels/${encodeURIComponent(String(labelId))}`, {
|
|
938
|
+
method: "PUT",
|
|
939
|
+
headers: DEFAULT_HEADERS,
|
|
940
|
+
body: JSON.stringify(options),
|
|
941
|
+
});
|
|
942
|
+
// Handle errors
|
|
943
|
+
await handleGitLabError(response);
|
|
944
|
+
// Parse and return the data
|
|
945
|
+
const data = await response.json();
|
|
946
|
+
return data;
|
|
947
|
+
}
|
|
948
|
+
/**
|
|
949
|
+
* Delete a label from a project
|
|
950
|
+
*
|
|
951
|
+
* @param projectId The ID or URL-encoded path of the project
|
|
952
|
+
* @param labelId The ID or name of the label to delete
|
|
953
|
+
*/
|
|
954
|
+
async function deleteLabel(projectId, labelId) {
|
|
955
|
+
// Make the API request
|
|
956
|
+
const response = await fetch(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/labels/${encodeURIComponent(String(labelId))}`, {
|
|
957
|
+
method: "DELETE",
|
|
958
|
+
headers: DEFAULT_HEADERS,
|
|
959
|
+
});
|
|
960
|
+
// Handle errors
|
|
961
|
+
await handleGitLabError(response);
|
|
677
962
|
}
|
|
678
963
|
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
679
964
|
return {
|
|
@@ -743,6 +1028,46 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
743
1028
|
description: "Create a new note (comment) to an issue or merge request",
|
|
744
1029
|
inputSchema: zodToJsonSchema(CreateNoteSchema),
|
|
745
1030
|
},
|
|
1031
|
+
{
|
|
1032
|
+
name: "list_issues",
|
|
1033
|
+
description: "List issues in a GitLab project with filtering options",
|
|
1034
|
+
inputSchema: zodToJsonSchema(ListIssuesSchema),
|
|
1035
|
+
},
|
|
1036
|
+
{
|
|
1037
|
+
name: "get_issue",
|
|
1038
|
+
description: "Get details of a specific issue in a GitLab project",
|
|
1039
|
+
inputSchema: zodToJsonSchema(GetIssueSchema),
|
|
1040
|
+
},
|
|
1041
|
+
{
|
|
1042
|
+
name: "update_issue",
|
|
1043
|
+
description: "Update an issue in a GitLab project",
|
|
1044
|
+
inputSchema: zodToJsonSchema(UpdateIssueSchema),
|
|
1045
|
+
},
|
|
1046
|
+
{
|
|
1047
|
+
name: "delete_issue",
|
|
1048
|
+
description: "Delete an issue from a GitLab project",
|
|
1049
|
+
inputSchema: zodToJsonSchema(DeleteIssueSchema),
|
|
1050
|
+
},
|
|
1051
|
+
{
|
|
1052
|
+
name: "list_issue_links",
|
|
1053
|
+
description: "List all issue links for a specific issue",
|
|
1054
|
+
inputSchema: zodToJsonSchema(ListIssueLinksSchema),
|
|
1055
|
+
},
|
|
1056
|
+
{
|
|
1057
|
+
name: "get_issue_link",
|
|
1058
|
+
description: "Get a specific issue link",
|
|
1059
|
+
inputSchema: zodToJsonSchema(GetIssueLinkSchema),
|
|
1060
|
+
},
|
|
1061
|
+
{
|
|
1062
|
+
name: "create_issue_link",
|
|
1063
|
+
description: "Create an issue link between two issues",
|
|
1064
|
+
inputSchema: zodToJsonSchema(CreateIssueLinkSchema),
|
|
1065
|
+
},
|
|
1066
|
+
{
|
|
1067
|
+
name: "delete_issue_link",
|
|
1068
|
+
description: "Delete an issue link",
|
|
1069
|
+
inputSchema: zodToJsonSchema(DeleteIssueLinkSchema),
|
|
1070
|
+
},
|
|
746
1071
|
{
|
|
747
1072
|
name: "list_namespaces",
|
|
748
1073
|
description: "List all namespaces available to the current user",
|
|
@@ -750,17 +1075,17 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
750
1075
|
},
|
|
751
1076
|
{
|
|
752
1077
|
name: "get_namespace",
|
|
753
|
-
description: "Get details
|
|
1078
|
+
description: "Get details of a namespace by ID or path",
|
|
754
1079
|
inputSchema: zodToJsonSchema(GetNamespaceSchema),
|
|
755
1080
|
},
|
|
756
1081
|
{
|
|
757
1082
|
name: "verify_namespace",
|
|
758
|
-
description: "Verify if a
|
|
1083
|
+
description: "Verify if a namespace path exists",
|
|
759
1084
|
inputSchema: zodToJsonSchema(VerifyNamespaceSchema),
|
|
760
1085
|
},
|
|
761
1086
|
{
|
|
762
1087
|
name: "get_project",
|
|
763
|
-
description: "Get details
|
|
1088
|
+
description: "Get details of a specific project",
|
|
764
1089
|
inputSchema: zodToJsonSchema(GetProjectSchema),
|
|
765
1090
|
},
|
|
766
1091
|
{
|
|
@@ -768,6 +1093,31 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
768
1093
|
description: "List projects accessible by the current user",
|
|
769
1094
|
inputSchema: zodToJsonSchema(ListProjectsSchema),
|
|
770
1095
|
},
|
|
1096
|
+
{
|
|
1097
|
+
name: "list_labels",
|
|
1098
|
+
description: "List labels for a project",
|
|
1099
|
+
inputSchema: zodToJsonSchema(ListLabelsSchema),
|
|
1100
|
+
},
|
|
1101
|
+
{
|
|
1102
|
+
name: "get_label",
|
|
1103
|
+
description: "Get a single label from a project",
|
|
1104
|
+
inputSchema: zodToJsonSchema(GetLabelSchema),
|
|
1105
|
+
},
|
|
1106
|
+
{
|
|
1107
|
+
name: "create_label",
|
|
1108
|
+
description: "Create a new label in a project",
|
|
1109
|
+
inputSchema: zodToJsonSchema(CreateLabelSchema),
|
|
1110
|
+
},
|
|
1111
|
+
{
|
|
1112
|
+
name: "update_label",
|
|
1113
|
+
description: "Update an existing label in a project",
|
|
1114
|
+
inputSchema: zodToJsonSchema(UpdateLabelSchema),
|
|
1115
|
+
},
|
|
1116
|
+
{
|
|
1117
|
+
name: "delete_label",
|
|
1118
|
+
description: "Delete a label from a project",
|
|
1119
|
+
inputSchema: zodToJsonSchema(DeleteLabelSchema),
|
|
1120
|
+
},
|
|
771
1121
|
],
|
|
772
1122
|
};
|
|
773
1123
|
});
|
|
@@ -893,36 +1243,86 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
893
1243
|
}
|
|
894
1244
|
case "list_namespaces": {
|
|
895
1245
|
const args = ListNamespacesSchema.parse(request.params.arguments);
|
|
896
|
-
const
|
|
1246
|
+
const url = new URL(`${GITLAB_API_URL}/namespaces`);
|
|
1247
|
+
if (args.search) {
|
|
1248
|
+
url.searchParams.append("search", args.search);
|
|
1249
|
+
}
|
|
1250
|
+
if (args.page) {
|
|
1251
|
+
url.searchParams.append("page", args.page.toString());
|
|
1252
|
+
}
|
|
1253
|
+
if (args.per_page) {
|
|
1254
|
+
url.searchParams.append("per_page", args.per_page.toString());
|
|
1255
|
+
}
|
|
1256
|
+
if (args.owned) {
|
|
1257
|
+
url.searchParams.append("owned", args.owned.toString());
|
|
1258
|
+
}
|
|
1259
|
+
const response = await fetch(url.toString(), {
|
|
1260
|
+
headers: DEFAULT_HEADERS,
|
|
1261
|
+
});
|
|
1262
|
+
await handleGitLabError(response);
|
|
1263
|
+
const data = await response.json();
|
|
1264
|
+
const namespaces = z.array(GitLabNamespaceSchema).parse(data);
|
|
897
1265
|
return {
|
|
898
1266
|
content: [{ type: "text", text: JSON.stringify(namespaces, null, 2) }],
|
|
899
1267
|
};
|
|
900
1268
|
}
|
|
901
1269
|
case "get_namespace": {
|
|
902
1270
|
const args = GetNamespaceSchema.parse(request.params.arguments);
|
|
903
|
-
const
|
|
1271
|
+
const url = new URL(`${GITLAB_API_URL}/namespaces/${encodeURIComponent(args.namespace_id)}`);
|
|
1272
|
+
const response = await fetch(url.toString(), {
|
|
1273
|
+
headers: DEFAULT_HEADERS,
|
|
1274
|
+
});
|
|
1275
|
+
await handleGitLabError(response);
|
|
1276
|
+
const data = await response.json();
|
|
1277
|
+
const namespace = GitLabNamespaceSchema.parse(data);
|
|
904
1278
|
return {
|
|
905
1279
|
content: [{ type: "text", text: JSON.stringify(namespace, null, 2) }],
|
|
906
1280
|
};
|
|
907
1281
|
}
|
|
908
1282
|
case "verify_namespace": {
|
|
909
1283
|
const args = VerifyNamespaceSchema.parse(request.params.arguments);
|
|
910
|
-
const
|
|
1284
|
+
const url = new URL(`${GITLAB_API_URL}/namespaces/${encodeURIComponent(args.path)}/exists`);
|
|
1285
|
+
const response = await fetch(url.toString(), {
|
|
1286
|
+
headers: DEFAULT_HEADERS,
|
|
1287
|
+
});
|
|
1288
|
+
await handleGitLabError(response);
|
|
1289
|
+
const data = await response.json();
|
|
1290
|
+
const namespaceExists = GitLabNamespaceExistsResponseSchema.parse(data);
|
|
911
1291
|
return {
|
|
912
|
-
content: [{ type: "text", text: JSON.stringify(
|
|
1292
|
+
content: [{ type: "text", text: JSON.stringify(namespaceExists, null, 2) }],
|
|
913
1293
|
};
|
|
914
1294
|
}
|
|
915
1295
|
case "get_project": {
|
|
916
1296
|
const args = GetProjectSchema.parse(request.params.arguments);
|
|
917
|
-
const
|
|
918
|
-
const
|
|
1297
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(args.project_id)}`);
|
|
1298
|
+
const response = await fetch(url.toString(), {
|
|
1299
|
+
headers: DEFAULT_HEADERS,
|
|
1300
|
+
});
|
|
1301
|
+
await handleGitLabError(response);
|
|
1302
|
+
const data = await response.json();
|
|
1303
|
+
const project = GitLabProjectSchema.parse(data);
|
|
919
1304
|
return {
|
|
920
1305
|
content: [{ type: "text", text: JSON.stringify(project, null, 2) }],
|
|
921
1306
|
};
|
|
922
1307
|
}
|
|
923
1308
|
case "list_projects": {
|
|
924
1309
|
const args = ListProjectsSchema.parse(request.params.arguments);
|
|
925
|
-
const
|
|
1310
|
+
const url = new URL(`${GITLAB_API_URL}/projects`);
|
|
1311
|
+
// Add query parameters for filtering
|
|
1312
|
+
Object.entries(args).forEach(([key, value]) => {
|
|
1313
|
+
if (value !== undefined) {
|
|
1314
|
+
url.searchParams.append(key, value.toString());
|
|
1315
|
+
}
|
|
1316
|
+
});
|
|
1317
|
+
const response = await fetch(url.toString(), {
|
|
1318
|
+
method: "GET",
|
|
1319
|
+
headers: DEFAULT_HEADERS,
|
|
1320
|
+
});
|
|
1321
|
+
// Handle errors
|
|
1322
|
+
await handleGitLabError(response);
|
|
1323
|
+
// Parse and return the data
|
|
1324
|
+
const data = await response.json();
|
|
1325
|
+
const projects = z.array(GitLabProjectSchema).parse(data);
|
|
926
1326
|
return {
|
|
927
1327
|
content: [{ type: "text", text: JSON.stringify(projects, null, 2) }],
|
|
928
1328
|
};
|
|
@@ -935,6 +1335,100 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
935
1335
|
content: [{ type: "text", text: JSON.stringify(note, null, 2) }],
|
|
936
1336
|
};
|
|
937
1337
|
}
|
|
1338
|
+
case "list_issues": {
|
|
1339
|
+
const args = ListIssuesSchema.parse(request.params.arguments);
|
|
1340
|
+
const { project_id, ...options } = args;
|
|
1341
|
+
const issues = await listIssues(project_id, options);
|
|
1342
|
+
return {
|
|
1343
|
+
content: [{ type: "text", text: JSON.stringify(issues, null, 2) }],
|
|
1344
|
+
};
|
|
1345
|
+
}
|
|
1346
|
+
case "get_issue": {
|
|
1347
|
+
const args = GetIssueSchema.parse(request.params.arguments);
|
|
1348
|
+
const issue = await getIssue(args.project_id, args.issue_iid);
|
|
1349
|
+
return {
|
|
1350
|
+
content: [{ type: "text", text: JSON.stringify(issue, null, 2) }],
|
|
1351
|
+
};
|
|
1352
|
+
}
|
|
1353
|
+
case "update_issue": {
|
|
1354
|
+
const args = UpdateIssueSchema.parse(request.params.arguments);
|
|
1355
|
+
const { project_id, issue_iid, ...options } = args;
|
|
1356
|
+
const issue = await updateIssue(project_id, issue_iid, options);
|
|
1357
|
+
return {
|
|
1358
|
+
content: [{ type: "text", text: JSON.stringify(issue, null, 2) }],
|
|
1359
|
+
};
|
|
1360
|
+
}
|
|
1361
|
+
case "delete_issue": {
|
|
1362
|
+
const args = DeleteIssueSchema.parse(request.params.arguments);
|
|
1363
|
+
await deleteIssue(args.project_id, args.issue_iid);
|
|
1364
|
+
return {
|
|
1365
|
+
content: [{ type: "text", text: JSON.stringify({ status: "success", message: "Issue deleted successfully" }, null, 2) }],
|
|
1366
|
+
};
|
|
1367
|
+
}
|
|
1368
|
+
case "list_issue_links": {
|
|
1369
|
+
const args = ListIssueLinksSchema.parse(request.params.arguments);
|
|
1370
|
+
const links = await listIssueLinks(args.project_id, args.issue_iid);
|
|
1371
|
+
return {
|
|
1372
|
+
content: [{ type: "text", text: JSON.stringify(links, null, 2) }],
|
|
1373
|
+
};
|
|
1374
|
+
}
|
|
1375
|
+
case "get_issue_link": {
|
|
1376
|
+
const args = GetIssueLinkSchema.parse(request.params.arguments);
|
|
1377
|
+
const link = await getIssueLink(args.project_id, args.issue_iid, args.issue_link_id);
|
|
1378
|
+
return {
|
|
1379
|
+
content: [{ type: "text", text: JSON.stringify(link, null, 2) }],
|
|
1380
|
+
};
|
|
1381
|
+
}
|
|
1382
|
+
case "create_issue_link": {
|
|
1383
|
+
const args = CreateIssueLinkSchema.parse(request.params.arguments);
|
|
1384
|
+
const link = await createIssueLink(args.project_id, args.issue_iid, args.target_project_id, args.target_issue_iid, args.link_type);
|
|
1385
|
+
return {
|
|
1386
|
+
content: [{ type: "text", text: JSON.stringify(link, null, 2) }],
|
|
1387
|
+
};
|
|
1388
|
+
}
|
|
1389
|
+
case "delete_issue_link": {
|
|
1390
|
+
const args = DeleteIssueLinkSchema.parse(request.params.arguments);
|
|
1391
|
+
await deleteIssueLink(args.project_id, args.issue_iid, args.issue_link_id);
|
|
1392
|
+
return {
|
|
1393
|
+
content: [{ type: "text", text: JSON.stringify({ status: "success", message: "Issue link deleted successfully" }, null, 2) }],
|
|
1394
|
+
};
|
|
1395
|
+
}
|
|
1396
|
+
case "list_labels": {
|
|
1397
|
+
const args = ListLabelsSchema.parse(request.params.arguments);
|
|
1398
|
+
const labels = await listLabels(args.project_id, args);
|
|
1399
|
+
return {
|
|
1400
|
+
content: [{ type: "text", text: JSON.stringify(labels, null, 2) }],
|
|
1401
|
+
};
|
|
1402
|
+
}
|
|
1403
|
+
case "get_label": {
|
|
1404
|
+
const args = GetLabelSchema.parse(request.params.arguments);
|
|
1405
|
+
const label = await getLabel(args.project_id, args.label_id, args.include_ancestor_groups);
|
|
1406
|
+
return {
|
|
1407
|
+
content: [{ type: "text", text: JSON.stringify(label, null, 2) }],
|
|
1408
|
+
};
|
|
1409
|
+
}
|
|
1410
|
+
case "create_label": {
|
|
1411
|
+
const args = CreateLabelSchema.parse(request.params.arguments);
|
|
1412
|
+
const label = await createLabel(args.project_id, args);
|
|
1413
|
+
return {
|
|
1414
|
+
content: [{ type: "text", text: JSON.stringify(label, null, 2) }],
|
|
1415
|
+
};
|
|
1416
|
+
}
|
|
1417
|
+
case "update_label": {
|
|
1418
|
+
const args = UpdateLabelSchema.parse(request.params.arguments);
|
|
1419
|
+
const { project_id, label_id, ...options } = args;
|
|
1420
|
+
const label = await updateLabel(project_id, label_id, options);
|
|
1421
|
+
return {
|
|
1422
|
+
content: [{ type: "text", text: JSON.stringify(label, null, 2) }],
|
|
1423
|
+
};
|
|
1424
|
+
}
|
|
1425
|
+
case "delete_label": {
|
|
1426
|
+
const args = DeleteLabelSchema.parse(request.params.arguments);
|
|
1427
|
+
await deleteLabel(args.project_id, args.label_id);
|
|
1428
|
+
return {
|
|
1429
|
+
content: [{ type: "text", text: JSON.stringify({ status: "success", message: "Label deleted successfully" }, null, 2) }],
|
|
1430
|
+
};
|
|
1431
|
+
}
|
|
938
1432
|
default:
|
|
939
1433
|
throw new Error(`Unknown tool: ${request.params.name}`);
|
|
940
1434
|
}
|
package/build/schemas.js
CHANGED
|
@@ -96,6 +96,8 @@ export const GitLabRepositorySchema = z.object({
|
|
|
96
96
|
group_access_level: z.number(),
|
|
97
97
|
})).optional(),
|
|
98
98
|
});
|
|
99
|
+
// Project schema (extended from repository schema)
|
|
100
|
+
export const GitLabProjectSchema = GitLabRepositorySchema;
|
|
99
101
|
// File content schemas
|
|
100
102
|
export const GitLabFileContentSchema = z.object({
|
|
101
103
|
file_name: z.string(), // Changed from name to match GitLab API
|
|
@@ -200,26 +202,20 @@ export const GitLabSearchResponseSchema = z.object({
|
|
|
200
202
|
current_page: z.number().optional(),
|
|
201
203
|
items: z.array(GitLabRepositorySchema),
|
|
202
204
|
});
|
|
203
|
-
// Fork related schemas
|
|
204
|
-
export const GitLabForkParentSchema = z.object({
|
|
205
|
-
name: z.string(),
|
|
206
|
-
path_with_namespace: z.string(), // Changed from full_name to match GitLab API
|
|
207
|
-
owner: z.object({
|
|
208
|
-
username: z.string(), // Changed from login to match GitLab API
|
|
209
|
-
id: z.number(),
|
|
210
|
-
avatar_url: z.string(),
|
|
211
|
-
}).optional(), // Made optional to handle cases where GitLab API doesn't include it
|
|
212
|
-
web_url: z.string(), // Changed from html_url to match GitLab API
|
|
213
|
-
});
|
|
214
|
-
export const GitLabForkSchema = GitLabRepositorySchema.extend({
|
|
215
|
-
forked_from_project: GitLabForkParentSchema.optional(), // Made optional to handle cases where GitLab API doesn't include it
|
|
216
|
-
});
|
|
217
205
|
// Issue related schemas
|
|
218
206
|
export const GitLabLabelSchema = z.object({
|
|
219
207
|
id: z.number(),
|
|
220
208
|
name: z.string(),
|
|
221
209
|
color: z.string(),
|
|
222
|
-
|
|
210
|
+
text_color: z.string(),
|
|
211
|
+
description: z.string().nullable(),
|
|
212
|
+
description_html: z.string().nullable(),
|
|
213
|
+
open_issues_count: z.number().optional(),
|
|
214
|
+
closed_issues_count: z.number().optional(),
|
|
215
|
+
open_merge_requests_count: z.number().optional(),
|
|
216
|
+
subscribed: z.boolean().optional(),
|
|
217
|
+
priority: z.number().nullable().optional(),
|
|
218
|
+
is_project_label: z.boolean().optional(),
|
|
223
219
|
});
|
|
224
220
|
export const GitLabUserSchema = z.object({
|
|
225
221
|
username: z.string(), // Changed from login to match GitLab API
|
|
@@ -245,12 +241,48 @@ export const GitLabIssueSchema = z.object({
|
|
|
245
241
|
state: z.string(),
|
|
246
242
|
author: GitLabUserSchema,
|
|
247
243
|
assignees: z.array(GitLabUserSchema),
|
|
248
|
-
labels: z.array(GitLabLabelSchema),
|
|
244
|
+
labels: z.array(GitLabLabelSchema).or(z.array(z.string())), // Support both label objects and strings
|
|
249
245
|
milestone: GitLabMilestoneSchema.nullable(),
|
|
250
246
|
created_at: z.string(),
|
|
251
247
|
updated_at: z.string(),
|
|
252
248
|
closed_at: z.string().nullable(),
|
|
253
249
|
web_url: z.string(), // Changed from html_url to match GitLab API
|
|
250
|
+
references: z.object({
|
|
251
|
+
short: z.string(),
|
|
252
|
+
relative: z.string(),
|
|
253
|
+
full: z.string(),
|
|
254
|
+
}).optional(),
|
|
255
|
+
time_stats: z.object({
|
|
256
|
+
time_estimate: z.number(),
|
|
257
|
+
total_time_spent: z.number(),
|
|
258
|
+
human_time_estimate: z.string().nullable(),
|
|
259
|
+
human_total_time_spent: z.string().nullable(),
|
|
260
|
+
}).optional(),
|
|
261
|
+
confidential: z.boolean().optional(),
|
|
262
|
+
due_date: z.string().nullable().optional(),
|
|
263
|
+
discussion_locked: z.boolean().nullable().optional(),
|
|
264
|
+
weight: z.number().nullable().optional(),
|
|
265
|
+
});
|
|
266
|
+
// NEW SCHEMA: For issue with link details (used in listing issue links)
|
|
267
|
+
export const GitLabIssueWithLinkDetailsSchema = GitLabIssueSchema.extend({
|
|
268
|
+
issue_link_id: z.number(),
|
|
269
|
+
link_type: z.enum(['relates_to', 'blocks', 'is_blocked_by']),
|
|
270
|
+
link_created_at: z.string(),
|
|
271
|
+
link_updated_at: z.string(),
|
|
272
|
+
});
|
|
273
|
+
// Fork related schemas
|
|
274
|
+
export const GitLabForkParentSchema = z.object({
|
|
275
|
+
name: z.string(),
|
|
276
|
+
path_with_namespace: z.string(), // Changed from full_name to match GitLab API
|
|
277
|
+
owner: z.object({
|
|
278
|
+
username: z.string(), // Changed from login to match GitLab API
|
|
279
|
+
id: z.number(),
|
|
280
|
+
avatar_url: z.string(),
|
|
281
|
+
}).optional(), // Made optional to handle cases where GitLab API doesn't include it
|
|
282
|
+
web_url: z.string(), // Changed from html_url to match GitLab API
|
|
283
|
+
});
|
|
284
|
+
export const GitLabForkSchema = GitLabRepositorySchema.extend({
|
|
285
|
+
forked_from_project: GitLabForkParentSchema.optional(), // Made optional to handle cases where GitLab API doesn't include it
|
|
254
286
|
});
|
|
255
287
|
// Merge Request related schemas (equivalent to Pull Request)
|
|
256
288
|
export const GitLabMergeRequestDiffRefSchema = z.object({
|
|
@@ -431,44 +463,137 @@ export const CreateNoteSchema = z.object({
|
|
|
431
463
|
noteable_iid: z.number().describe("IID of the issue or merge request"),
|
|
432
464
|
body: z.string().describe("Note content"),
|
|
433
465
|
});
|
|
434
|
-
//
|
|
466
|
+
// Issues API operation schemas
|
|
467
|
+
export const ListIssuesSchema = z.object({
|
|
468
|
+
project_id: z.string().describe("Project ID or URL-encoded path"),
|
|
469
|
+
assignee_id: z.number().optional().describe("Return issues assigned to the given user ID"),
|
|
470
|
+
assignee_username: z.string().optional().describe("Return issues assigned to the given username"),
|
|
471
|
+
author_id: z.number().optional().describe("Return issues created by the given user ID"),
|
|
472
|
+
author_username: z.string().optional().describe("Return issues created by the given username"),
|
|
473
|
+
confidential: z.boolean().optional().describe("Filter confidential or public issues"),
|
|
474
|
+
created_after: z.string().optional().describe("Return issues created after the given time"),
|
|
475
|
+
created_before: z.string().optional().describe("Return issues created before the given time"),
|
|
476
|
+
due_date: z.string().optional().describe("Return issues that have the due date"),
|
|
477
|
+
label_name: z.array(z.string()).optional().describe("Array of label names"),
|
|
478
|
+
milestone: z.string().optional().describe("Milestone title"),
|
|
479
|
+
scope: z.enum(['created-by-me', 'assigned-to-me', 'all']).optional().describe("Return issues from a specific scope"),
|
|
480
|
+
search: z.string().optional().describe("Search for specific terms"),
|
|
481
|
+
state: z.enum(['opened', 'closed', 'all']).optional().describe("Return issues with a specific state"),
|
|
482
|
+
updated_after: z.string().optional().describe("Return issues updated after the given time"),
|
|
483
|
+
updated_before: z.string().optional().describe("Return issues updated before the given time"),
|
|
484
|
+
with_labels_details: z.boolean().optional().describe("Return more details for each label"),
|
|
485
|
+
page: z.number().optional().describe("Page number for pagination"),
|
|
486
|
+
per_page: z.number().optional().describe("Number of items per page"),
|
|
487
|
+
});
|
|
488
|
+
export const GetIssueSchema = z.object({
|
|
489
|
+
project_id: z.string().describe("Project ID or URL-encoded path"),
|
|
490
|
+
issue_iid: z.number().describe("The internal ID of the project issue"),
|
|
491
|
+
});
|
|
492
|
+
export const UpdateIssueSchema = z.object({
|
|
493
|
+
project_id: z.string().describe("Project ID or URL-encoded path"),
|
|
494
|
+
issue_iid: z.number().describe("The internal ID of the project issue"),
|
|
495
|
+
title: z.string().optional().describe("The title of the issue"),
|
|
496
|
+
description: z.string().optional().describe("The description of the issue"),
|
|
497
|
+
assignee_ids: z.array(z.number()).optional().describe("Array of user IDs to assign issue to"),
|
|
498
|
+
confidential: z.boolean().optional().describe("Set the issue to be confidential"),
|
|
499
|
+
discussion_locked: z.boolean().optional().describe("Flag to lock discussions"),
|
|
500
|
+
due_date: z.string().optional().describe("Date the issue is due (YYYY-MM-DD)"),
|
|
501
|
+
labels: z.array(z.string()).optional().describe("Array of label names"),
|
|
502
|
+
milestone_id: z.number().optional().describe("Milestone ID to assign"),
|
|
503
|
+
state_event: z.enum(['close', 'reopen']).optional().describe("Update issue state (close/reopen)"),
|
|
504
|
+
weight: z.number().optional().describe("Weight of the issue (0-9)"),
|
|
505
|
+
});
|
|
506
|
+
export const DeleteIssueSchema = z.object({
|
|
507
|
+
project_id: z.string().describe("Project ID or URL-encoded path"),
|
|
508
|
+
issue_iid: z.number().describe("The internal ID of the project issue"),
|
|
509
|
+
});
|
|
510
|
+
// Issue links related schemas
|
|
511
|
+
export const GitLabIssueLinkSchema = z.object({
|
|
512
|
+
source_issue: GitLabIssueSchema,
|
|
513
|
+
target_issue: GitLabIssueSchema,
|
|
514
|
+
link_type: z.enum(['relates_to', 'blocks', 'is_blocked_by']),
|
|
515
|
+
});
|
|
516
|
+
export const ListIssueLinksSchema = z.object({
|
|
517
|
+
project_id: z.string().describe("Project ID or URL-encoded path"),
|
|
518
|
+
issue_iid: z.number().describe("The internal ID of a project's issue"),
|
|
519
|
+
});
|
|
520
|
+
export const GetIssueLinkSchema = z.object({
|
|
521
|
+
project_id: z.string().describe("Project ID or URL-encoded path"),
|
|
522
|
+
issue_iid: z.number().describe("The internal ID of a project's issue"),
|
|
523
|
+
issue_link_id: z.number().describe("ID of an issue relationship"),
|
|
524
|
+
});
|
|
525
|
+
export const CreateIssueLinkSchema = z.object({
|
|
526
|
+
project_id: z.string().describe("Project ID or URL-encoded path"),
|
|
527
|
+
issue_iid: z.number().describe("The internal ID of a project's issue"),
|
|
528
|
+
target_project_id: z.string().describe("The ID or URL-encoded path of a target project"),
|
|
529
|
+
target_issue_iid: z.number().describe("The internal ID of a target project's issue"),
|
|
530
|
+
link_type: z.enum(['relates_to', 'blocks', 'is_blocked_by']).optional().describe("The type of the relation, defaults to relates_to"),
|
|
531
|
+
});
|
|
532
|
+
export const DeleteIssueLinkSchema = z.object({
|
|
533
|
+
project_id: z.string().describe("Project ID or URL-encoded path"),
|
|
534
|
+
issue_iid: z.number().describe("The internal ID of a project's issue"),
|
|
535
|
+
issue_link_id: z.number().describe("The ID of an issue relationship"),
|
|
536
|
+
});
|
|
537
|
+
// Namespace API operation schemas
|
|
435
538
|
export const ListNamespacesSchema = z.object({
|
|
436
|
-
search: z.string().optional().describe("
|
|
437
|
-
|
|
438
|
-
|
|
539
|
+
search: z.string().optional().describe("Search term for namespaces"),
|
|
540
|
+
page: z.number().optional().describe("Page number for pagination"),
|
|
541
|
+
per_page: z.number().optional().describe("Number of items per page"),
|
|
542
|
+
owned: z.boolean().optional().describe("Filter for namespaces owned by current user"),
|
|
439
543
|
});
|
|
440
544
|
export const GetNamespaceSchema = z.object({
|
|
441
|
-
|
|
545
|
+
namespace_id: z.string().describe("Namespace ID or full path"),
|
|
442
546
|
});
|
|
443
547
|
export const VerifyNamespaceSchema = z.object({
|
|
444
|
-
|
|
445
|
-
parent_id: z.number().optional().describe("ID of the parent namespace. If unspecified, only returns top-level namespaces"),
|
|
548
|
+
path: z.string().describe("Namespace path to verify"),
|
|
446
549
|
});
|
|
447
550
|
// Project API operation schemas
|
|
448
551
|
export const GetProjectSchema = z.object({
|
|
449
|
-
|
|
450
|
-
license: z.boolean().optional().describe("Include project license data"),
|
|
451
|
-
statistics: z.boolean().optional().describe("Include project statistics"),
|
|
452
|
-
with_custom_attributes: z.boolean().optional().describe("Include custom attributes in response"),
|
|
552
|
+
project_id: z.string().describe("Project ID or URL-encoded path"),
|
|
453
553
|
});
|
|
454
554
|
export const ListProjectsSchema = z.object({
|
|
455
|
-
|
|
456
|
-
id_after: z.number().optional().describe("Limit results to projects with IDs greater than the specified ID"),
|
|
457
|
-
id_before: z.number().optional().describe("Limit results to projects with IDs less than the specified ID"),
|
|
458
|
-
membership: z.boolean().optional().describe("Limit by projects that the current user is a member of"),
|
|
459
|
-
min_access_level: z.number().optional().describe("Limit by minimum access level"),
|
|
460
|
-
order_by: z.enum(['id', 'name', 'path', 'created_at', 'updated_at', 'last_activity_at']).optional().describe("Return projects ordered by field"),
|
|
461
|
-
owned: z.boolean().optional().describe("Limit by projects explicitly owned by the current user"),
|
|
462
|
-
search: z.string().optional().describe("Return list of projects matching the search criteria"),
|
|
463
|
-
simple: z.boolean().optional().describe("Return only limited fields for each project"),
|
|
464
|
-
sort: z.enum(['asc', 'desc']).optional().describe("Return projects sorted in ascending or descending order"),
|
|
465
|
-
starred: z.boolean().optional().describe("Limit by projects starred by the current user"),
|
|
466
|
-
visibility: z.enum(['public', 'internal', 'private']).optional().describe("Limit by visibility"),
|
|
467
|
-
with_custom_attributes: z.boolean().optional().describe("Include custom attributes in response"),
|
|
468
|
-
with_issues_enabled: z.boolean().optional().describe("Limit by enabled issues feature"),
|
|
469
|
-
with_merge_requests_enabled: z.boolean().optional().describe("Limit by enabled merge requests feature"),
|
|
470
|
-
with_programming_language: z.string().optional().describe("Limit by projects which use the given programming language"),
|
|
471
|
-
with_shared: z.boolean().optional().describe("Include projects shared to this group"),
|
|
555
|
+
search: z.string().optional().describe("Search term for projects"),
|
|
472
556
|
page: z.number().optional().describe("Page number for pagination"),
|
|
473
557
|
per_page: z.number().optional().describe("Number of items per page"),
|
|
558
|
+
owned: z.boolean().optional().describe("Filter for projects owned by current user"),
|
|
559
|
+
membership: z.boolean().optional().describe("Filter for projects where current user is a member"),
|
|
560
|
+
simple: z.boolean().optional().describe("Return only limited fields"),
|
|
561
|
+
archived: z.boolean().optional().describe("Filter for archived projects"),
|
|
562
|
+
visibility: z.enum(["public", "internal", "private"]).optional().describe("Filter by project visibility"),
|
|
563
|
+
order_by: z.enum(["id", "name", "path", "created_at", "updated_at", "last_activity_at"]).optional().describe("Return projects ordered by field"),
|
|
564
|
+
sort: z.enum(["asc", "desc"]).optional().describe("Return projects sorted in ascending or descending order"),
|
|
565
|
+
with_issues_enabled: z.boolean().optional().describe("Filter projects with issues feature enabled"),
|
|
566
|
+
with_merge_requests_enabled: z.boolean().optional().describe("Filter projects with merge requests feature enabled"),
|
|
567
|
+
min_access_level: z.number().optional().describe("Filter by minimum access level"),
|
|
568
|
+
});
|
|
569
|
+
// Label operation schemas
|
|
570
|
+
export const ListLabelsSchema = z.object({
|
|
571
|
+
project_id: z.string().describe("Project ID or URL-encoded path"),
|
|
572
|
+
with_counts: z.boolean().optional().describe("Whether or not to include issue and merge request counts"),
|
|
573
|
+
include_ancestor_groups: z.boolean().optional().describe("Include ancestor groups"),
|
|
574
|
+
search: z.string().optional().describe("Keyword to filter labels by"),
|
|
575
|
+
});
|
|
576
|
+
export const GetLabelSchema = z.object({
|
|
577
|
+
project_id: z.string().describe("Project ID or URL-encoded path"),
|
|
578
|
+
label_id: z.union([z.number(), z.string()]).describe("The ID or title of a project's label"),
|
|
579
|
+
include_ancestor_groups: z.boolean().optional().describe("Include ancestor groups"),
|
|
580
|
+
});
|
|
581
|
+
export const CreateLabelSchema = z.object({
|
|
582
|
+
project_id: z.string().describe("Project ID or URL-encoded path"),
|
|
583
|
+
name: z.string().describe("The name of the label"),
|
|
584
|
+
color: z.string().describe("The color of the label given in 6-digit hex notation with leading '#' sign"),
|
|
585
|
+
description: z.string().optional().describe("The description of the label"),
|
|
586
|
+
priority: z.number().nullable().optional().describe("The priority of the label"),
|
|
587
|
+
});
|
|
588
|
+
export const UpdateLabelSchema = z.object({
|
|
589
|
+
project_id: z.string().describe("Project ID or URL-encoded path"),
|
|
590
|
+
label_id: z.union([z.number(), z.string()]).describe("The ID or title of a project's label"),
|
|
591
|
+
new_name: z.string().optional().describe("The new name of the label"),
|
|
592
|
+
color: z.string().optional().describe("The color of the label given in 6-digit hex notation with leading '#' sign"),
|
|
593
|
+
description: z.string().optional().describe("The new description of the label"),
|
|
594
|
+
priority: z.number().nullable().optional().describe("The new priority of the label"),
|
|
595
|
+
});
|
|
596
|
+
export const DeleteLabelSchema = z.object({
|
|
597
|
+
project_id: z.string().describe("Project ID or URL-encoded path"),
|
|
598
|
+
label_id: z.union([z.number(), z.string()]).describe("The ID or title of a project's label"),
|
|
474
599
|
});
|