@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 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
- 1. `create_or_update_file`
46
-
47
- - Create or update a single file in a GitLab project. 📝
48
- - Inputs:
49
- - `project_id` (string): Project ID or namespace/project_path
50
- - `file_path` (string): Path to create/update the file
51
- - `content` (string): File content
52
- - `commit_message` (string): Commit message
53
- - `branch` (string): Branch to create/update the file in
54
- - `previous_path` (optional string): Previous file path when renaming a file
55
- - Returns: File content and commit details
56
-
57
- 2. `push_files`
58
-
59
- - Push multiple files in a single commit. 📤
60
- - Inputs:
61
- - `project_id` (string): Project ID or namespace/project_path
62
- - `branch` (string): Branch to push to
63
- - `files` (array): Array of files to push, each with `file_path` and `content` properties
64
- - `commit_message` (string): Commit message
65
- - Returns: Updated branch reference
66
-
67
- 3. `search_repositories`
68
-
69
- - Search for GitLab projects. 🔍
70
- - Inputs:
71
- - `search` (string): Search query
72
- - `page` (optional number): Page number (default: 1)
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
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zereight/mcp-gitlab",
3
- "version": "1.0.16",
3
+ "version": "1.0.18",
4
4
  "description": "MCP server for using the GitLab API",
5
5
  "license": "MIT",
6
6
  "author": "zereight",