@zereight/mcp-gitlab 1.0.31 â 1.0.33
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 +44 -237
- package/build/index.js +216 -30
- package/build/schemas.js +300 -78
- package/build/scripts/generate-tools-readme.js +41 -0
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -23,7 +23,8 @@ When using with the Claude App, you need to set up your API key and URLs directl
|
|
|
23
23
|
"env": {
|
|
24
24
|
"GITLAB_PERSONAL_ACCESS_TOKEN": "your_gitlab_token",
|
|
25
25
|
"GITLAB_API_URL": "your_gitlab_api_url",
|
|
26
|
-
"GITLAB_READ_ONLY_MODE": "
|
|
26
|
+
"GITLAB_READ_ONLY_MODE": "false",
|
|
27
|
+
"USE_GITLAB_WIKI":"true"
|
|
27
28
|
}
|
|
28
29
|
}
|
|
29
30
|
}
|
|
@@ -36,242 +37,48 @@ When using with the Claude App, you need to set up your API key and URLs directl
|
|
|
36
37
|
- `GITLAB_PERSONAL_ACCESS_TOKEN`: Your GitLab personal access token.
|
|
37
38
|
- `GITLAB_API_URL`: Your GitLab API URL. (Default: `https://gitlab.com/api/v4`)
|
|
38
39
|
- `GITLAB_READ_ONLY_MODE`: When set to 'true', restricts the server to only expose read-only operations. Useful for enhanced security or when write access is not needed. Also useful for using with Cursor and it's 40 tool limit.
|
|
40
|
+
- `USE_GITLAB_WIKI`: When set to 'true', enables the wiki-related tools (list_wiki_pages, get_wiki_page, create_wiki_page, update_wiki_page, delete_wiki_page). By default, wiki features are disabled.
|
|
39
41
|
|
|
40
42
|
## Tools đ ī¸
|
|
41
43
|
|
|
42
|
-
|
|
43
|
-
|
|
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
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
5. `get_file_contents`
|
|
84
|
-
|
|
85
|
-
- Get the contents of a file or directory. đ
|
|
86
|
-
- Inputs:
|
|
87
|
-
- `project_id` (string): Project ID or namespace/project_path
|
|
88
|
-
- `file_path` (string): Path to the file/directory
|
|
89
|
-
- `ref` (optional string): Branch, tag, or commit SHA (default: default branch)
|
|
90
|
-
- Returns: File/directory content
|
|
91
|
-
|
|
92
|
-
6. `create_issue`
|
|
93
|
-
|
|
94
|
-
- Create a new issue. đ
|
|
95
|
-
- Inputs:
|
|
96
|
-
- `project_id` (string): Project ID or namespace/project_path
|
|
97
|
-
- `title` (string): Issue title
|
|
98
|
-
- `description` (string): Issue description
|
|
99
|
-
- `assignee_ids` (optional number[]): Array of assignee IDs
|
|
100
|
-
- `milestone_id` (optional number): Milestone ID
|
|
101
|
-
- `labels` (optional string[]): Array of labels
|
|
102
|
-
- Returns: Details of the created issue
|
|
103
|
-
|
|
104
|
-
7. `create_merge_request`
|
|
105
|
-
|
|
106
|
-
- Create a new merge request. đ
|
|
107
|
-
- Inputs:
|
|
108
|
-
- `project_id` (string): Project ID or namespace/project_path
|
|
109
|
-
- `title` (string): Merge request title
|
|
110
|
-
- `description` (string): Merge request description
|
|
111
|
-
- `source_branch` (string): Branch with changes
|
|
112
|
-
- `target_branch` (string): Branch to merge into
|
|
113
|
-
- `allow_collaboration` (optional boolean): Allow collaborators to push commits to the source branch
|
|
114
|
-
- `draft` (optional boolean): Create as a draft merge request
|
|
115
|
-
- Returns: Details of the created merge request
|
|
116
|
-
|
|
117
|
-
8. `fork_repository`
|
|
118
|
-
|
|
119
|
-
- Fork a project. đ´
|
|
120
|
-
- Inputs:
|
|
121
|
-
- `project_id` (string): Project ID or namespace/project_path to fork
|
|
122
|
-
- `namespace` (optional string): Namespace to fork into (default: user namespace)
|
|
123
|
-
- Returns: Details of the forked project
|
|
124
|
-
|
|
125
|
-
9. `create_branch`
|
|
126
|
-
|
|
127
|
-
- Create a new branch. đŋ
|
|
128
|
-
- Inputs:
|
|
129
|
-
- `project_id` (string): Project ID or namespace/project_path
|
|
130
|
-
- `name` (string): New branch name
|
|
131
|
-
- `ref` (optional string): Ref to create the branch from (branch, tag, commit SHA, default: default branch)
|
|
132
|
-
- Returns: Created branch reference
|
|
133
|
-
|
|
134
|
-
10. `get_merge_request`
|
|
135
|
-
|
|
136
|
-
- Get details of a merge request. âšī¸
|
|
137
|
-
- Inputs:
|
|
138
|
-
- `project_id` (string): Project ID or namespace/project_path
|
|
139
|
-
- `merge_request_iid` (number): Merge request IID
|
|
140
|
-
- Returns: Merge request details
|
|
141
|
-
|
|
142
|
-
11. `get_merge_request_diffs`
|
|
143
|
-
|
|
144
|
-
- Get changes (diffs) of a merge request. diff
|
|
145
|
-
- Inputs:
|
|
146
|
-
- `project_id` (string): Project ID or namespace/project_path
|
|
147
|
-
- `merge_request_iid` (number): Merge request IID
|
|
148
|
-
- `view` (optional string): Diff view type ('inline' or 'parallel')
|
|
149
|
-
- Returns: Array of merge request diff information
|
|
150
|
-
|
|
151
|
-
12. `update_merge_request`
|
|
152
|
-
|
|
153
|
-
- Update a merge request. đ
|
|
154
|
-
- Inputs:
|
|
155
|
-
- `project_id` (string): Project ID or namespace/project_path
|
|
156
|
-
- `merge_request_iid` (number): Merge request IID
|
|
157
|
-
- `title` (optional string): New title
|
|
158
|
-
- `description` (string): New description
|
|
159
|
-
- `target_branch` (optional string): New target branch
|
|
160
|
-
- `state_event` (optional string): Merge request state change event ('close', 'reopen')
|
|
161
|
-
- `remove_source_branch` (optional boolean): Remove source branch after merge
|
|
162
|
-
- `allow_collaboration` (optional boolean): Allow collaborators to push commits to the source branch
|
|
163
|
-
- Returns: Updated merge request details
|
|
164
|
-
|
|
165
|
-
13. `create_note`
|
|
166
|
-
- Create a new note (comment) to an issue or merge request. đŦ
|
|
167
|
-
- Inputs:
|
|
168
|
-
- `project_id` (string): Project ID or namespace/project_path
|
|
169
|
-
- `noteable_type` (string): Type of noteable ("issue" or "merge_request")
|
|
170
|
-
- `noteable_iid` (number): IID of the issue or merge request
|
|
171
|
-
- `body` (string): Note content
|
|
172
|
-
- Returns: Details of the created note
|
|
173
|
-
|
|
174
|
-
14. `list_projects`
|
|
175
|
-
- List accessible projects with rich filtering options đ
|
|
176
|
-
- Inputs:
|
|
177
|
-
- Search/filtering:
|
|
178
|
-
- `search`
|
|
179
|
-
- `owned`
|
|
180
|
-
- `membership`
|
|
181
|
-
- `archived`
|
|
182
|
-
- `visibility`
|
|
183
|
-
- Features filtering:
|
|
184
|
-
- `with_issues_enabled`
|
|
185
|
-
- `with_merge_requests_enabled`
|
|
186
|
-
- Sorting:
|
|
187
|
-
- `order_by`
|
|
188
|
-
- `sort`
|
|
189
|
-
- Access control:
|
|
190
|
-
- `min_access_level`
|
|
191
|
-
- Pagination:
|
|
192
|
-
- `page`
|
|
193
|
-
- `per_page`
|
|
194
|
-
- `simple`
|
|
195
|
-
- Returns: Array of projects
|
|
196
|
-
15. `list_labels`
|
|
197
|
-
- List all labels for a project with filtering options đˇī¸
|
|
198
|
-
- Inputs:
|
|
199
|
-
- `project_id` (string): Project ID or path
|
|
200
|
-
- `with_counts` (optional): Include issue and merge request counts
|
|
201
|
-
- `include_ancestor_groups` (optional): Include ancestor groups
|
|
202
|
-
- `search` (optional): Filter labels by keyword
|
|
203
|
-
- Returns: Array of labels
|
|
204
|
-
16. `get_label`
|
|
205
|
-
- Get a single label from a project
|
|
206
|
-
- Inputs:
|
|
207
|
-
- `project_id` (string): Project ID or path
|
|
208
|
-
- `label_id` (number/string): Label ID or name
|
|
209
|
-
- `include_ancestor_groups` (optional): Include ancestor groups
|
|
210
|
-
- Returns: label details
|
|
211
|
-
17. `create_label`
|
|
212
|
-
- Create a new label in an object đˇī¸â
|
|
213
|
-
- Inputs:
|
|
214
|
-
- `project_id` (string): Project ID or path
|
|
215
|
-
- `name` (string): Label name
|
|
216
|
-
- `color` (string): Color in hex format (e.g., "#FF0000")
|
|
217
|
-
- `description` (optional): Label description
|
|
218
|
-
- `priority` (optional): Label priority
|
|
219
|
-
- Returns: Created label details
|
|
220
|
-
18. `update_label`
|
|
221
|
-
- Update an existing label in a project đˇī¸âī¸
|
|
222
|
-
- Inputs:
|
|
223
|
-
- `project_id` (string): Project ID or path
|
|
224
|
-
- `label_id` (number/string): Label ID or name
|
|
225
|
-
- `new_name` (optional): New label name
|
|
226
|
-
- `color` (optional): New color in hex format
|
|
227
|
-
- `description` (optional): New description
|
|
228
|
-
- `priority` (optional): New priority
|
|
229
|
-
- Returns: Updated label details
|
|
230
|
-
19. `delete_label`
|
|
231
|
-
- Delete a label from a project đˇī¸â
|
|
232
|
-
- Inputs:
|
|
233
|
-
- `project_id` (string): Project ID or path
|
|
234
|
-
- `label_id` (number/string): Label ID or name
|
|
235
|
-
- Returns: Success message
|
|
236
|
-
|
|
237
|
-
14. `list_group_projects`
|
|
238
|
-
|
|
239
|
-
- List all projects in a GitLab group. đ
|
|
240
|
-
- Inputs:
|
|
241
|
-
- `group_id` (string): Project ID or namespace/project_path
|
|
242
|
-
- Filtering options:
|
|
243
|
-
- `include_subgroups` (optional boolean): Include projects from subgroups
|
|
244
|
-
- `search` (optional string): Search term to filter projects
|
|
245
|
-
- `archived` (optional boolean): Filter for archived projects
|
|
246
|
-
- `visibility` (optional string): Filter by project visibility (public/internal/private)
|
|
247
|
-
- `with_programming_language` (optional string): Filter by programming language
|
|
248
|
-
- `starred` (optional boolean): Filter by starred projects
|
|
249
|
-
- Feature filtering:
|
|
250
|
-
- `with_issues_enabled` (optional boolean): Filter projects with issues feature enabled
|
|
251
|
-
- `with_merge_requests_enabled` (optional boolean): Filter projects with merge requests feature enabled
|
|
252
|
-
- `min_access_level` (optional number): Filter by minimum access level
|
|
253
|
-
- Pagination:
|
|
254
|
-
- `page` (optional number): Page number
|
|
255
|
-
- `per_page` (optional number): Results per page
|
|
256
|
-
- Sorting:
|
|
257
|
-
- `order_by` (optional string): Field to sort by
|
|
258
|
-
- `sort` (optional string): Sort direction (asc/desc)
|
|
259
|
-
- Additional data:
|
|
260
|
-
- `statistics` (optional boolean): Include project statistics
|
|
261
|
-
- `with_custom_attributes` (optional boolean): Include custom attributes
|
|
262
|
-
- `with_security_reports` (optional boolean): Include security reports
|
|
263
|
-
- Returns: List of projects
|
|
264
|
-
|
|
265
|
-
## Environment Variable Configuration
|
|
266
|
-
|
|
267
|
-
Before running the server, you need to set the following environment variables:
|
|
268
|
-
|
|
269
|
-
```
|
|
270
|
-
GITLAB_PERSONAL_ACCESS_TOKEN=your_gitlab_token
|
|
271
|
-
GITLAB_API_URL=your_gitlab_api_url # Default: https://gitlab.com/api/v4
|
|
272
|
-
GITLAB_READ_ONLY_MODE=true # Optional: Enable read-only mode
|
|
273
|
-
```
|
|
274
|
-
|
|
275
|
-
## License
|
|
276
|
-
|
|
277
|
-
MIT License
|
|
44
|
+
+<!-- TOOLS-START -->
|
|
45
|
+
1. `create_or_update_file` - Create or update a single file in a GitLab project
|
|
46
|
+
2. `search_repositories` - Search for GitLab projects
|
|
47
|
+
3. `create_repository` - Create a new GitLab project
|
|
48
|
+
4. `get_file_contents` - Get the contents of a file or directory from a GitLab project
|
|
49
|
+
5. `push_files` - Push multiple files to a GitLab project in a single commit
|
|
50
|
+
6. `create_issue` - Create a new issue in a GitLab project
|
|
51
|
+
7. `create_merge_request` - Create a new merge request in a GitLab project
|
|
52
|
+
8. `fork_repository` - Fork a GitLab project to your account or specified namespace
|
|
53
|
+
9. `create_branch` - Create a new branch in a GitLab project
|
|
54
|
+
10. `get_merge_request` - Get details of a merge request
|
|
55
|
+
11. `get_merge_request_diffs` - Get the changes/diffs of a merge request
|
|
56
|
+
12. `update_merge_request` - Update a merge request
|
|
57
|
+
13. `create_note` - Create a new note (comment) to an issue or merge request
|
|
58
|
+
14. `mr_discussions` - List discussion items for a merge request
|
|
59
|
+
15. `update_merge_request_note` - Modify an existing merge request thread note
|
|
60
|
+
16. `list_issues` - List issues in a GitLab project with filtering options
|
|
61
|
+
17. `get_issue` - Get details of a specific issue in a GitLab project
|
|
62
|
+
18. `update_issue` - Update an issue in a GitLab project
|
|
63
|
+
19. `delete_issue` - Delete an issue from a GitLab project
|
|
64
|
+
20. `list_issue_links` - List all issue links for a specific issue
|
|
65
|
+
21. `get_issue_link` - Get a specific issue link
|
|
66
|
+
22. `create_issue_link` - Create an issue link between two issues
|
|
67
|
+
23. `delete_issue_link` - Delete an issue link
|
|
68
|
+
24. `list_namespaces` - List all namespaces available to the current user
|
|
69
|
+
25. `get_namespace` - Get details of a namespace by ID or path
|
|
70
|
+
26. `verify_namespace` - Verify if a namespace path exists
|
|
71
|
+
27. `get_project` - Get details of a specific project
|
|
72
|
+
28. `list_projects` - List projects accessible by the current user
|
|
73
|
+
29. `list_labels` - List labels for a project
|
|
74
|
+
30. `get_label` - Get a single label from a project
|
|
75
|
+
31. `create_label` - Create a new label in a project
|
|
76
|
+
32. `update_label` - Update an existing label in a project
|
|
77
|
+
33. `delete_label` - Delete a label from a project
|
|
78
|
+
34. `list_group_projects` - List projects in a GitLab group with filtering options
|
|
79
|
+
35. `list_wiki_pages` - List wiki pages in a GitLab project
|
|
80
|
+
36. `get_wiki_page` - Get details of a specific wiki page
|
|
81
|
+
37. `create_wiki_page` - Create a new wiki page in a GitLab project
|
|
82
|
+
38. `update_wiki_page` - Update an existing wiki page in a GitLab project
|
|
83
|
+
39. `delete_wiki_page` - Delete a wiki page from a GitLab project
|
|
84
|
+
<!-- TOOLS-END -->
|
package/build/index.js
CHANGED
|
@@ -3,17 +3,17 @@ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
|
3
3
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
4
|
import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
5
5
|
import fetch from "node-fetch";
|
|
6
|
-
import { SocksProxyAgent } from
|
|
7
|
-
import { HttpsProxyAgent } from
|
|
8
|
-
import { HttpProxyAgent } from
|
|
6
|
+
import { SocksProxyAgent } from "socks-proxy-agent";
|
|
7
|
+
import { HttpsProxyAgent } from "https-proxy-agent";
|
|
8
|
+
import { HttpProxyAgent } from "http-proxy-agent";
|
|
9
9
|
import { z } from "zod";
|
|
10
10
|
import { zodToJsonSchema } from "zod-to-json-schema";
|
|
11
11
|
import { fileURLToPath } from "url";
|
|
12
12
|
import { dirname } from "path";
|
|
13
13
|
import fs from "fs";
|
|
14
14
|
import path from "path";
|
|
15
|
-
import { URL } from
|
|
16
|
-
import { GitLabForkSchema, GitLabReferenceSchema, GitLabRepositorySchema, GitLabIssueSchema, GitLabMergeRequestSchema, GitLabContentSchema, GitLabCreateUpdateFileResponseSchema, GitLabSearchResponseSchema, GitLabTreeSchema, GitLabCommitSchema, GitLabNamespaceSchema, GitLabNamespaceExistsResponseSchema, GitLabProjectSchema, CreateOrUpdateFileSchema, SearchRepositoriesSchema, CreateRepositorySchema, GetFileContentsSchema, PushFilesSchema, CreateIssueSchema, CreateMergeRequestSchema, ForkRepositorySchema, CreateBranchSchema, GitLabMergeRequestDiffSchema, GetMergeRequestSchema, GetMergeRequestDiffsSchema, UpdateMergeRequestSchema, ListIssuesSchema, GetIssueSchema, UpdateIssueSchema, DeleteIssueSchema, GitLabIssueLinkSchema, GitLabIssueWithLinkDetailsSchema, ListIssueLinksSchema, GetIssueLinkSchema, CreateIssueLinkSchema, DeleteIssueLinkSchema, ListNamespacesSchema, GetNamespaceSchema, VerifyNamespaceSchema, GetProjectSchema, ListProjectsSchema, ListLabelsSchema, GetLabelSchema, CreateLabelSchema, UpdateLabelSchema, DeleteLabelSchema, CreateNoteSchema, ListGroupProjectsSchema,
|
|
15
|
+
import { URL } from "url";
|
|
16
|
+
import { GitLabForkSchema, GitLabReferenceSchema, GitLabRepositorySchema, GitLabIssueSchema, GitLabMergeRequestSchema, GitLabContentSchema, GitLabCreateUpdateFileResponseSchema, GitLabSearchResponseSchema, GitLabTreeSchema, GitLabCommitSchema, GitLabNamespaceSchema, GitLabNamespaceExistsResponseSchema, GitLabProjectSchema, CreateOrUpdateFileSchema, SearchRepositoriesSchema, CreateRepositorySchema, GetFileContentsSchema, PushFilesSchema, CreateIssueSchema, CreateMergeRequestSchema, ForkRepositorySchema, CreateBranchSchema, GitLabMergeRequestDiffSchema, GetMergeRequestSchema, GetMergeRequestDiffsSchema, UpdateMergeRequestSchema, ListIssuesSchema, GetIssueSchema, UpdateIssueSchema, DeleteIssueSchema, GitLabIssueLinkSchema, GitLabIssueWithLinkDetailsSchema, ListIssueLinksSchema, GetIssueLinkSchema, CreateIssueLinkSchema, DeleteIssueLinkSchema, ListNamespacesSchema, GetNamespaceSchema, VerifyNamespaceSchema, GetProjectSchema, ListProjectsSchema, ListLabelsSchema, GetLabelSchema, CreateLabelSchema, UpdateLabelSchema, DeleteLabelSchema, CreateNoteSchema, ListGroupProjectsSchema, ListWikiPagesSchema, GetWikiPageSchema, CreateWikiPageSchema, UpdateWikiPageSchema, DeleteWikiPageSchema, GitLabWikiPageSchema,
|
|
17
17
|
// Discussion Schemas
|
|
18
18
|
GitLabDiscussionNoteSchema, // Added
|
|
19
19
|
GitLabDiscussionSchema, UpdateMergeRequestNoteSchema, // Added
|
|
@@ -44,6 +44,7 @@ const server = new Server({
|
|
|
44
44
|
});
|
|
45
45
|
const GITLAB_PERSONAL_ACCESS_TOKEN = process.env.GITLAB_PERSONAL_ACCESS_TOKEN;
|
|
46
46
|
const GITLAB_READ_ONLY_MODE = process.env.GITLAB_READ_ONLY_MODE === "true";
|
|
47
|
+
const USE_GITLAB_WIKI = process.env.USE_GITLAB_WIKI === "true";
|
|
47
48
|
// Add proxy configuration
|
|
48
49
|
const HTTP_PROXY = process.env.HTTP_PROXY;
|
|
49
50
|
const HTTPS_PROXY = process.env.HTTPS_PROXY;
|
|
@@ -51,7 +52,7 @@ const HTTPS_PROXY = process.env.HTTPS_PROXY;
|
|
|
51
52
|
let httpAgent = undefined;
|
|
52
53
|
let httpsAgent = undefined;
|
|
53
54
|
if (HTTP_PROXY) {
|
|
54
|
-
if (HTTP_PROXY.startsWith(
|
|
55
|
+
if (HTTP_PROXY.startsWith("socks")) {
|
|
55
56
|
httpAgent = new SocksProxyAgent(HTTP_PROXY);
|
|
56
57
|
}
|
|
57
58
|
else {
|
|
@@ -59,7 +60,7 @@ if (HTTP_PROXY) {
|
|
|
59
60
|
}
|
|
60
61
|
}
|
|
61
62
|
if (HTTPS_PROXY) {
|
|
62
|
-
if (HTTPS_PROXY.startsWith(
|
|
63
|
+
if (HTTPS_PROXY.startsWith("socks")) {
|
|
63
64
|
httpsAgent = new SocksProxyAgent(HTTPS_PROXY);
|
|
64
65
|
}
|
|
65
66
|
else {
|
|
@@ -76,11 +77,11 @@ const DEFAULT_HEADERS = {
|
|
|
76
77
|
const DEFAULT_FETCH_CONFIG = {
|
|
77
78
|
headers: DEFAULT_HEADERS,
|
|
78
79
|
agent: (parsedUrl) => {
|
|
79
|
-
if (parsedUrl.protocol ===
|
|
80
|
+
if (parsedUrl.protocol === "https:") {
|
|
80
81
|
return httpsAgent;
|
|
81
82
|
}
|
|
82
83
|
return httpAgent;
|
|
83
|
-
}
|
|
84
|
+
},
|
|
84
85
|
};
|
|
85
86
|
// Define all available tools
|
|
86
87
|
const allTools = [
|
|
@@ -131,17 +132,17 @@ const allTools = [
|
|
|
131
132
|
},
|
|
132
133
|
{
|
|
133
134
|
name: "get_merge_request",
|
|
134
|
-
description: "Get details of a merge request",
|
|
135
|
+
description: "Get details of a merge request (Either mergeRequestIid or branchName must be provided)",
|
|
135
136
|
inputSchema: zodToJsonSchema(GetMergeRequestSchema),
|
|
136
137
|
},
|
|
137
138
|
{
|
|
138
139
|
name: "get_merge_request_diffs",
|
|
139
|
-
description: "Get the changes/diffs of a merge request",
|
|
140
|
+
description: "Get the changes/diffs of a merge request (Either mergeRequestIid or branchName must be provided)",
|
|
140
141
|
inputSchema: zodToJsonSchema(GetMergeRequestDiffsSchema),
|
|
141
142
|
},
|
|
142
143
|
{
|
|
143
144
|
name: "update_merge_request",
|
|
144
|
-
description: "Update a merge request",
|
|
145
|
+
description: "Update a merge request (Either mergeRequestIid or branchName must be provided)",
|
|
145
146
|
inputSchema: zodToJsonSchema(UpdateMergeRequestSchema),
|
|
146
147
|
},
|
|
147
148
|
{
|
|
@@ -150,7 +151,7 @@ const allTools = [
|
|
|
150
151
|
inputSchema: zodToJsonSchema(CreateNoteSchema),
|
|
151
152
|
},
|
|
152
153
|
{
|
|
153
|
-
name: "
|
|
154
|
+
name: "mr_discussions",
|
|
154
155
|
description: "List discussion items for a merge request",
|
|
155
156
|
inputSchema: zodToJsonSchema(ListMergeRequestDiscussionsSchema),
|
|
156
157
|
},
|
|
@@ -254,6 +255,31 @@ const allTools = [
|
|
|
254
255
|
description: "List projects in a GitLab group with filtering options",
|
|
255
256
|
inputSchema: zodToJsonSchema(ListGroupProjectsSchema),
|
|
256
257
|
},
|
|
258
|
+
{
|
|
259
|
+
name: "list_wiki_pages",
|
|
260
|
+
description: "List wiki pages in a GitLab project",
|
|
261
|
+
inputSchema: zodToJsonSchema(ListWikiPagesSchema),
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
name: "get_wiki_page",
|
|
265
|
+
description: "Get details of a specific wiki page",
|
|
266
|
+
inputSchema: zodToJsonSchema(GetWikiPageSchema),
|
|
267
|
+
},
|
|
268
|
+
{
|
|
269
|
+
name: "create_wiki_page",
|
|
270
|
+
description: "Create a new wiki page in a GitLab project",
|
|
271
|
+
inputSchema: zodToJsonSchema(CreateWikiPageSchema),
|
|
272
|
+
},
|
|
273
|
+
{
|
|
274
|
+
name: "update_wiki_page",
|
|
275
|
+
description: "Update an existing wiki page in a GitLab project",
|
|
276
|
+
inputSchema: zodToJsonSchema(UpdateWikiPageSchema),
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
name: "delete_wiki_page",
|
|
280
|
+
description: "Delete a wiki page from a GitLab project",
|
|
281
|
+
inputSchema: zodToJsonSchema(DeleteWikiPageSchema),
|
|
282
|
+
},
|
|
257
283
|
];
|
|
258
284
|
// Define which tools are read-only
|
|
259
285
|
const readOnlyTools = [
|
|
@@ -261,7 +287,7 @@ const readOnlyTools = [
|
|
|
261
287
|
"get_file_contents",
|
|
262
288
|
"get_merge_request",
|
|
263
289
|
"get_merge_request_diffs",
|
|
264
|
-
"
|
|
290
|
+
"mr_discussions",
|
|
265
291
|
"list_issues",
|
|
266
292
|
"get_issue",
|
|
267
293
|
"list_issue_links",
|
|
@@ -275,6 +301,15 @@ const readOnlyTools = [
|
|
|
275
301
|
"get_label",
|
|
276
302
|
"list_group_projects",
|
|
277
303
|
];
|
|
304
|
+
// Define which tools are related to wiki and can be toggled by USE_GITLAB_WIKI
|
|
305
|
+
const wikiToolNames = [
|
|
306
|
+
"list_wiki_pages",
|
|
307
|
+
"get_wiki_page",
|
|
308
|
+
"create_wiki_page",
|
|
309
|
+
"update_wiki_page",
|
|
310
|
+
"delete_wiki_page",
|
|
311
|
+
"upload_wiki_attachment",
|
|
312
|
+
];
|
|
278
313
|
/**
|
|
279
314
|
* Smart URL handling for GitLab API
|
|
280
315
|
*
|
|
@@ -312,7 +347,8 @@ async function handleGitLabError(response) {
|
|
|
312
347
|
if (!response.ok) {
|
|
313
348
|
const errorBody = await response.text();
|
|
314
349
|
// Check specifically for Rate Limit error
|
|
315
|
-
if (response.status === 403 &&
|
|
350
|
+
if (response.status === 403 &&
|
|
351
|
+
errorBody.includes("User API Key Rate limit exceeded")) {
|
|
316
352
|
console.error("GitLab API Rate Limit Exceeded:", errorBody);
|
|
317
353
|
console.log("User API Key Rate limit exceeded. Please try again later.");
|
|
318
354
|
throw new Error(`GitLab API Rate Limit Exceeded: ${errorBody}`);
|
|
@@ -902,27 +938,50 @@ async function createRepository(options) {
|
|
|
902
938
|
* MR ėĄ°í í¨ė (Function to retrieve merge request)
|
|
903
939
|
*
|
|
904
940
|
* @param {string} projectId - The ID or URL-encoded path of the project
|
|
905
|
-
* @param {number} mergeRequestIid - The internal ID of the merge request
|
|
941
|
+
* @param {number} mergeRequestIid - The internal ID of the merge request (Optional)
|
|
942
|
+
* @param {string} [branchName] - The name of the branch to search for merge request by branch name (Optional)
|
|
906
943
|
* @returns {Promise<GitLabMergeRequest>} The merge request details
|
|
907
944
|
*/
|
|
908
|
-
async function getMergeRequest(projectId, mergeRequestIid) {
|
|
909
|
-
|
|
945
|
+
async function getMergeRequest(projectId, mergeRequestIid, branchName) {
|
|
946
|
+
let url;
|
|
947
|
+
if (mergeRequestIid) {
|
|
948
|
+
url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/merge_requests/${mergeRequestIid}`);
|
|
949
|
+
}
|
|
950
|
+
else if (branchName) {
|
|
951
|
+
url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/merge_requests?source_branch=${encodeURIComponent(branchName)}`);
|
|
952
|
+
}
|
|
953
|
+
else {
|
|
954
|
+
throw new Error("Either mergeRequestIid or branchName must be provided");
|
|
955
|
+
}
|
|
910
956
|
const response = await fetch(url.toString(), {
|
|
911
957
|
...DEFAULT_FETCH_CONFIG,
|
|
912
958
|
});
|
|
913
959
|
await handleGitLabError(response);
|
|
914
|
-
|
|
960
|
+
const data = await response.json();
|
|
961
|
+
// If response is an array (Comes from branchName search), return the first item if exist
|
|
962
|
+
if (Array.isArray(data) && data.length > 0) {
|
|
963
|
+
return GitLabMergeRequestSchema.parse(data[0]);
|
|
964
|
+
}
|
|
965
|
+
return GitLabMergeRequestSchema.parse(data);
|
|
915
966
|
}
|
|
916
967
|
/**
|
|
917
968
|
* Get merge request changes/diffs
|
|
918
969
|
* MR ëŗę˛ŊėŦí ėĄ°í í¨ė (Function to retrieve merge request changes)
|
|
919
970
|
*
|
|
920
971
|
* @param {string} projectId - The ID or URL-encoded path of the project
|
|
921
|
-
* @param {number} mergeRequestIid - The internal ID of the merge request
|
|
972
|
+
* @param {number} mergeRequestIid - The internal ID of the merge request (Either mergeRequestIid or branchName must be provided)
|
|
973
|
+
* @param {string} [branchName] - The name of the branch to search for merge request by branch name (Either mergeRequestIid or branchName must be provided)
|
|
922
974
|
* @param {string} [view] - The view type for the diff (inline or parallel)
|
|
923
975
|
* @returns {Promise<GitLabMergeRequestDiff[]>} The merge request diffs
|
|
924
976
|
*/
|
|
925
|
-
async function getMergeRequestDiffs(projectId, mergeRequestIid, view) {
|
|
977
|
+
async function getMergeRequestDiffs(projectId, mergeRequestIid, branchName, view) {
|
|
978
|
+
if (!mergeRequestIid && !branchName) {
|
|
979
|
+
throw new Error("Either mergeRequestIid or branchName must be provided");
|
|
980
|
+
}
|
|
981
|
+
if (branchName && !mergeRequestIid) {
|
|
982
|
+
const mergeRequest = await getMergeRequest(projectId, undefined, branchName);
|
|
983
|
+
mergeRequestIid = mergeRequest.iid;
|
|
984
|
+
}
|
|
926
985
|
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/merge_requests/${mergeRequestIid}/changes`);
|
|
927
986
|
if (view) {
|
|
928
987
|
url.searchParams.append("view", view);
|
|
@@ -939,11 +998,19 @@ async function getMergeRequestDiffs(projectId, mergeRequestIid, view) {
|
|
|
939
998
|
* MR ė
ë°ė´í¸ í¨ė (Function to update merge request)
|
|
940
999
|
*
|
|
941
1000
|
* @param {string} projectId - The ID or URL-encoded path of the project
|
|
942
|
-
* @param {number} mergeRequestIid - The internal ID of the merge request
|
|
1001
|
+
* @param {number} mergeRequestIid - The internal ID of the merge request (Optional)
|
|
1002
|
+
* @param {string} branchName - The name of the branch to search for merge request by branch name (Optional)
|
|
943
1003
|
* @param {Object} options - The update options
|
|
944
1004
|
* @returns {Promise<GitLabMergeRequest>} The updated merge request
|
|
945
1005
|
*/
|
|
946
|
-
async function updateMergeRequest(projectId, mergeRequestIid,
|
|
1006
|
+
async function updateMergeRequest(projectId, options, mergeRequestIid, branchName) {
|
|
1007
|
+
if (!mergeRequestIid && !branchName) {
|
|
1008
|
+
throw new Error("Either mergeRequestIid or branchName must be provided");
|
|
1009
|
+
}
|
|
1010
|
+
if (branchName && !mergeRequestIid) {
|
|
1011
|
+
const mergeRequest = await getMergeRequest(projectId, undefined, branchName);
|
|
1012
|
+
mergeRequestIid = mergeRequest.iid;
|
|
1013
|
+
}
|
|
947
1014
|
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/merge_requests/${mergeRequestIid}`);
|
|
948
1015
|
const response = await fetch(url.toString(), {
|
|
949
1016
|
...DEFAULT_FETCH_CONFIG,
|
|
@@ -1262,11 +1329,87 @@ async function listGroupProjects(options) {
|
|
|
1262
1329
|
const projects = await response.json();
|
|
1263
1330
|
return GitLabProjectSchema.array().parse(projects);
|
|
1264
1331
|
}
|
|
1332
|
+
// Wiki API helper functions
|
|
1333
|
+
/**
|
|
1334
|
+
* List wiki pages in a project
|
|
1335
|
+
*/
|
|
1336
|
+
async function listWikiPages(projectId, options = {}) {
|
|
1337
|
+
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/wikis`);
|
|
1338
|
+
if (options.page)
|
|
1339
|
+
url.searchParams.append("page", options.page.toString());
|
|
1340
|
+
if (options.per_page)
|
|
1341
|
+
url.searchParams.append("per_page", options.per_page.toString());
|
|
1342
|
+
const response = await fetch(url.toString(), {
|
|
1343
|
+
...DEFAULT_FETCH_CONFIG,
|
|
1344
|
+
});
|
|
1345
|
+
await handleGitLabError(response);
|
|
1346
|
+
const data = await response.json();
|
|
1347
|
+
return GitLabWikiPageSchema.array().parse(data);
|
|
1348
|
+
}
|
|
1349
|
+
/**
|
|
1350
|
+
* Get a specific wiki page
|
|
1351
|
+
*/
|
|
1352
|
+
async function getWikiPage(projectId, slug) {
|
|
1353
|
+
const response = await fetch(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/wikis/${encodeURIComponent(slug)}`, { ...DEFAULT_FETCH_CONFIG });
|
|
1354
|
+
await handleGitLabError(response);
|
|
1355
|
+
const data = await response.json();
|
|
1356
|
+
return GitLabWikiPageSchema.parse(data);
|
|
1357
|
+
}
|
|
1358
|
+
/**
|
|
1359
|
+
* Create a new wiki page
|
|
1360
|
+
*/
|
|
1361
|
+
async function createWikiPage(projectId, title, content, format) {
|
|
1362
|
+
const body = { title, content };
|
|
1363
|
+
if (format)
|
|
1364
|
+
body.format = format;
|
|
1365
|
+
const response = await fetch(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/wikis`, {
|
|
1366
|
+
...DEFAULT_FETCH_CONFIG,
|
|
1367
|
+
method: "POST",
|
|
1368
|
+
body: JSON.stringify(body),
|
|
1369
|
+
});
|
|
1370
|
+
await handleGitLabError(response);
|
|
1371
|
+
const data = await response.json();
|
|
1372
|
+
return GitLabWikiPageSchema.parse(data);
|
|
1373
|
+
}
|
|
1374
|
+
/**
|
|
1375
|
+
* Update an existing wiki page
|
|
1376
|
+
*/
|
|
1377
|
+
async function updateWikiPage(projectId, slug, title, content, format) {
|
|
1378
|
+
const body = {};
|
|
1379
|
+
if (title)
|
|
1380
|
+
body.title = title;
|
|
1381
|
+
if (content)
|
|
1382
|
+
body.content = content;
|
|
1383
|
+
if (format)
|
|
1384
|
+
body.format = format;
|
|
1385
|
+
const response = await fetch(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/wikis/${encodeURIComponent(slug)}`, {
|
|
1386
|
+
...DEFAULT_FETCH_CONFIG,
|
|
1387
|
+
method: "PUT",
|
|
1388
|
+
body: JSON.stringify(body),
|
|
1389
|
+
});
|
|
1390
|
+
await handleGitLabError(response);
|
|
1391
|
+
const data = await response.json();
|
|
1392
|
+
return GitLabWikiPageSchema.parse(data);
|
|
1393
|
+
}
|
|
1394
|
+
/**
|
|
1395
|
+
* Delete a wiki page
|
|
1396
|
+
*/
|
|
1397
|
+
async function deleteWikiPage(projectId, slug) {
|
|
1398
|
+
const response = await fetch(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/wikis/${encodeURIComponent(slug)}`, {
|
|
1399
|
+
...DEFAULT_FETCH_CONFIG,
|
|
1400
|
+
method: "DELETE",
|
|
1401
|
+
});
|
|
1402
|
+
await handleGitLabError(response);
|
|
1403
|
+
}
|
|
1265
1404
|
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
1266
|
-
//
|
|
1267
|
-
const
|
|
1405
|
+
// Apply read-only filter first
|
|
1406
|
+
const tools0 = GITLAB_READ_ONLY_MODE
|
|
1268
1407
|
? allTools.filter((tool) => readOnlyTools.includes(tool.name))
|
|
1269
1408
|
: allTools;
|
|
1409
|
+
// Toggle wiki tools by USE_GITLAB_WIKI flag
|
|
1410
|
+
const tools = USE_GITLAB_WIKI
|
|
1411
|
+
? tools0
|
|
1412
|
+
: tools0.filter((tool) => !wikiToolNames.includes(tool.name));
|
|
1270
1413
|
return {
|
|
1271
1414
|
tools,
|
|
1272
1415
|
};
|
|
@@ -1382,7 +1525,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1382
1525
|
}
|
|
1383
1526
|
case "get_merge_request": {
|
|
1384
1527
|
const args = GetMergeRequestSchema.parse(request.params.arguments);
|
|
1385
|
-
const mergeRequest = await getMergeRequest(args.project_id, args.merge_request_iid);
|
|
1528
|
+
const mergeRequest = await getMergeRequest(args.project_id, args.merge_request_iid, args.source_branch);
|
|
1386
1529
|
return {
|
|
1387
1530
|
content: [
|
|
1388
1531
|
{ type: "text", text: JSON.stringify(mergeRequest, null, 2) },
|
|
@@ -1391,22 +1534,22 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1391
1534
|
}
|
|
1392
1535
|
case "get_merge_request_diffs": {
|
|
1393
1536
|
const args = GetMergeRequestDiffsSchema.parse(request.params.arguments);
|
|
1394
|
-
const diffs = await getMergeRequestDiffs(args.project_id, args.merge_request_iid, args.view);
|
|
1537
|
+
const diffs = await getMergeRequestDiffs(args.project_id, args.merge_request_iid, args.source_branch, args.view);
|
|
1395
1538
|
return {
|
|
1396
1539
|
content: [{ type: "text", text: JSON.stringify(diffs, null, 2) }],
|
|
1397
1540
|
};
|
|
1398
1541
|
}
|
|
1399
1542
|
case "update_merge_request": {
|
|
1400
1543
|
const args = UpdateMergeRequestSchema.parse(request.params.arguments);
|
|
1401
|
-
const { project_id, merge_request_iid, ...options } = args;
|
|
1402
|
-
const mergeRequest = await updateMergeRequest(project_id, merge_request_iid,
|
|
1544
|
+
const { project_id, merge_request_iid, source_branch, ...options } = args;
|
|
1545
|
+
const mergeRequest = await updateMergeRequest(project_id, options, merge_request_iid, source_branch);
|
|
1403
1546
|
return {
|
|
1404
1547
|
content: [
|
|
1405
1548
|
{ type: "text", text: JSON.stringify(mergeRequest, null, 2) },
|
|
1406
1549
|
],
|
|
1407
1550
|
};
|
|
1408
1551
|
}
|
|
1409
|
-
case "
|
|
1552
|
+
case "mr_discussions": {
|
|
1410
1553
|
const args = ListMergeRequestDiscussionsSchema.parse(request.params.arguments);
|
|
1411
1554
|
const discussions = await listMergeRequestDiscussions(args.project_id, args.merge_request_iid);
|
|
1412
1555
|
return {
|
|
@@ -1617,6 +1760,49 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1617
1760
|
content: [{ type: "text", text: JSON.stringify(projects, null, 2) }],
|
|
1618
1761
|
};
|
|
1619
1762
|
}
|
|
1763
|
+
case "list_wiki_pages": {
|
|
1764
|
+
const { project_id, page, per_page } = ListWikiPagesSchema.parse(request.params.arguments);
|
|
1765
|
+
const wikiPages = await listWikiPages(project_id, { page, per_page });
|
|
1766
|
+
return {
|
|
1767
|
+
content: [{ type: "text", text: JSON.stringify(wikiPages, null, 2) }],
|
|
1768
|
+
};
|
|
1769
|
+
}
|
|
1770
|
+
case "get_wiki_page": {
|
|
1771
|
+
const { project_id, slug } = GetWikiPageSchema.parse(request.params.arguments);
|
|
1772
|
+
const wikiPage = await getWikiPage(project_id, slug);
|
|
1773
|
+
return {
|
|
1774
|
+
content: [{ type: "text", text: JSON.stringify(wikiPage, null, 2) }],
|
|
1775
|
+
};
|
|
1776
|
+
}
|
|
1777
|
+
case "create_wiki_page": {
|
|
1778
|
+
const { project_id, title, content, format } = CreateWikiPageSchema.parse(request.params.arguments);
|
|
1779
|
+
const wikiPage = await createWikiPage(project_id, title, content, format);
|
|
1780
|
+
return {
|
|
1781
|
+
content: [{ type: "text", text: JSON.stringify(wikiPage, null, 2) }],
|
|
1782
|
+
};
|
|
1783
|
+
}
|
|
1784
|
+
case "update_wiki_page": {
|
|
1785
|
+
const { project_id, slug, title, content, format } = UpdateWikiPageSchema.parse(request.params.arguments);
|
|
1786
|
+
const wikiPage = await updateWikiPage(project_id, slug, title, content, format);
|
|
1787
|
+
return {
|
|
1788
|
+
content: [{ type: "text", text: JSON.stringify(wikiPage, null, 2) }],
|
|
1789
|
+
};
|
|
1790
|
+
}
|
|
1791
|
+
case "delete_wiki_page": {
|
|
1792
|
+
const { project_id, slug } = DeleteWikiPageSchema.parse(request.params.arguments);
|
|
1793
|
+
await deleteWikiPage(project_id, slug);
|
|
1794
|
+
return {
|
|
1795
|
+
content: [
|
|
1796
|
+
{
|
|
1797
|
+
type: "text",
|
|
1798
|
+
text: JSON.stringify({
|
|
1799
|
+
status: "success",
|
|
1800
|
+
message: "Wiki page deleted successfully",
|
|
1801
|
+
}, null, 2),
|
|
1802
|
+
},
|
|
1803
|
+
],
|
|
1804
|
+
};
|
|
1805
|
+
}
|
|
1620
1806
|
default:
|
|
1621
1807
|
throw new Error(`Unknown tool: ${request.params.name}`);
|
|
1622
1808
|
}
|
package/build/schemas.js
CHANGED
|
@@ -57,7 +57,8 @@ export const GitLabRepositorySchema = z.object({
|
|
|
57
57
|
created_at: z.string().optional(),
|
|
58
58
|
last_activity_at: z.string().optional(),
|
|
59
59
|
default_branch: z.string().optional(),
|
|
60
|
-
namespace: z
|
|
60
|
+
namespace: z
|
|
61
|
+
.object({
|
|
61
62
|
id: z.number(),
|
|
62
63
|
name: z.string(),
|
|
63
64
|
path: z.string(),
|
|
@@ -65,7 +66,8 @@ export const GitLabRepositorySchema = z.object({
|
|
|
65
66
|
full_path: z.string(),
|
|
66
67
|
avatar_url: z.string().nullable().optional(),
|
|
67
68
|
web_url: z.string().optional(),
|
|
68
|
-
})
|
|
69
|
+
})
|
|
70
|
+
.optional(),
|
|
69
71
|
readme_url: z.string().optional().nullable(),
|
|
70
72
|
topics: z.array(z.string()).optional(),
|
|
71
73
|
tag_list: z.array(z.string()).optional(), // deprecated but still present
|
|
@@ -73,16 +75,24 @@ export const GitLabRepositorySchema = z.object({
|
|
|
73
75
|
archived: z.boolean().optional(),
|
|
74
76
|
forks_count: z.number().optional(),
|
|
75
77
|
star_count: z.number().optional(),
|
|
76
|
-
permissions: z
|
|
77
|
-
|
|
78
|
+
permissions: z
|
|
79
|
+
.object({
|
|
80
|
+
project_access: z
|
|
81
|
+
.object({
|
|
78
82
|
access_level: z.number(),
|
|
79
83
|
notification_level: z.number().optional(),
|
|
80
|
-
})
|
|
81
|
-
|
|
84
|
+
})
|
|
85
|
+
.optional()
|
|
86
|
+
.nullable(),
|
|
87
|
+
group_access: z
|
|
88
|
+
.object({
|
|
82
89
|
access_level: z.number(),
|
|
83
90
|
notification_level: z.number().optional(),
|
|
84
|
-
})
|
|
85
|
-
|
|
91
|
+
})
|
|
92
|
+
.optional()
|
|
93
|
+
.nullable(),
|
|
94
|
+
})
|
|
95
|
+
.optional(),
|
|
86
96
|
container_registry_enabled: z.boolean().optional(),
|
|
87
97
|
container_registry_access_level: z.string().optional(),
|
|
88
98
|
issues_enabled: z.boolean().optional(),
|
|
@@ -93,12 +103,14 @@ export const GitLabRepositorySchema = z.object({
|
|
|
93
103
|
can_create_merge_request_in: z.boolean().optional(),
|
|
94
104
|
resolve_outdated_diff_discussions: z.boolean().optional(),
|
|
95
105
|
shared_runners_enabled: z.boolean().optional(),
|
|
96
|
-
shared_with_groups: z
|
|
106
|
+
shared_with_groups: z
|
|
107
|
+
.array(z.object({
|
|
97
108
|
group_id: z.number(),
|
|
98
109
|
group_name: z.string(),
|
|
99
110
|
group_full_path: z.string(),
|
|
100
111
|
group_access_level: z.number(),
|
|
101
|
-
}))
|
|
112
|
+
}))
|
|
113
|
+
.optional(),
|
|
102
114
|
});
|
|
103
115
|
// Project schema (extended from repository schema)
|
|
104
116
|
export const GitLabProjectSchema = GitLabRepositorySchema;
|
|
@@ -251,17 +263,21 @@ export const GitLabIssueSchema = z.object({
|
|
|
251
263
|
updated_at: z.string(),
|
|
252
264
|
closed_at: z.string().nullable(),
|
|
253
265
|
web_url: z.string(), // Changed from html_url to match GitLab API
|
|
254
|
-
references: z
|
|
266
|
+
references: z
|
|
267
|
+
.object({
|
|
255
268
|
short: z.string(),
|
|
256
269
|
relative: z.string(),
|
|
257
270
|
full: z.string(),
|
|
258
|
-
})
|
|
259
|
-
|
|
271
|
+
})
|
|
272
|
+
.optional(),
|
|
273
|
+
time_stats: z
|
|
274
|
+
.object({
|
|
260
275
|
time_estimate: z.number(),
|
|
261
276
|
total_time_spent: z.number(),
|
|
262
277
|
human_time_estimate: z.string().nullable(),
|
|
263
278
|
human_total_time_spent: z.string().nullable(),
|
|
264
|
-
})
|
|
279
|
+
})
|
|
280
|
+
.optional(),
|
|
265
281
|
confidential: z.boolean().optional(),
|
|
266
282
|
due_date: z.string().nullable().optional(),
|
|
267
283
|
discussion_locked: z.boolean().nullable().optional(),
|
|
@@ -270,7 +286,7 @@ export const GitLabIssueSchema = z.object({
|
|
|
270
286
|
// NEW SCHEMA: For issue with link details (used in listing issue links)
|
|
271
287
|
export const GitLabIssueWithLinkDetailsSchema = GitLabIssueSchema.extend({
|
|
272
288
|
issue_link_id: z.number(),
|
|
273
|
-
link_type: z.enum([
|
|
289
|
+
link_type: z.enum(["relates_to", "blocks", "is_blocked_by"]),
|
|
274
290
|
link_created_at: z.string(),
|
|
275
291
|
link_updated_at: z.string(),
|
|
276
292
|
});
|
|
@@ -278,11 +294,13 @@ export const GitLabIssueWithLinkDetailsSchema = GitLabIssueSchema.extend({
|
|
|
278
294
|
export const GitLabForkParentSchema = z.object({
|
|
279
295
|
name: z.string(),
|
|
280
296
|
path_with_namespace: z.string(), // Changed from full_name to match GitLab API
|
|
281
|
-
owner: z
|
|
297
|
+
owner: z
|
|
298
|
+
.object({
|
|
282
299
|
username: z.string(), // Changed from login to match GitLab API
|
|
283
300
|
id: z.number(),
|
|
284
301
|
avatar_url: z.string(),
|
|
285
|
-
})
|
|
302
|
+
})
|
|
303
|
+
.optional(), // Made optional to handle cases where GitLab API doesn't include it
|
|
286
304
|
web_url: z.string(), // Changed from html_url to match GitLab API
|
|
287
305
|
});
|
|
288
306
|
export const GitLabForkSchema = GitLabRepositorySchema.extend({
|
|
@@ -346,7 +364,9 @@ export const GitLabDiscussionNoteSchema = z.object({
|
|
|
346
364
|
resolved: z.boolean().optional(),
|
|
347
365
|
resolved_by: GitLabUserSchema.nullable().optional(),
|
|
348
366
|
resolved_at: z.string().nullable().optional(),
|
|
349
|
-
position: z
|
|
367
|
+
position: z
|
|
368
|
+
.object({
|
|
369
|
+
// Only present for DiffNote
|
|
350
370
|
base_sha: z.string(),
|
|
351
371
|
start_sha: z.string(),
|
|
352
372
|
head_sha: z.string(),
|
|
@@ -355,7 +375,8 @@ export const GitLabDiscussionNoteSchema = z.object({
|
|
|
355
375
|
position_type: z.enum(["text", "image", "file"]),
|
|
356
376
|
old_line: z.number().nullable(),
|
|
357
377
|
new_line: z.number().nullable(),
|
|
358
|
-
line_range: z
|
|
378
|
+
line_range: z
|
|
379
|
+
.object({
|
|
359
380
|
start: z.object({
|
|
360
381
|
line_code: z.string(),
|
|
361
382
|
type: z.enum(["new", "old"]),
|
|
@@ -368,12 +389,15 @@ export const GitLabDiscussionNoteSchema = z.object({
|
|
|
368
389
|
old_line: z.number().nullable(),
|
|
369
390
|
new_line: z.number().nullable(),
|
|
370
391
|
}),
|
|
371
|
-
})
|
|
392
|
+
})
|
|
393
|
+
.nullable()
|
|
394
|
+
.optional(), // For multi-line diff notes
|
|
372
395
|
width: z.number().optional(), // For image diff notes
|
|
373
396
|
height: z.number().optional(), // For image diff notes
|
|
374
397
|
x: z.number().optional(), // For image diff notes
|
|
375
398
|
y: z.number().optional(), // For image diff notes
|
|
376
|
-
})
|
|
399
|
+
})
|
|
400
|
+
.optional(),
|
|
377
401
|
});
|
|
378
402
|
export const GitLabDiscussionSchema = z.object({
|
|
379
403
|
id: z.string(),
|
|
@@ -402,10 +426,7 @@ export const CreateOrUpdateFileSchema = ProjectParamsSchema.extend({
|
|
|
402
426
|
.string()
|
|
403
427
|
.optional()
|
|
404
428
|
.describe("Path of the file to move/rename"),
|
|
405
|
-
last_commit_id: z
|
|
406
|
-
.string()
|
|
407
|
-
.optional()
|
|
408
|
-
.describe("Last known file commit ID"),
|
|
429
|
+
last_commit_id: z.string().optional().describe("Last known file commit ID"),
|
|
409
430
|
commit_id: z
|
|
410
431
|
.string()
|
|
411
432
|
.optional()
|
|
@@ -489,7 +510,9 @@ export const GitLabMergeRequestDiffSchema = z.object({
|
|
|
489
510
|
export const GetMergeRequestSchema = ProjectParamsSchema.extend({
|
|
490
511
|
merge_request_iid: z
|
|
491
512
|
.number()
|
|
492
|
-
.
|
|
513
|
+
.optional()
|
|
514
|
+
.describe("The IID of a merge request"),
|
|
515
|
+
source_branch: z.string().optional().describe("Source branch name"),
|
|
493
516
|
});
|
|
494
517
|
export const UpdateMergeRequestSchema = GetMergeRequestSchema.extend({
|
|
495
518
|
title: z.string().optional().describe("The title of the merge request"),
|
|
@@ -531,22 +554,61 @@ export const CreateNoteSchema = z.object({
|
|
|
531
554
|
// Issues API operation schemas
|
|
532
555
|
export const ListIssuesSchema = z.object({
|
|
533
556
|
project_id: z.string().describe("Project ID or URL-encoded path"),
|
|
534
|
-
assignee_id: z
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
557
|
+
assignee_id: z
|
|
558
|
+
.number()
|
|
559
|
+
.optional()
|
|
560
|
+
.describe("Return issues assigned to the given user ID"),
|
|
561
|
+
assignee_username: z
|
|
562
|
+
.string()
|
|
563
|
+
.optional()
|
|
564
|
+
.describe("Return issues assigned to the given username"),
|
|
565
|
+
author_id: z
|
|
566
|
+
.number()
|
|
567
|
+
.optional()
|
|
568
|
+
.describe("Return issues created by the given user ID"),
|
|
569
|
+
author_username: z
|
|
570
|
+
.string()
|
|
571
|
+
.optional()
|
|
572
|
+
.describe("Return issues created by the given username"),
|
|
573
|
+
confidential: z
|
|
574
|
+
.boolean()
|
|
575
|
+
.optional()
|
|
576
|
+
.describe("Filter confidential or public issues"),
|
|
577
|
+
created_after: z
|
|
578
|
+
.string()
|
|
579
|
+
.optional()
|
|
580
|
+
.describe("Return issues created after the given time"),
|
|
581
|
+
created_before: z
|
|
582
|
+
.string()
|
|
583
|
+
.optional()
|
|
584
|
+
.describe("Return issues created before the given time"),
|
|
585
|
+
due_date: z
|
|
586
|
+
.string()
|
|
587
|
+
.optional()
|
|
588
|
+
.describe("Return issues that have the due date"),
|
|
542
589
|
label_name: z.array(z.string()).optional().describe("Array of label names"),
|
|
543
590
|
milestone: z.string().optional().describe("Milestone title"),
|
|
544
|
-
scope: z
|
|
591
|
+
scope: z
|
|
592
|
+
.enum(["created-by-me", "assigned-to-me", "all"])
|
|
593
|
+
.optional()
|
|
594
|
+
.describe("Return issues from a specific scope"),
|
|
545
595
|
search: z.string().optional().describe("Search for specific terms"),
|
|
546
|
-
state: z
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
596
|
+
state: z
|
|
597
|
+
.enum(["opened", "closed", "all"])
|
|
598
|
+
.optional()
|
|
599
|
+
.describe("Return issues with a specific state"),
|
|
600
|
+
updated_after: z
|
|
601
|
+
.string()
|
|
602
|
+
.optional()
|
|
603
|
+
.describe("Return issues updated after the given time"),
|
|
604
|
+
updated_before: z
|
|
605
|
+
.string()
|
|
606
|
+
.optional()
|
|
607
|
+
.describe("Return issues updated before the given time"),
|
|
608
|
+
with_labels_details: z
|
|
609
|
+
.boolean()
|
|
610
|
+
.optional()
|
|
611
|
+
.describe("Return more details for each label"),
|
|
550
612
|
page: z.number().optional().describe("Page number for pagination"),
|
|
551
613
|
per_page: z.number().optional().describe("Number of items per page"),
|
|
552
614
|
});
|
|
@@ -559,13 +621,28 @@ export const UpdateIssueSchema = z.object({
|
|
|
559
621
|
issue_iid: z.number().describe("The internal ID of the project issue"),
|
|
560
622
|
title: z.string().optional().describe("The title of the issue"),
|
|
561
623
|
description: z.string().optional().describe("The description of the issue"),
|
|
562
|
-
assignee_ids: z
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
624
|
+
assignee_ids: z
|
|
625
|
+
.array(z.number())
|
|
626
|
+
.optional()
|
|
627
|
+
.describe("Array of user IDs to assign issue to"),
|
|
628
|
+
confidential: z
|
|
629
|
+
.boolean()
|
|
630
|
+
.optional()
|
|
631
|
+
.describe("Set the issue to be confidential"),
|
|
632
|
+
discussion_locked: z
|
|
633
|
+
.boolean()
|
|
634
|
+
.optional()
|
|
635
|
+
.describe("Flag to lock discussions"),
|
|
636
|
+
due_date: z
|
|
637
|
+
.string()
|
|
638
|
+
.optional()
|
|
639
|
+
.describe("Date the issue is due (YYYY-MM-DD)"),
|
|
566
640
|
labels: z.array(z.string()).optional().describe("Array of label names"),
|
|
567
641
|
milestone_id: z.number().optional().describe("Milestone ID to assign"),
|
|
568
|
-
state_event: z
|
|
642
|
+
state_event: z
|
|
643
|
+
.enum(["close", "reopen"])
|
|
644
|
+
.optional()
|
|
645
|
+
.describe("Update issue state (close/reopen)"),
|
|
569
646
|
weight: z.number().optional().describe("Weight of the issue (0-9)"),
|
|
570
647
|
});
|
|
571
648
|
export const DeleteIssueSchema = z.object({
|
|
@@ -576,7 +653,7 @@ export const DeleteIssueSchema = z.object({
|
|
|
576
653
|
export const GitLabIssueLinkSchema = z.object({
|
|
577
654
|
source_issue: GitLabIssueSchema,
|
|
578
655
|
target_issue: GitLabIssueSchema,
|
|
579
|
-
link_type: z.enum([
|
|
656
|
+
link_type: z.enum(["relates_to", "blocks", "is_blocked_by"]),
|
|
580
657
|
});
|
|
581
658
|
export const ListIssueLinksSchema = z.object({
|
|
582
659
|
project_id: z.string().describe("Project ID or URL-encoded path"),
|
|
@@ -590,9 +667,16 @@ export const GetIssueLinkSchema = z.object({
|
|
|
590
667
|
export const CreateIssueLinkSchema = z.object({
|
|
591
668
|
project_id: z.string().describe("Project ID or URL-encoded path"),
|
|
592
669
|
issue_iid: z.number().describe("The internal ID of a project's issue"),
|
|
593
|
-
target_project_id: z
|
|
594
|
-
|
|
595
|
-
|
|
670
|
+
target_project_id: z
|
|
671
|
+
.string()
|
|
672
|
+
.describe("The ID or URL-encoded path of a target project"),
|
|
673
|
+
target_issue_iid: z
|
|
674
|
+
.number()
|
|
675
|
+
.describe("The internal ID of a target project's issue"),
|
|
676
|
+
link_type: z
|
|
677
|
+
.enum(["relates_to", "blocks", "is_blocked_by"])
|
|
678
|
+
.optional()
|
|
679
|
+
.describe("The type of the relation, defaults to relates_to"),
|
|
596
680
|
});
|
|
597
681
|
export const DeleteIssueLinkSchema = z.object({
|
|
598
682
|
project_id: z.string().describe("Project ID or URL-encoded path"),
|
|
@@ -604,7 +688,10 @@ export const ListNamespacesSchema = z.object({
|
|
|
604
688
|
search: z.string().optional().describe("Search term for namespaces"),
|
|
605
689
|
page: z.number().optional().describe("Page number for pagination"),
|
|
606
690
|
per_page: z.number().optional().describe("Number of items per page"),
|
|
607
|
-
owned: z
|
|
691
|
+
owned: z
|
|
692
|
+
.boolean()
|
|
693
|
+
.optional()
|
|
694
|
+
.describe("Filter for namespaces owned by current user"),
|
|
608
695
|
});
|
|
609
696
|
export const GetNamespaceSchema = z.object({
|
|
610
697
|
namespace_id: z.string().describe("Namespace ID or full path"),
|
|
@@ -620,65 +707,200 @@ export const ListProjectsSchema = z.object({
|
|
|
620
707
|
search: z.string().optional().describe("Search term for projects"),
|
|
621
708
|
page: z.number().optional().describe("Page number for pagination"),
|
|
622
709
|
per_page: z.number().optional().describe("Number of items per page"),
|
|
623
|
-
|
|
624
|
-
|
|
710
|
+
search_namespaces: z
|
|
711
|
+
.boolean()
|
|
712
|
+
.optional()
|
|
713
|
+
.describe("Needs to be true if search is full path"),
|
|
714
|
+
owned: z
|
|
715
|
+
.boolean()
|
|
716
|
+
.optional()
|
|
717
|
+
.describe("Filter for projects owned by current user"),
|
|
718
|
+
membership: z
|
|
719
|
+
.boolean()
|
|
720
|
+
.optional()
|
|
721
|
+
.describe("Filter for projects where current user is a member"),
|
|
625
722
|
simple: z.boolean().optional().describe("Return only limited fields"),
|
|
626
723
|
archived: z.boolean().optional().describe("Filter for archived projects"),
|
|
627
|
-
visibility: z
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
724
|
+
visibility: z
|
|
725
|
+
.enum(["public", "internal", "private"])
|
|
726
|
+
.optional()
|
|
727
|
+
.describe("Filter by project visibility"),
|
|
728
|
+
order_by: z
|
|
729
|
+
.enum([
|
|
730
|
+
"id",
|
|
731
|
+
"name",
|
|
732
|
+
"path",
|
|
733
|
+
"created_at",
|
|
734
|
+
"updated_at",
|
|
735
|
+
"last_activity_at",
|
|
736
|
+
])
|
|
737
|
+
.optional()
|
|
738
|
+
.describe("Return projects ordered by field"),
|
|
739
|
+
sort: z
|
|
740
|
+
.enum(["asc", "desc"])
|
|
741
|
+
.optional()
|
|
742
|
+
.describe("Return projects sorted in ascending or descending order"),
|
|
743
|
+
with_issues_enabled: z
|
|
744
|
+
.boolean()
|
|
745
|
+
.optional()
|
|
746
|
+
.describe("Filter projects with issues feature enabled"),
|
|
747
|
+
with_merge_requests_enabled: z
|
|
748
|
+
.boolean()
|
|
749
|
+
.optional()
|
|
750
|
+
.describe("Filter projects with merge requests feature enabled"),
|
|
751
|
+
min_access_level: z
|
|
752
|
+
.number()
|
|
753
|
+
.optional()
|
|
754
|
+
.describe("Filter by minimum access level"),
|
|
633
755
|
});
|
|
634
756
|
// Label operation schemas
|
|
635
757
|
export const ListLabelsSchema = z.object({
|
|
636
758
|
project_id: z.string().describe("Project ID or URL-encoded path"),
|
|
637
|
-
with_counts: z
|
|
638
|
-
|
|
759
|
+
with_counts: z
|
|
760
|
+
.boolean()
|
|
761
|
+
.optional()
|
|
762
|
+
.describe("Whether or not to include issue and merge request counts"),
|
|
763
|
+
include_ancestor_groups: z
|
|
764
|
+
.boolean()
|
|
765
|
+
.optional()
|
|
766
|
+
.describe("Include ancestor groups"),
|
|
639
767
|
search: z.string().optional().describe("Keyword to filter labels by"),
|
|
640
768
|
});
|
|
641
769
|
export const GetLabelSchema = z.object({
|
|
642
770
|
project_id: z.string().describe("Project ID or URL-encoded path"),
|
|
643
|
-
label_id: z
|
|
644
|
-
|
|
771
|
+
label_id: z
|
|
772
|
+
.union([z.number(), z.string()])
|
|
773
|
+
.describe("The ID or title of a project's label"),
|
|
774
|
+
include_ancestor_groups: z
|
|
775
|
+
.boolean()
|
|
776
|
+
.optional()
|
|
777
|
+
.describe("Include ancestor groups"),
|
|
645
778
|
});
|
|
646
779
|
export const CreateLabelSchema = z.object({
|
|
647
780
|
project_id: z.string().describe("Project ID or URL-encoded path"),
|
|
648
781
|
name: z.string().describe("The name of the label"),
|
|
649
|
-
color: z
|
|
782
|
+
color: z
|
|
783
|
+
.string()
|
|
784
|
+
.describe("The color of the label given in 6-digit hex notation with leading '#' sign"),
|
|
650
785
|
description: z.string().optional().describe("The description of the label"),
|
|
651
|
-
priority: z
|
|
786
|
+
priority: z
|
|
787
|
+
.number()
|
|
788
|
+
.nullable()
|
|
789
|
+
.optional()
|
|
790
|
+
.describe("The priority of the label"),
|
|
652
791
|
});
|
|
653
792
|
export const UpdateLabelSchema = z.object({
|
|
654
793
|
project_id: z.string().describe("Project ID or URL-encoded path"),
|
|
655
|
-
label_id: z
|
|
794
|
+
label_id: z
|
|
795
|
+
.union([z.number(), z.string()])
|
|
796
|
+
.describe("The ID or title of a project's label"),
|
|
656
797
|
new_name: z.string().optional().describe("The new name of the label"),
|
|
657
|
-
color: z
|
|
658
|
-
|
|
659
|
-
|
|
798
|
+
color: z
|
|
799
|
+
.string()
|
|
800
|
+
.optional()
|
|
801
|
+
.describe("The color of the label given in 6-digit hex notation with leading '#' sign"),
|
|
802
|
+
description: z
|
|
803
|
+
.string()
|
|
804
|
+
.optional()
|
|
805
|
+
.describe("The new description of the label"),
|
|
806
|
+
priority: z
|
|
807
|
+
.number()
|
|
808
|
+
.nullable()
|
|
809
|
+
.optional()
|
|
810
|
+
.describe("The new priority of the label"),
|
|
660
811
|
});
|
|
661
812
|
export const DeleteLabelSchema = z.object({
|
|
662
813
|
project_id: z.string().describe("Project ID or URL-encoded path"),
|
|
663
|
-
label_id: z
|
|
814
|
+
label_id: z
|
|
815
|
+
.union([z.number(), z.string()])
|
|
816
|
+
.describe("The ID or title of a project's label"),
|
|
664
817
|
});
|
|
665
818
|
// Group projects schema
|
|
666
819
|
export const ListGroupProjectsSchema = z.object({
|
|
667
820
|
group_id: z.string().describe("Group ID or path"),
|
|
668
|
-
include_subgroups: z
|
|
821
|
+
include_subgroups: z
|
|
822
|
+
.boolean()
|
|
823
|
+
.optional()
|
|
824
|
+
.describe("Include projects from subgroups"),
|
|
669
825
|
search: z.string().optional().describe("Search term to filter projects"),
|
|
670
|
-
order_by: z
|
|
671
|
-
|
|
826
|
+
order_by: z
|
|
827
|
+
.enum(["name", "path", "created_at", "updated_at", "last_activity_at"])
|
|
828
|
+
.optional()
|
|
829
|
+
.describe("Field to sort by"),
|
|
830
|
+
sort: z.enum(["asc", "desc"]).optional().describe("Sort direction"),
|
|
672
831
|
page: z.number().optional().describe("Page number"),
|
|
673
832
|
per_page: z.number().optional().describe("Number of results per page"),
|
|
674
833
|
archived: z.boolean().optional().describe("Filter for archived projects"),
|
|
675
|
-
visibility: z
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
834
|
+
visibility: z
|
|
835
|
+
.enum(["public", "internal", "private"])
|
|
836
|
+
.optional()
|
|
837
|
+
.describe("Filter by project visibility"),
|
|
838
|
+
with_issues_enabled: z
|
|
839
|
+
.boolean()
|
|
840
|
+
.optional()
|
|
841
|
+
.describe("Filter projects with issues feature enabled"),
|
|
842
|
+
with_merge_requests_enabled: z
|
|
843
|
+
.boolean()
|
|
844
|
+
.optional()
|
|
845
|
+
.describe("Filter projects with merge requests feature enabled"),
|
|
846
|
+
min_access_level: z
|
|
847
|
+
.number()
|
|
848
|
+
.optional()
|
|
849
|
+
.describe("Filter by minimum access level"),
|
|
850
|
+
with_programming_language: z
|
|
851
|
+
.string()
|
|
852
|
+
.optional()
|
|
853
|
+
.describe("Filter by programming language"),
|
|
680
854
|
starred: z.boolean().optional().describe("Filter by starred projects"),
|
|
681
855
|
statistics: z.boolean().optional().describe("Include project statistics"),
|
|
682
|
-
with_custom_attributes: z
|
|
683
|
-
|
|
856
|
+
with_custom_attributes: z
|
|
857
|
+
.boolean()
|
|
858
|
+
.optional()
|
|
859
|
+
.describe("Include custom attributes"),
|
|
860
|
+
with_security_reports: z
|
|
861
|
+
.boolean()
|
|
862
|
+
.optional()
|
|
863
|
+
.describe("Include security reports"),
|
|
864
|
+
});
|
|
865
|
+
// Add wiki operation schemas
|
|
866
|
+
export const ListWikiPagesSchema = z.object({
|
|
867
|
+
project_id: z.string().describe("Project ID or URL-encoded path"),
|
|
868
|
+
page: z.number().optional().describe("Page number for pagination"),
|
|
869
|
+
per_page: z.number().optional().describe("Number of items per page"),
|
|
870
|
+
});
|
|
871
|
+
export const GetWikiPageSchema = z.object({
|
|
872
|
+
project_id: z.string().describe("Project ID or URL-encoded path"),
|
|
873
|
+
slug: z.string().describe("URL-encoded slug of the wiki page"),
|
|
874
|
+
});
|
|
875
|
+
export const CreateWikiPageSchema = z.object({
|
|
876
|
+
project_id: z.string().describe("Project ID or URL-encoded path"),
|
|
877
|
+
title: z.string().describe("Title of the wiki page"),
|
|
878
|
+
content: z.string().describe("Content of the wiki page"),
|
|
879
|
+
format: z
|
|
880
|
+
.string()
|
|
881
|
+
.optional()
|
|
882
|
+
.describe("Content format, e.g., markdown, rdoc"),
|
|
883
|
+
});
|
|
884
|
+
export const UpdateWikiPageSchema = z.object({
|
|
885
|
+
project_id: z.string().describe("Project ID or URL-encoded path"),
|
|
886
|
+
slug: z.string().describe("URL-encoded slug of the wiki page"),
|
|
887
|
+
title: z.string().optional().describe("New title of the wiki page"),
|
|
888
|
+
content: z.string().optional().describe("New content of the wiki page"),
|
|
889
|
+
format: z
|
|
890
|
+
.string()
|
|
891
|
+
.optional()
|
|
892
|
+
.describe("Content format, e.g., markdown, rdoc"),
|
|
893
|
+
});
|
|
894
|
+
export const DeleteWikiPageSchema = z.object({
|
|
895
|
+
project_id: z.string().describe("Project ID or URL-encoded path"),
|
|
896
|
+
slug: z.string().describe("URL-encoded slug of the wiki page"),
|
|
897
|
+
});
|
|
898
|
+
// Define wiki response schemas
|
|
899
|
+
export const GitLabWikiPageSchema = z.object({
|
|
900
|
+
title: z.string(),
|
|
901
|
+
slug: z.string(),
|
|
902
|
+
format: z.string(),
|
|
903
|
+
content: z.string(),
|
|
904
|
+
created_at: z.string().optional(),
|
|
905
|
+
updated_at: z.string().optional(),
|
|
684
906
|
});
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
5
|
+
const __dirname = path.dirname(__filename);
|
|
6
|
+
async function main() {
|
|
7
|
+
const repoRoot = path.resolve(__dirname, '..');
|
|
8
|
+
const indexPath = path.join(repoRoot, 'index.ts');
|
|
9
|
+
const readmePath = path.join(repoRoot, 'README.md');
|
|
10
|
+
// 1. Read index.ts
|
|
11
|
+
const code = fs.readFileSync(indexPath, 'utf-8');
|
|
12
|
+
// 2. Extract allTools array block
|
|
13
|
+
const match = code.match(/const allTools = \[([\s\S]*?)\];/);
|
|
14
|
+
if (!match) {
|
|
15
|
+
console.error('Unable to locate allTools array in index.ts');
|
|
16
|
+
process.exit(1);
|
|
17
|
+
}
|
|
18
|
+
const toolsBlock = match[1];
|
|
19
|
+
// 3. Parse tool entries
|
|
20
|
+
const toolRegex = /name:\s*"([^"]+)",[\s\S]*?description:\s*"([^"]+)"/g;
|
|
21
|
+
const tools = [];
|
|
22
|
+
let m;
|
|
23
|
+
while ((m = toolRegex.exec(toolsBlock)) !== null) {
|
|
24
|
+
tools.push({ name: m[1], description: m[2] });
|
|
25
|
+
}
|
|
26
|
+
// 4. Generate markdown
|
|
27
|
+
const lines = tools.map((tool, index) => {
|
|
28
|
+
return `${index + 1}. \`${tool.name}\` - ${tool.description}`;
|
|
29
|
+
});
|
|
30
|
+
const markdown = lines.join('\n');
|
|
31
|
+
// 5. Read README.md and replace between markers
|
|
32
|
+
const readme = fs.readFileSync(readmePath, 'utf-8');
|
|
33
|
+
const updated = readme.replace(/<!-- TOOLS-START -->([\s\S]*?)<!-- TOOLS-END -->/, `<!-- TOOLS-START -->\n${markdown}\n<!-- TOOLS-END -->`);
|
|
34
|
+
// 6. Write back
|
|
35
|
+
fs.writeFileSync(readmePath, updated, 'utf-8');
|
|
36
|
+
console.log('README.md tools section updated.');
|
|
37
|
+
}
|
|
38
|
+
main().catch(err => {
|
|
39
|
+
console.error(err);
|
|
40
|
+
process.exit(1);
|
|
41
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zereight/mcp-gitlab",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.33",
|
|
4
4
|
"description": "MCP server for using the GitLab API",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "zereight",
|
|
@@ -19,10 +19,12 @@
|
|
|
19
19
|
"build": "tsc && node -e \"require('fs').chmodSync('build/index.js', '755')\"",
|
|
20
20
|
"prepare": "npm run build",
|
|
21
21
|
"watch": "tsc --watch",
|
|
22
|
-
"deploy": "npm publish --access public"
|
|
22
|
+
"deploy": "npm publish --access public",
|
|
23
|
+
"generate-tools": "npx ts-node scripts/generate-tools-readme.ts"
|
|
23
24
|
},
|
|
24
25
|
"dependencies": {
|
|
25
26
|
"@modelcontextprotocol/sdk": "1.8.0",
|
|
27
|
+
"form-data": "^4.0.0",
|
|
26
28
|
"@types/node-fetch": "^2.6.12",
|
|
27
29
|
"http-proxy-agent": "^7.0.2",
|
|
28
30
|
"https-proxy-agent": "^7.0.6",
|