@zereight/mcp-gitlab 1.0.16 â 1.0.18
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 +30 -133
- package/build/index.js +487 -1
- package/build/schemas.js +210 -16
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -40,139 +40,36 @@ env GITLAB_PERSONAL_ACCESS_TOKEN=your_gitlab_token GITLAB_API_URL=your_gitlab_ap
|
|
|
40
40
|
- `GITLAB_PERSONAL_ACCESS_TOKEN`: Your GitLab personal access token.
|
|
41
41
|
- `GITLAB_API_URL`: Your GitLab API URL. (Default: `https://gitlab.com/api/v4`)
|
|
42
42
|
|
|
43
|
-
## Tools đ ī¸
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
- `per_page` (optional number): Results per page (default: 20, max: 100)
|
|
74
|
-
- Returns: Project search results
|
|
75
|
-
|
|
76
|
-
4. `create_repository`
|
|
77
|
-
|
|
78
|
-
- Create a new GitLab project. â
|
|
79
|
-
- Inputs:
|
|
80
|
-
- `name` (string): Project name
|
|
81
|
-
- `description` (optional string): Project description
|
|
82
|
-
- `visibility` (optional string): Project visibility level (public, private, internal)
|
|
83
|
-
- `initialize_with_readme` (optional boolean): Initialize with README
|
|
84
|
-
- Returns: Details of the created project
|
|
85
|
-
|
|
86
|
-
5. `get_file_contents`
|
|
87
|
-
|
|
88
|
-
- Get the contents of a file or directory. đ
|
|
89
|
-
- Inputs:
|
|
90
|
-
- `project_id` (string): Project ID or namespace/project_path
|
|
91
|
-
- `file_path` (string): Path to the file/directory
|
|
92
|
-
- `ref` (optional string): Branch, tag, or commit SHA (default: default branch)
|
|
93
|
-
- Returns: File/directory content
|
|
94
|
-
|
|
95
|
-
6. `create_issue`
|
|
96
|
-
|
|
97
|
-
- Create a new issue. đ
|
|
98
|
-
- Inputs:
|
|
99
|
-
- `project_id` (string): Project ID or namespace/project_path
|
|
100
|
-
- `title` (string): Issue title
|
|
101
|
-
- `description` (string): Issue description
|
|
102
|
-
- `assignee_ids` (optional number[]): Array of assignee IDs
|
|
103
|
-
- `milestone_id` (optional number): Milestone ID
|
|
104
|
-
- `labels` (optional string[]): Array of labels
|
|
105
|
-
- Returns: Details of the created issue
|
|
106
|
-
|
|
107
|
-
7. `create_merge_request`
|
|
108
|
-
|
|
109
|
-
- Create a new merge request. đ
|
|
110
|
-
- Inputs:
|
|
111
|
-
- `project_id` (string): Project ID or namespace/project_path
|
|
112
|
-
- `title` (string): Merge request title
|
|
113
|
-
- `description` (string): Merge request description
|
|
114
|
-
- `source_branch` (string): Branch with changes
|
|
115
|
-
- `target_branch` (string): Branch to merge into
|
|
116
|
-
- `allow_collaboration` (optional boolean): Allow collaborators to push commits to the source branch
|
|
117
|
-
- `draft` (optional boolean): Create as a draft merge request
|
|
118
|
-
- Returns: Details of the created merge request
|
|
119
|
-
|
|
120
|
-
8. `fork_repository`
|
|
121
|
-
|
|
122
|
-
- Fork a project. đ´
|
|
123
|
-
- Inputs:
|
|
124
|
-
- `project_id` (string): Project ID or namespace/project_path to fork
|
|
125
|
-
- `namespace` (optional string): Namespace to fork into (default: user namespace)
|
|
126
|
-
- Returns: Details of the forked project
|
|
127
|
-
|
|
128
|
-
9. `create_branch`
|
|
129
|
-
|
|
130
|
-
- Create a new branch. đŋ
|
|
131
|
-
- Inputs:
|
|
132
|
-
- `project_id` (string): Project ID or namespace/project_path
|
|
133
|
-
- `name` (string): New branch name
|
|
134
|
-
- `ref` (optional string): Ref to create the branch from (branch, tag, commit SHA, default: default branch)
|
|
135
|
-
- Returns: Created branch reference
|
|
136
|
-
|
|
137
|
-
10. `get_merge_request`
|
|
138
|
-
|
|
139
|
-
- Get details of a merge request. âšī¸
|
|
140
|
-
- Inputs:
|
|
141
|
-
- `project_id` (string): Project ID or namespace/project_path
|
|
142
|
-
- `merge_request_iid` (number): Merge request IID
|
|
143
|
-
- Returns: Merge request details
|
|
144
|
-
|
|
145
|
-
11. `get_merge_request_diffs`
|
|
146
|
-
|
|
147
|
-
- Get changes (diffs) of a merge request. diff
|
|
148
|
-
- Inputs:
|
|
149
|
-
- `project_id` (string): Project ID or namespace/project_path
|
|
150
|
-
- `merge_request_iid` (number): Merge request IID
|
|
151
|
-
- `view` (optional string): Diff view type ('inline' or 'parallel')
|
|
152
|
-
- Returns: Array of merge request diff information
|
|
153
|
-
|
|
154
|
-
12. `update_merge_request`
|
|
155
|
-
|
|
156
|
-
- Update a merge request. đ
|
|
157
|
-
- Inputs:
|
|
158
|
-
- `project_id` (string): Project ID or namespace/project_path
|
|
159
|
-
- `merge_request_iid` (number): Merge request IID
|
|
160
|
-
- `title` (optional string): New title
|
|
161
|
-
- `description` (string): New description
|
|
162
|
-
- `target_branch` (optional string): New target branch
|
|
163
|
-
- `state_event` (optional string): Merge request state change event ('close', 'reopen')
|
|
164
|
-
- `remove_source_branch` (optional boolean): Remove source branch after merge
|
|
165
|
-
- `allow_collaboration` (optional boolean): Allow collaborators to push commits to the source branch
|
|
166
|
-
- Returns: Updated merge request details
|
|
167
|
-
|
|
168
|
-
13. `create_note`
|
|
169
|
-
- Create a new note (comment) to an issue or merge request. đŦ
|
|
170
|
-
- Inputs:
|
|
171
|
-
- `project_id` (string): Project ID or namespace/project_path
|
|
172
|
-
- `noteable_type` (string): Type of noteable ("issue" or "merge_request")
|
|
173
|
-
- `noteable_iid` (number): IID of the issue or merge request
|
|
174
|
-
- `body` (string): Note content
|
|
175
|
-
- Returns: Details of the created note
|
|
43
|
+
## Tools Reference đ ī¸
|
|
44
|
+
|
|
45
|
+
| Tool | Description | Parameters | Returns |
|
|
46
|
+
|------|-------------|------------|---------|
|
|
47
|
+
| **`create_or_update_file`** | Create or update a single file in a GitLab project đ | âĸ `project_id` (string): Project ID or path<br>âĸ `file_path` (string): Path to create/update<br>âĸ `content` (string): File content<br>âĸ `commit_message` (string): Commit message<br>âĸ `branch` (string): Target branch<br>âĸ `previous_path` (optional): Previous path when renaming | File content and commit details |
|
|
48
|
+
| **`push_files`** | Push multiple files in a single commit đ¤ (internally creates a tree and commit) | âĸ `project_id` (string): Project ID or path<br>âĸ `branch` (string): Target branch<br>âĸ `files` (array): Array of files with `file_path` and `content`<br>âĸ `commit_message` (string): Commit message | Updated branch reference |
|
|
49
|
+
| **`search_repositories`** | Search for GitLab projects đ | âĸ `search` (string): Search query<br>âĸ `page` (optional): Page number (default: 1)<br>âĸ `per_page` (optional): Results per page (default: 20) | Project search results |
|
|
50
|
+
| **`create_repository`** | Create a new GitLab project â | âĸ `name` (string): Project name<br>âĸ `description` (optional): Project description<br>âĸ `visibility` (optional): Visibility level<br>âĸ `initialize_with_readme` (optional): Initialize with README | Created project details |
|
|
51
|
+
| **`get_file_contents`** | Get the contents of a file or directory đ | âĸ `project_id` (string): Project ID or path<br>âĸ `file_path` (string): Path to file/directory<br>âĸ `ref` (optional): Branch, tag, or commit SHA | File/directory content |
|
|
52
|
+
| **`create_issue`** | Create a new issue đ | âĸ `project_id` (string): Project ID or path<br>âĸ `title` (string): Issue title<br>âĸ `description` (string): Issue description<br>âĸ `assignee_ids` (optional): Array of assignee IDs<br>âĸ `milestone_id` (optional): Milestone ID<br>âĸ `labels` (optional): Array of labels | Created issue details |
|
|
53
|
+
| **`list_issues`** | List issues in a project with comprehensive filtering options đ | âĸ `project_id` (string): Project ID or path<br>âĸ Optional filters: `assignee_id`, `assignee_username`, `author_id`, `author_username`, `confidential`, `created_after/before`, `due_date`, `label_name`, `milestone`, `scope`, `search`, `state`, `updated_after/before`<br>âĸ Pagination: `page`, `per_page` | Array of issues |
|
|
54
|
+
| **`get_issue`** | Get details of a specific issue | âĸ `project_id` (string): Project ID or path<br>âĸ `issue_iid` (number): Issue IID | Issue details |
|
|
55
|
+
| **`update_issue`** | Update an existing issue âī¸ | âĸ `project_id` (string): Project ID or path<br>âĸ `issue_iid` (number): Issue IID<br>âĸ Editable fields: `title`, `description`, `assignee_ids`, `labels`, `milestone_id`, `state_event` (close/reopen), `confidential`, `discussion_locked`, `due_date`, `weight` | Updated issue details |
|
|
56
|
+
| **`delete_issue`** | Delete an issue | âĸ `project_id` (string): Project ID or path<br>âĸ `issue_iid` (number): Issue IID | Success message |
|
|
57
|
+
| **`list_issue_links`** | List all links for a specific issue | âĸ `project_id` (string): Project ID or path<br>âĸ `issue_iid` (number): Issue IID | Array of linked issues |
|
|
58
|
+
| **`get_issue_link`** | Get details of a specific issue link | âĸ `project_id` (string): Project ID or path<br>âĸ `issue_iid` (number): Issue IID<br>âĸ `issue_link_id` (number): Link ID | Issue link details |
|
|
59
|
+
| **`create_issue_link`** | Create a link between two issues | âĸ `project_id` (string): Project ID or path<br>âĸ `issue_iid` (number): Source issue IID<br>âĸ `target_project_id` (string): Target project ID<br>âĸ `target_issue_iid` (number): Target issue IID<br>âĸ `link_type` (optional): Relationship type | Created link details |
|
|
60
|
+
| **`delete_issue_link`** | Delete an issue link | âĸ `project_id` (string): Project ID or path<br>âĸ `issue_iid` (number): Issue IID<br>âĸ `issue_link_id` (number): Link ID | Success message |
|
|
61
|
+
| **`create_merge_request`** | Create a new merge request đ | âĸ `project_id` (string): Project ID or path<br>âĸ `title` (string): MR title<br>âĸ `description` (string): MR description<br>âĸ `source_branch` (string): Branch with changes<br>âĸ `target_branch` (string): Branch to merge into<br>âĸ `allow_collaboration` (optional): Allow collaborators<br>âĸ `draft` (optional): Create as draft | Created merge request details |
|
|
62
|
+
| **`fork_repository`** | Fork a project đ´ | âĸ `project_id` (string): Project ID or path to fork<br>âĸ `namespace` (optional): Namespace to fork into | Forked project details |
|
|
63
|
+
| **`create_branch`** | Create a new branch đŋ | âĸ `project_id` (string): Project ID or path<br>âĸ `branch` (string): New branch name<br>âĸ `ref` (optional): Reference to create from | Created branch reference |
|
|
64
|
+
| **`get_merge_request`** | Get details of a merge request âšī¸ | âĸ `project_id` (string): Project ID or path<br>âĸ `merge_request_iid` (number): MR IID | Merge request details |
|
|
65
|
+
| **`get_merge_request_diffs`** | Get changes of a merge request | âĸ `project_id` (string): Project ID or path<br>âĸ `merge_request_iid` (number): MR IID<br>âĸ `view` (optional): Diff view type | Array of merge request diffs |
|
|
66
|
+
| **`update_merge_request`** | Update a merge request đ | âĸ `project_id` (string): Project ID or path<br>âĸ `merge_request_iid` (number): MR IID<br>âĸ Editable fields: `title`, `description`, `target_branch`, `assignee_ids`, `labels`, `state_event` (close/reopen), `remove_source_branch`, `squash`, `draft` | Updated merge request details |
|
|
67
|
+
| **`create_note`** | Create a comment on an issue or MR đŦ | âĸ `project_id` (string): Project ID or path<br>âĸ `noteable_type` (string): "issue" or "merge_request"<br>âĸ `noteable_iid` (number): IID of the issue or MR<br>âĸ `body` (string): Comment content | Created note details |
|
|
68
|
+
| **`list_namespaces`** | List available namespaces | âĸ `search` (optional): Search term<br>âĸ `page` (optional): Page number<br>âĸ `per_page` (optional): Results per page<br>âĸ `owned` (optional): Filter by ownership | Array of namespaces |
|
|
69
|
+
| **`get_namespace`** | Get details of a namespace | âĸ `namespace_id` (string): Namespace ID or path | Namespace details |
|
|
70
|
+
| **`verify_namespace`** | Check if a namespace exists | âĸ `path` (string): Namespace path to verify | Verification result |
|
|
71
|
+
| **`get_project`** | Get details of a specific project | âĸ `project_id` (string): Project ID or path | Project details |
|
|
72
|
+
| **`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 |
|
|
176
73
|
|
|
177
74
|
## Environment Variable Configuration
|
|
178
75
|
|
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, CreateOrUpdateFileSchema, SearchRepositoriesSchema, CreateRepositorySchema, GetFileContentsSchema, PushFilesSchema, CreateIssueSchema, CreateMergeRequestSchema, ForkRepositorySchema, CreateBranchSchema, GitLabMergeRequestDiffSchema, GetMergeRequestSchema, GetMergeRequestDiffsSchema, UpdateMergeRequestSchema, 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, 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
|
* ëŗíŠ ėė˛ ėėą
|
|
@@ -560,6 +725,121 @@ noteableIid, body) {
|
|
|
560
725
|
}
|
|
561
726
|
return await response.json();
|
|
562
727
|
}
|
|
728
|
+
/**
|
|
729
|
+
* List all namespaces
|
|
730
|
+
* ėŦėŠ ę°ëĨí ëǍë ë¤ėė¤íė´ė¤ ëĒŠëĄ ėĄ°í
|
|
731
|
+
*
|
|
732
|
+
* @param {Object} options - Options for listing namespaces
|
|
733
|
+
* @param {string} [options.search] - Search query to filter namespaces
|
|
734
|
+
* @param {boolean} [options.owned_only] - Only return namespaces owned by the authenticated user
|
|
735
|
+
* @param {boolean} [options.top_level_only] - Only return top-level namespaces
|
|
736
|
+
* @returns {Promise<GitLabNamespace[]>} List of namespaces
|
|
737
|
+
*/
|
|
738
|
+
async function listNamespaces(options) {
|
|
739
|
+
const url = new URL(`${GITLAB_API_URL}/namespaces`);
|
|
740
|
+
if (options.search) {
|
|
741
|
+
url.searchParams.append("search", options.search);
|
|
742
|
+
}
|
|
743
|
+
if (options.owned_only) {
|
|
744
|
+
url.searchParams.append("owned_only", "true");
|
|
745
|
+
}
|
|
746
|
+
if (options.top_level_only) {
|
|
747
|
+
url.searchParams.append("top_level_only", "true");
|
|
748
|
+
}
|
|
749
|
+
const response = await fetch(url.toString(), {
|
|
750
|
+
headers: DEFAULT_HEADERS,
|
|
751
|
+
});
|
|
752
|
+
await handleGitLabError(response);
|
|
753
|
+
const data = await response.json();
|
|
754
|
+
return z.array(GitLabNamespaceSchema).parse(data);
|
|
755
|
+
}
|
|
756
|
+
/**
|
|
757
|
+
* Get details on a namespace
|
|
758
|
+
* ë¤ėė¤íė´ė¤ ėė¸ ė ëŗ´ ėĄ°í
|
|
759
|
+
*
|
|
760
|
+
* @param {string} id - The ID or URL-encoded path of the namespace
|
|
761
|
+
* @returns {Promise<GitLabNamespace>} The namespace details
|
|
762
|
+
*/
|
|
763
|
+
async function getNamespace(id) {
|
|
764
|
+
const url = new URL(`${GITLAB_API_URL}/namespaces/${encodeURIComponent(id)}`);
|
|
765
|
+
const response = await fetch(url.toString(), {
|
|
766
|
+
headers: DEFAULT_HEADERS,
|
|
767
|
+
});
|
|
768
|
+
await handleGitLabError(response);
|
|
769
|
+
const data = await response.json();
|
|
770
|
+
return GitLabNamespaceSchema.parse(data);
|
|
771
|
+
}
|
|
772
|
+
/**
|
|
773
|
+
* Verify if a namespace exists
|
|
774
|
+
* ë¤ėė¤íė´ė¤ ėĄ´ėŦ ėŦëļ íė¸
|
|
775
|
+
*
|
|
776
|
+
* @param {string} namespacePath - The path of the namespace to check
|
|
777
|
+
* @param {number} [parentId] - The ID of the parent namespace
|
|
778
|
+
* @returns {Promise<GitLabNamespaceExistsResponse>} The verification result
|
|
779
|
+
*/
|
|
780
|
+
async function verifyNamespaceExistence(namespacePath, parentId) {
|
|
781
|
+
const url = new URL(`${GITLAB_API_URL}/namespaces/${encodeURIComponent(namespacePath)}/exists`);
|
|
782
|
+
if (parentId) {
|
|
783
|
+
url.searchParams.append("parent_id", parentId.toString());
|
|
784
|
+
}
|
|
785
|
+
const response = await fetch(url.toString(), {
|
|
786
|
+
headers: DEFAULT_HEADERS,
|
|
787
|
+
});
|
|
788
|
+
await handleGitLabError(response);
|
|
789
|
+
const data = await response.json();
|
|
790
|
+
return GitLabNamespaceExistsResponseSchema.parse(data);
|
|
791
|
+
}
|
|
792
|
+
/**
|
|
793
|
+
* Get a single project
|
|
794
|
+
* ë¨ėŧ íëĄė í¸ ėĄ°í
|
|
795
|
+
*
|
|
796
|
+
* @param {string} projectId - The ID or URL-encoded path of the project
|
|
797
|
+
* @param {Object} options - Options for getting project details
|
|
798
|
+
* @param {boolean} [options.license] - Include project license data
|
|
799
|
+
* @param {boolean} [options.statistics] - Include project statistics
|
|
800
|
+
* @param {boolean} [options.with_custom_attributes] - Include custom attributes in response
|
|
801
|
+
* @returns {Promise<GitLabProject>} Project details
|
|
802
|
+
*/
|
|
803
|
+
async function getProject(projectId, options = {}) {
|
|
804
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}`);
|
|
805
|
+
if (options.license) {
|
|
806
|
+
url.searchParams.append("license", "true");
|
|
807
|
+
}
|
|
808
|
+
if (options.statistics) {
|
|
809
|
+
url.searchParams.append("statistics", "true");
|
|
810
|
+
}
|
|
811
|
+
if (options.with_custom_attributes) {
|
|
812
|
+
url.searchParams.append("with_custom_attributes", "true");
|
|
813
|
+
}
|
|
814
|
+
const response = await fetch(url.toString(), {
|
|
815
|
+
headers: DEFAULT_HEADERS,
|
|
816
|
+
});
|
|
817
|
+
await handleGitLabError(response);
|
|
818
|
+
const data = await response.json();
|
|
819
|
+
return GitLabRepositorySchema.parse(data);
|
|
820
|
+
}
|
|
821
|
+
/**
|
|
822
|
+
* List projects
|
|
823
|
+
* íëĄė í¸ ëĒŠëĄ ėĄ°í
|
|
824
|
+
*
|
|
825
|
+
* @param {Object} options - Options for listing projects
|
|
826
|
+
* @returns {Promise<GitLabProject[]>} List of projects
|
|
827
|
+
*/
|
|
828
|
+
async function listProjects(options = {}) {
|
|
829
|
+
const url = new URL(`${GITLAB_API_URL}/projects`);
|
|
830
|
+
// Add all the query parameters from options
|
|
831
|
+
Object.entries(options).forEach(([key, value]) => {
|
|
832
|
+
if (value !== undefined) {
|
|
833
|
+
url.searchParams.append(key, value.toString());
|
|
834
|
+
}
|
|
835
|
+
});
|
|
836
|
+
const response = await fetch(url.toString(), {
|
|
837
|
+
headers: DEFAULT_HEADERS,
|
|
838
|
+
});
|
|
839
|
+
await handleGitLabError(response);
|
|
840
|
+
const data = await response.json();
|
|
841
|
+
return z.array(GitLabRepositorySchema).parse(data);
|
|
842
|
+
}
|
|
563
843
|
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
564
844
|
return {
|
|
565
845
|
tools: [
|
|
@@ -628,6 +908,71 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
628
908
|
description: "Create a new note (comment) to an issue or merge request",
|
|
629
909
|
inputSchema: zodToJsonSchema(CreateNoteSchema),
|
|
630
910
|
},
|
|
911
|
+
{
|
|
912
|
+
name: "list_issues",
|
|
913
|
+
description: "List issues in a GitLab project with filtering options",
|
|
914
|
+
inputSchema: zodToJsonSchema(ListIssuesSchema),
|
|
915
|
+
},
|
|
916
|
+
{
|
|
917
|
+
name: "get_issue",
|
|
918
|
+
description: "Get details of a specific issue in a GitLab project",
|
|
919
|
+
inputSchema: zodToJsonSchema(GetIssueSchema),
|
|
920
|
+
},
|
|
921
|
+
{
|
|
922
|
+
name: "update_issue",
|
|
923
|
+
description: "Update an issue in a GitLab project",
|
|
924
|
+
inputSchema: zodToJsonSchema(UpdateIssueSchema),
|
|
925
|
+
},
|
|
926
|
+
{
|
|
927
|
+
name: "delete_issue",
|
|
928
|
+
description: "Delete an issue from a GitLab project",
|
|
929
|
+
inputSchema: zodToJsonSchema(DeleteIssueSchema),
|
|
930
|
+
},
|
|
931
|
+
{
|
|
932
|
+
name: "list_issue_links",
|
|
933
|
+
description: "List all issue links for a specific issue",
|
|
934
|
+
inputSchema: zodToJsonSchema(ListIssueLinksSchema),
|
|
935
|
+
},
|
|
936
|
+
{
|
|
937
|
+
name: "get_issue_link",
|
|
938
|
+
description: "Get a specific issue link",
|
|
939
|
+
inputSchema: zodToJsonSchema(GetIssueLinkSchema),
|
|
940
|
+
},
|
|
941
|
+
{
|
|
942
|
+
name: "create_issue_link",
|
|
943
|
+
description: "Create an issue link between two issues",
|
|
944
|
+
inputSchema: zodToJsonSchema(CreateIssueLinkSchema),
|
|
945
|
+
},
|
|
946
|
+
{
|
|
947
|
+
name: "delete_issue_link",
|
|
948
|
+
description: "Delete an issue link",
|
|
949
|
+
inputSchema: zodToJsonSchema(DeleteIssueLinkSchema),
|
|
950
|
+
},
|
|
951
|
+
{
|
|
952
|
+
name: "list_namespaces",
|
|
953
|
+
description: "List all namespaces available to the current user",
|
|
954
|
+
inputSchema: zodToJsonSchema(ListNamespacesSchema),
|
|
955
|
+
},
|
|
956
|
+
{
|
|
957
|
+
name: "get_namespace",
|
|
958
|
+
description: "Get details of a namespace by ID or path",
|
|
959
|
+
inputSchema: zodToJsonSchema(GetNamespaceSchema),
|
|
960
|
+
},
|
|
961
|
+
{
|
|
962
|
+
name: "verify_namespace",
|
|
963
|
+
description: "Verify if a namespace path exists",
|
|
964
|
+
inputSchema: zodToJsonSchema(VerifyNamespaceSchema),
|
|
965
|
+
},
|
|
966
|
+
{
|
|
967
|
+
name: "get_project",
|
|
968
|
+
description: "Get details of a specific project",
|
|
969
|
+
inputSchema: zodToJsonSchema(GetProjectSchema),
|
|
970
|
+
},
|
|
971
|
+
{
|
|
972
|
+
name: "list_projects",
|
|
973
|
+
description: "List projects accessible by the current user",
|
|
974
|
+
inputSchema: zodToJsonSchema(ListProjectsSchema),
|
|
975
|
+
},
|
|
631
976
|
],
|
|
632
977
|
};
|
|
633
978
|
});
|
|
@@ -751,6 +1096,89 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
751
1096
|
],
|
|
752
1097
|
};
|
|
753
1098
|
}
|
|
1099
|
+
case "list_namespaces": {
|
|
1100
|
+
const args = ListNamespacesSchema.parse(request.params.arguments);
|
|
1101
|
+
const url = new URL(`${GITLAB_API_URL}/namespaces`);
|
|
1102
|
+
if (args.search) {
|
|
1103
|
+
url.searchParams.append("search", args.search);
|
|
1104
|
+
}
|
|
1105
|
+
if (args.page) {
|
|
1106
|
+
url.searchParams.append("page", args.page.toString());
|
|
1107
|
+
}
|
|
1108
|
+
if (args.per_page) {
|
|
1109
|
+
url.searchParams.append("per_page", args.per_page.toString());
|
|
1110
|
+
}
|
|
1111
|
+
if (args.owned) {
|
|
1112
|
+
url.searchParams.append("owned", args.owned.toString());
|
|
1113
|
+
}
|
|
1114
|
+
const response = await fetch(url.toString(), {
|
|
1115
|
+
headers: DEFAULT_HEADERS,
|
|
1116
|
+
});
|
|
1117
|
+
await handleGitLabError(response);
|
|
1118
|
+
const data = await response.json();
|
|
1119
|
+
const namespaces = z.array(GitLabNamespaceSchema).parse(data);
|
|
1120
|
+
return {
|
|
1121
|
+
content: [{ type: "text", text: JSON.stringify(namespaces, null, 2) }],
|
|
1122
|
+
};
|
|
1123
|
+
}
|
|
1124
|
+
case "get_namespace": {
|
|
1125
|
+
const args = GetNamespaceSchema.parse(request.params.arguments);
|
|
1126
|
+
const url = new URL(`${GITLAB_API_URL}/namespaces/${encodeURIComponent(args.namespace_id)}`);
|
|
1127
|
+
const response = await fetch(url.toString(), {
|
|
1128
|
+
headers: DEFAULT_HEADERS,
|
|
1129
|
+
});
|
|
1130
|
+
await handleGitLabError(response);
|
|
1131
|
+
const data = await response.json();
|
|
1132
|
+
const namespace = GitLabNamespaceSchema.parse(data);
|
|
1133
|
+
return {
|
|
1134
|
+
content: [{ type: "text", text: JSON.stringify(namespace, null, 2) }],
|
|
1135
|
+
};
|
|
1136
|
+
}
|
|
1137
|
+
case "verify_namespace": {
|
|
1138
|
+
const args = VerifyNamespaceSchema.parse(request.params.arguments);
|
|
1139
|
+
const url = new URL(`${GITLAB_API_URL}/namespaces/${encodeURIComponent(args.path)}/exists`);
|
|
1140
|
+
const response = await fetch(url.toString(), {
|
|
1141
|
+
headers: DEFAULT_HEADERS,
|
|
1142
|
+
});
|
|
1143
|
+
await handleGitLabError(response);
|
|
1144
|
+
const data = await response.json();
|
|
1145
|
+
const namespaceExists = GitLabNamespaceExistsResponseSchema.parse(data);
|
|
1146
|
+
return {
|
|
1147
|
+
content: [{ type: "text", text: JSON.stringify(namespaceExists, null, 2) }],
|
|
1148
|
+
};
|
|
1149
|
+
}
|
|
1150
|
+
case "get_project": {
|
|
1151
|
+
const args = GetProjectSchema.parse(request.params.arguments);
|
|
1152
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(args.project_id)}`);
|
|
1153
|
+
const response = await fetch(url.toString(), {
|
|
1154
|
+
headers: DEFAULT_HEADERS,
|
|
1155
|
+
});
|
|
1156
|
+
await handleGitLabError(response);
|
|
1157
|
+
const data = await response.json();
|
|
1158
|
+
const project = GitLabProjectSchema.parse(data);
|
|
1159
|
+
return {
|
|
1160
|
+
content: [{ type: "text", text: JSON.stringify(project, null, 2) }],
|
|
1161
|
+
};
|
|
1162
|
+
}
|
|
1163
|
+
case "list_projects": {
|
|
1164
|
+
const args = ListProjectsSchema.parse(request.params.arguments);
|
|
1165
|
+
const url = new URL(`${GITLAB_API_URL}/projects`);
|
|
1166
|
+
// Add query parameters for filtering
|
|
1167
|
+
Object.entries(args).forEach(([key, value]) => {
|
|
1168
|
+
if (value !== undefined) {
|
|
1169
|
+
url.searchParams.append(key, value.toString());
|
|
1170
|
+
}
|
|
1171
|
+
});
|
|
1172
|
+
const response = await fetch(url.toString(), {
|
|
1173
|
+
headers: DEFAULT_HEADERS,
|
|
1174
|
+
});
|
|
1175
|
+
await handleGitLabError(response);
|
|
1176
|
+
const data = await response.json();
|
|
1177
|
+
const projects = z.array(GitLabProjectSchema).parse(data);
|
|
1178
|
+
return {
|
|
1179
|
+
content: [{ type: "text", text: JSON.stringify(projects, null, 2) }],
|
|
1180
|
+
};
|
|
1181
|
+
}
|
|
754
1182
|
case "create_note": {
|
|
755
1183
|
const args = CreateNoteSchema.parse(request.params.arguments);
|
|
756
1184
|
const { project_id, noteable_type, noteable_iid, body } = args;
|
|
@@ -759,6 +1187,64 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
759
1187
|
content: [{ type: "text", text: JSON.stringify(note, null, 2) }],
|
|
760
1188
|
};
|
|
761
1189
|
}
|
|
1190
|
+
case "list_issues": {
|
|
1191
|
+
const args = ListIssuesSchema.parse(request.params.arguments);
|
|
1192
|
+
const { project_id, ...options } = args;
|
|
1193
|
+
const issues = await listIssues(project_id, options);
|
|
1194
|
+
return {
|
|
1195
|
+
content: [{ type: "text", text: JSON.stringify(issues, null, 2) }],
|
|
1196
|
+
};
|
|
1197
|
+
}
|
|
1198
|
+
case "get_issue": {
|
|
1199
|
+
const args = GetIssueSchema.parse(request.params.arguments);
|
|
1200
|
+
const issue = await getIssue(args.project_id, args.issue_iid);
|
|
1201
|
+
return {
|
|
1202
|
+
content: [{ type: "text", text: JSON.stringify(issue, null, 2) }],
|
|
1203
|
+
};
|
|
1204
|
+
}
|
|
1205
|
+
case "update_issue": {
|
|
1206
|
+
const args = UpdateIssueSchema.parse(request.params.arguments);
|
|
1207
|
+
const { project_id, issue_iid, ...options } = args;
|
|
1208
|
+
const issue = await updateIssue(project_id, issue_iid, options);
|
|
1209
|
+
return {
|
|
1210
|
+
content: [{ type: "text", text: JSON.stringify(issue, null, 2) }],
|
|
1211
|
+
};
|
|
1212
|
+
}
|
|
1213
|
+
case "delete_issue": {
|
|
1214
|
+
const args = DeleteIssueSchema.parse(request.params.arguments);
|
|
1215
|
+
await deleteIssue(args.project_id, args.issue_iid);
|
|
1216
|
+
return {
|
|
1217
|
+
content: [{ type: "text", text: JSON.stringify({ status: "success", message: "Issue deleted successfully" }, null, 2) }],
|
|
1218
|
+
};
|
|
1219
|
+
}
|
|
1220
|
+
case "list_issue_links": {
|
|
1221
|
+
const args = ListIssueLinksSchema.parse(request.params.arguments);
|
|
1222
|
+
const links = await listIssueLinks(args.project_id, args.issue_iid);
|
|
1223
|
+
return {
|
|
1224
|
+
content: [{ type: "text", text: JSON.stringify(links, null, 2) }],
|
|
1225
|
+
};
|
|
1226
|
+
}
|
|
1227
|
+
case "get_issue_link": {
|
|
1228
|
+
const args = GetIssueLinkSchema.parse(request.params.arguments);
|
|
1229
|
+
const link = await getIssueLink(args.project_id, args.issue_iid, args.issue_link_id);
|
|
1230
|
+
return {
|
|
1231
|
+
content: [{ type: "text", text: JSON.stringify(link, null, 2) }],
|
|
1232
|
+
};
|
|
1233
|
+
}
|
|
1234
|
+
case "create_issue_link": {
|
|
1235
|
+
const args = CreateIssueLinkSchema.parse(request.params.arguments);
|
|
1236
|
+
const link = await createIssueLink(args.project_id, args.issue_iid, args.target_project_id, args.target_issue_iid, args.link_type);
|
|
1237
|
+
return {
|
|
1238
|
+
content: [{ type: "text", text: JSON.stringify(link, null, 2) }],
|
|
1239
|
+
};
|
|
1240
|
+
}
|
|
1241
|
+
case "delete_issue_link": {
|
|
1242
|
+
const args = DeleteIssueLinkSchema.parse(request.params.arguments);
|
|
1243
|
+
await deleteIssueLink(args.project_id, args.issue_iid, args.issue_link_id);
|
|
1244
|
+
return {
|
|
1245
|
+
content: [{ type: "text", text: JSON.stringify({ status: "success", message: "Issue link deleted successfully" }, null, 2) }],
|
|
1246
|
+
};
|
|
1247
|
+
}
|
|
762
1248
|
default:
|
|
763
1249
|
throw new Error(`Unknown tool: ${request.params.name}`);
|
|
764
1250
|
}
|
package/build/schemas.js
CHANGED
|
@@ -5,6 +5,31 @@ export const GitLabAuthorSchema = z.object({
|
|
|
5
5
|
email: z.string(),
|
|
6
6
|
date: z.string(),
|
|
7
7
|
});
|
|
8
|
+
// Namespace related schemas
|
|
9
|
+
export const GitLabNamespaceSchema = z.object({
|
|
10
|
+
id: z.number(),
|
|
11
|
+
name: z.string(),
|
|
12
|
+
path: z.string(),
|
|
13
|
+
kind: z.enum(["user", "group"]),
|
|
14
|
+
full_path: z.string(),
|
|
15
|
+
parent_id: z.number().nullable(),
|
|
16
|
+
avatar_url: z.string().nullable(),
|
|
17
|
+
web_url: z.string(),
|
|
18
|
+
members_count_with_descendants: z.number().optional(),
|
|
19
|
+
billable_members_count: z.number().optional(),
|
|
20
|
+
max_seats_used: z.number().optional(),
|
|
21
|
+
seats_in_use: z.number().optional(),
|
|
22
|
+
plan: z.string().optional(),
|
|
23
|
+
end_date: z.string().nullable().optional(),
|
|
24
|
+
trial_ends_on: z.string().nullable().optional(),
|
|
25
|
+
trial: z.boolean().optional(),
|
|
26
|
+
root_repository_size: z.number().optional(),
|
|
27
|
+
projects_count: z.number().optional(),
|
|
28
|
+
});
|
|
29
|
+
export const GitLabNamespaceExistsResponseSchema = z.object({
|
|
30
|
+
exists: z.boolean(),
|
|
31
|
+
suggests: z.array(z.string()).optional(),
|
|
32
|
+
});
|
|
8
33
|
// Repository related schemas
|
|
9
34
|
export const GitLabOwnerSchema = z.object({
|
|
10
35
|
username: z.string(), // Changed from login to match GitLab API
|
|
@@ -28,7 +53,51 @@ export const GitLabRepositorySchema = z.object({
|
|
|
28
53
|
created_at: z.string().optional(),
|
|
29
54
|
last_activity_at: z.string().optional(),
|
|
30
55
|
default_branch: z.string().optional(),
|
|
31
|
-
|
|
56
|
+
namespace: z.object({
|
|
57
|
+
id: z.number(),
|
|
58
|
+
name: z.string(),
|
|
59
|
+
path: z.string(),
|
|
60
|
+
kind: z.string(),
|
|
61
|
+
full_path: z.string(),
|
|
62
|
+
avatar_url: z.string().nullable().optional(),
|
|
63
|
+
web_url: z.string().optional(),
|
|
64
|
+
}).optional(),
|
|
65
|
+
readme_url: z.string().optional().nullable(),
|
|
66
|
+
topics: z.array(z.string()).optional(),
|
|
67
|
+
tag_list: z.array(z.string()).optional(), // deprecated but still present
|
|
68
|
+
open_issues_count: z.number().optional(),
|
|
69
|
+
archived: z.boolean().optional(),
|
|
70
|
+
forks_count: z.number().optional(),
|
|
71
|
+
star_count: z.number().optional(),
|
|
72
|
+
permissions: z.object({
|
|
73
|
+
project_access: z.object({
|
|
74
|
+
access_level: z.number(),
|
|
75
|
+
notification_level: z.number().optional(),
|
|
76
|
+
}).optional().nullable(),
|
|
77
|
+
group_access: z.object({
|
|
78
|
+
access_level: z.number(),
|
|
79
|
+
notification_level: z.number().optional(),
|
|
80
|
+
}).optional().nullable(),
|
|
81
|
+
}).optional(),
|
|
82
|
+
container_registry_enabled: z.boolean().optional(),
|
|
83
|
+
container_registry_access_level: z.string().optional(),
|
|
84
|
+
issues_enabled: z.boolean().optional(),
|
|
85
|
+
merge_requests_enabled: z.boolean().optional(),
|
|
86
|
+
wiki_enabled: z.boolean().optional(),
|
|
87
|
+
jobs_enabled: z.boolean().optional(),
|
|
88
|
+
snippets_enabled: z.boolean().optional(),
|
|
89
|
+
can_create_merge_request_in: z.boolean().optional(),
|
|
90
|
+
resolve_outdated_diff_discussions: z.boolean().optional(),
|
|
91
|
+
shared_runners_enabled: z.boolean().optional(),
|
|
92
|
+
shared_with_groups: z.array(z.object({
|
|
93
|
+
group_id: z.number(),
|
|
94
|
+
group_name: z.string(),
|
|
95
|
+
group_full_path: z.string(),
|
|
96
|
+
group_access_level: z.number(),
|
|
97
|
+
})).optional(),
|
|
98
|
+
});
|
|
99
|
+
// Project schema (extended from repository schema)
|
|
100
|
+
export const GitLabProjectSchema = GitLabRepositorySchema;
|
|
32
101
|
// File content schemas
|
|
33
102
|
export const GitLabFileContentSchema = z.object({
|
|
34
103
|
file_name: z.string(), // Changed from name to match GitLab API
|
|
@@ -133,20 +202,6 @@ export const GitLabSearchResponseSchema = z.object({
|
|
|
133
202
|
current_page: z.number().optional(),
|
|
134
203
|
items: z.array(GitLabRepositorySchema),
|
|
135
204
|
});
|
|
136
|
-
// Fork related schemas
|
|
137
|
-
export const GitLabForkParentSchema = z.object({
|
|
138
|
-
name: z.string(),
|
|
139
|
-
path_with_namespace: z.string(), // Changed from full_name to match GitLab API
|
|
140
|
-
owner: z.object({
|
|
141
|
-
username: z.string(), // Changed from login to match GitLab API
|
|
142
|
-
id: z.number(),
|
|
143
|
-
avatar_url: z.string(),
|
|
144
|
-
}).optional(), // Made optional to handle cases where GitLab API doesn't include it
|
|
145
|
-
web_url: z.string(), // Changed from html_url to match GitLab API
|
|
146
|
-
});
|
|
147
|
-
export const GitLabForkSchema = GitLabRepositorySchema.extend({
|
|
148
|
-
forked_from_project: GitLabForkParentSchema.optional(), // Made optional to handle cases where GitLab API doesn't include it
|
|
149
|
-
});
|
|
150
205
|
// Issue related schemas
|
|
151
206
|
export const GitLabLabelSchema = z.object({
|
|
152
207
|
id: z.number(),
|
|
@@ -178,12 +233,48 @@ export const GitLabIssueSchema = z.object({
|
|
|
178
233
|
state: z.string(),
|
|
179
234
|
author: GitLabUserSchema,
|
|
180
235
|
assignees: z.array(GitLabUserSchema),
|
|
181
|
-
labels: z.array(GitLabLabelSchema),
|
|
236
|
+
labels: z.array(GitLabLabelSchema).or(z.array(z.string())), // Support both label objects and strings
|
|
182
237
|
milestone: GitLabMilestoneSchema.nullable(),
|
|
183
238
|
created_at: z.string(),
|
|
184
239
|
updated_at: z.string(),
|
|
185
240
|
closed_at: z.string().nullable(),
|
|
186
241
|
web_url: z.string(), // Changed from html_url to match GitLab API
|
|
242
|
+
references: z.object({
|
|
243
|
+
short: z.string(),
|
|
244
|
+
relative: z.string(),
|
|
245
|
+
full: z.string(),
|
|
246
|
+
}).optional(),
|
|
247
|
+
time_stats: z.object({
|
|
248
|
+
time_estimate: z.number(),
|
|
249
|
+
total_time_spent: z.number(),
|
|
250
|
+
human_time_estimate: z.string().nullable(),
|
|
251
|
+
human_total_time_spent: z.string().nullable(),
|
|
252
|
+
}).optional(),
|
|
253
|
+
confidential: z.boolean().optional(),
|
|
254
|
+
due_date: z.string().nullable().optional(),
|
|
255
|
+
discussion_locked: z.boolean().nullable().optional(),
|
|
256
|
+
weight: z.number().nullable().optional(),
|
|
257
|
+
});
|
|
258
|
+
// NEW SCHEMA: For issue with link details (used in listing issue links)
|
|
259
|
+
export const GitLabIssueWithLinkDetailsSchema = GitLabIssueSchema.extend({
|
|
260
|
+
issue_link_id: z.number(),
|
|
261
|
+
link_type: z.enum(['relates_to', 'blocks', 'is_blocked_by']),
|
|
262
|
+
link_created_at: z.string(),
|
|
263
|
+
link_updated_at: z.string(),
|
|
264
|
+
});
|
|
265
|
+
// Fork related schemas
|
|
266
|
+
export const GitLabForkParentSchema = z.object({
|
|
267
|
+
name: z.string(),
|
|
268
|
+
path_with_namespace: z.string(), // Changed from full_name to match GitLab API
|
|
269
|
+
owner: z.object({
|
|
270
|
+
username: z.string(), // Changed from login to match GitLab API
|
|
271
|
+
id: z.number(),
|
|
272
|
+
avatar_url: z.string(),
|
|
273
|
+
}).optional(), // Made optional to handle cases where GitLab API doesn't include it
|
|
274
|
+
web_url: z.string(), // Changed from html_url to match GitLab API
|
|
275
|
+
});
|
|
276
|
+
export const GitLabForkSchema = GitLabRepositorySchema.extend({
|
|
277
|
+
forked_from_project: GitLabForkParentSchema.optional(), // Made optional to handle cases where GitLab API doesn't include it
|
|
187
278
|
});
|
|
188
279
|
// Merge Request related schemas (equivalent to Pull Request)
|
|
189
280
|
export const GitLabMergeRequestDiffRefSchema = z.object({
|
|
@@ -364,3 +455,106 @@ export const CreateNoteSchema = z.object({
|
|
|
364
455
|
noteable_iid: z.number().describe("IID of the issue or merge request"),
|
|
365
456
|
body: z.string().describe("Note content"),
|
|
366
457
|
});
|
|
458
|
+
// Issues API operation schemas
|
|
459
|
+
export const ListIssuesSchema = z.object({
|
|
460
|
+
project_id: z.string().describe("Project ID or URL-encoded path"),
|
|
461
|
+
assignee_id: z.number().optional().describe("Return issues assigned to the given user ID"),
|
|
462
|
+
assignee_username: z.string().optional().describe("Return issues assigned to the given username"),
|
|
463
|
+
author_id: z.number().optional().describe("Return issues created by the given user ID"),
|
|
464
|
+
author_username: z.string().optional().describe("Return issues created by the given username"),
|
|
465
|
+
confidential: z.boolean().optional().describe("Filter confidential or public issues"),
|
|
466
|
+
created_after: z.string().optional().describe("Return issues created after the given time"),
|
|
467
|
+
created_before: z.string().optional().describe("Return issues created before the given time"),
|
|
468
|
+
due_date: z.string().optional().describe("Return issues that have the due date"),
|
|
469
|
+
label_name: z.array(z.string()).optional().describe("Array of label names"),
|
|
470
|
+
milestone: z.string().optional().describe("Milestone title"),
|
|
471
|
+
scope: z.enum(['created-by-me', 'assigned-to-me', 'all']).optional().describe("Return issues from a specific scope"),
|
|
472
|
+
search: z.string().optional().describe("Search for specific terms"),
|
|
473
|
+
state: z.enum(['opened', 'closed', 'all']).optional().describe("Return issues with a specific state"),
|
|
474
|
+
updated_after: z.string().optional().describe("Return issues updated after the given time"),
|
|
475
|
+
updated_before: z.string().optional().describe("Return issues updated before the given time"),
|
|
476
|
+
with_labels_details: z.boolean().optional().describe("Return more details for each label"),
|
|
477
|
+
page: z.number().optional().describe("Page number for pagination"),
|
|
478
|
+
per_page: z.number().optional().describe("Number of items per page"),
|
|
479
|
+
});
|
|
480
|
+
export const GetIssueSchema = z.object({
|
|
481
|
+
project_id: z.string().describe("Project ID or URL-encoded path"),
|
|
482
|
+
issue_iid: z.number().describe("The internal ID of the project issue"),
|
|
483
|
+
});
|
|
484
|
+
export const UpdateIssueSchema = z.object({
|
|
485
|
+
project_id: z.string().describe("Project ID or URL-encoded path"),
|
|
486
|
+
issue_iid: z.number().describe("The internal ID of the project issue"),
|
|
487
|
+
title: z.string().optional().describe("The title of the issue"),
|
|
488
|
+
description: z.string().optional().describe("The description of the issue"),
|
|
489
|
+
assignee_ids: z.array(z.number()).optional().describe("Array of user IDs to assign issue to"),
|
|
490
|
+
confidential: z.boolean().optional().describe("Set the issue to be confidential"),
|
|
491
|
+
discussion_locked: z.boolean().optional().describe("Flag to lock discussions"),
|
|
492
|
+
due_date: z.string().optional().describe("Date the issue is due (YYYY-MM-DD)"),
|
|
493
|
+
labels: z.array(z.string()).optional().describe("Array of label names"),
|
|
494
|
+
milestone_id: z.number().optional().describe("Milestone ID to assign"),
|
|
495
|
+
state_event: z.enum(['close', 'reopen']).optional().describe("Update issue state (close/reopen)"),
|
|
496
|
+
weight: z.number().optional().describe("Weight of the issue (0-9)"),
|
|
497
|
+
});
|
|
498
|
+
export const DeleteIssueSchema = z.object({
|
|
499
|
+
project_id: z.string().describe("Project ID or URL-encoded path"),
|
|
500
|
+
issue_iid: z.number().describe("The internal ID of the project issue"),
|
|
501
|
+
});
|
|
502
|
+
// Issue links related schemas
|
|
503
|
+
export const GitLabIssueLinkSchema = z.object({
|
|
504
|
+
source_issue: GitLabIssueSchema,
|
|
505
|
+
target_issue: GitLabIssueSchema,
|
|
506
|
+
link_type: z.enum(['relates_to', 'blocks', 'is_blocked_by']),
|
|
507
|
+
});
|
|
508
|
+
export const ListIssueLinksSchema = z.object({
|
|
509
|
+
project_id: z.string().describe("Project ID or URL-encoded path"),
|
|
510
|
+
issue_iid: z.number().describe("The internal ID of a project's issue"),
|
|
511
|
+
});
|
|
512
|
+
export const GetIssueLinkSchema = z.object({
|
|
513
|
+
project_id: z.string().describe("Project ID or URL-encoded path"),
|
|
514
|
+
issue_iid: z.number().describe("The internal ID of a project's issue"),
|
|
515
|
+
issue_link_id: z.number().describe("ID of an issue relationship"),
|
|
516
|
+
});
|
|
517
|
+
export const CreateIssueLinkSchema = z.object({
|
|
518
|
+
project_id: z.string().describe("Project ID or URL-encoded path"),
|
|
519
|
+
issue_iid: z.number().describe("The internal ID of a project's issue"),
|
|
520
|
+
target_project_id: z.string().describe("The ID or URL-encoded path of a target project"),
|
|
521
|
+
target_issue_iid: z.number().describe("The internal ID of a target project's issue"),
|
|
522
|
+
link_type: z.enum(['relates_to', 'blocks', 'is_blocked_by']).optional().describe("The type of the relation, defaults to relates_to"),
|
|
523
|
+
});
|
|
524
|
+
export const DeleteIssueLinkSchema = z.object({
|
|
525
|
+
project_id: z.string().describe("Project ID or URL-encoded path"),
|
|
526
|
+
issue_iid: z.number().describe("The internal ID of a project's issue"),
|
|
527
|
+
issue_link_id: z.number().describe("The ID of an issue relationship"),
|
|
528
|
+
});
|
|
529
|
+
// Namespace API operation schemas
|
|
530
|
+
export const ListNamespacesSchema = z.object({
|
|
531
|
+
search: z.string().optional().describe("Search term for namespaces"),
|
|
532
|
+
page: z.number().optional().describe("Page number for pagination"),
|
|
533
|
+
per_page: z.number().optional().describe("Number of items per page"),
|
|
534
|
+
owned: z.boolean().optional().describe("Filter for namespaces owned by current user"),
|
|
535
|
+
});
|
|
536
|
+
export const GetNamespaceSchema = z.object({
|
|
537
|
+
namespace_id: z.string().describe("Namespace ID or full path"),
|
|
538
|
+
});
|
|
539
|
+
export const VerifyNamespaceSchema = z.object({
|
|
540
|
+
path: z.string().describe("Namespace path to verify"),
|
|
541
|
+
});
|
|
542
|
+
// Project API operation schemas
|
|
543
|
+
export const GetProjectSchema = z.object({
|
|
544
|
+
project_id: z.string().describe("Project ID or URL-encoded path"),
|
|
545
|
+
});
|
|
546
|
+
export const ListProjectsSchema = z.object({
|
|
547
|
+
search: z.string().optional().describe("Search term for projects"),
|
|
548
|
+
page: z.number().optional().describe("Page number for pagination"),
|
|
549
|
+
per_page: z.number().optional().describe("Number of items per page"),
|
|
550
|
+
owned: z.boolean().optional().describe("Filter for projects owned by current user"),
|
|
551
|
+
membership: z.boolean().optional().describe("Filter for projects where current user is a member"),
|
|
552
|
+
simple: z.boolean().optional().describe("Return only limited fields"),
|
|
553
|
+
archived: z.boolean().optional().describe("Filter for archived projects"),
|
|
554
|
+
visibility: z.enum(["public", "internal", "private"]).optional().describe("Filter by project visibility"),
|
|
555
|
+
order_by: z.enum(["id", "name", "path", "created_at", "updated_at", "last_activity_at"]).optional().describe("Return projects ordered by field"),
|
|
556
|
+
sort: z.enum(["asc", "desc"]).optional().describe("Return projects sorted in ascending or descending order"),
|
|
557
|
+
with_issues_enabled: z.boolean().optional().describe("Filter projects with issues feature enabled"),
|
|
558
|
+
with_merge_requests_enabled: z.boolean().optional().describe("Filter projects with merge requests feature enabled"),
|
|
559
|
+
min_access_level: z.number().optional().describe("Filter by minimum access level"),
|
|
560
|
+
});
|