@zereight/mcp-gitlab 1.0.32 â 1.0.34
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 +133 -36
- package/build/schemas.js +279 -84
- package/build/scripts/generate-tools-readme.js +41 -0
- package/package.json +3 -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,21 +3,21 @@ 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
|
|
15
|
+
import { URL } from "url";
|
|
16
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
|
|
20
|
-
ListMergeRequestDiscussionsSchema, } from "./schemas.js";
|
|
20
|
+
ListMergeRequestDiscussionsSchema, GitLabTreeItemSchema, GetRepositoryTreeSchema, } from "./schemas.js";
|
|
21
21
|
/**
|
|
22
22
|
* Read version from package.json
|
|
23
23
|
*/
|
|
@@ -52,7 +52,7 @@ const HTTPS_PROXY = process.env.HTTPS_PROXY;
|
|
|
52
52
|
let httpAgent = undefined;
|
|
53
53
|
let httpsAgent = undefined;
|
|
54
54
|
if (HTTP_PROXY) {
|
|
55
|
-
if (HTTP_PROXY.startsWith(
|
|
55
|
+
if (HTTP_PROXY.startsWith("socks")) {
|
|
56
56
|
httpAgent = new SocksProxyAgent(HTTP_PROXY);
|
|
57
57
|
}
|
|
58
58
|
else {
|
|
@@ -60,7 +60,7 @@ if (HTTP_PROXY) {
|
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
62
|
if (HTTPS_PROXY) {
|
|
63
|
-
if (HTTPS_PROXY.startsWith(
|
|
63
|
+
if (HTTPS_PROXY.startsWith("socks")) {
|
|
64
64
|
httpsAgent = new SocksProxyAgent(HTTPS_PROXY);
|
|
65
65
|
}
|
|
66
66
|
else {
|
|
@@ -77,11 +77,11 @@ const DEFAULT_HEADERS = {
|
|
|
77
77
|
const DEFAULT_FETCH_CONFIG = {
|
|
78
78
|
headers: DEFAULT_HEADERS,
|
|
79
79
|
agent: (parsedUrl) => {
|
|
80
|
-
if (parsedUrl.protocol ===
|
|
80
|
+
if (parsedUrl.protocol === "https:") {
|
|
81
81
|
return httpsAgent;
|
|
82
82
|
}
|
|
83
83
|
return httpAgent;
|
|
84
|
-
}
|
|
84
|
+
},
|
|
85
85
|
};
|
|
86
86
|
// Define all available tools
|
|
87
87
|
const allTools = [
|
|
@@ -132,17 +132,17 @@ const allTools = [
|
|
|
132
132
|
},
|
|
133
133
|
{
|
|
134
134
|
name: "get_merge_request",
|
|
135
|
-
description: "Get details of a merge request",
|
|
135
|
+
description: "Get details of a merge request (Either mergeRequestIid or branchName must be provided)",
|
|
136
136
|
inputSchema: zodToJsonSchema(GetMergeRequestSchema),
|
|
137
137
|
},
|
|
138
138
|
{
|
|
139
139
|
name: "get_merge_request_diffs",
|
|
140
|
-
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)",
|
|
141
141
|
inputSchema: zodToJsonSchema(GetMergeRequestDiffsSchema),
|
|
142
142
|
},
|
|
143
143
|
{
|
|
144
144
|
name: "update_merge_request",
|
|
145
|
-
description: "Update a merge request",
|
|
145
|
+
description: "Update a merge request (Either mergeRequestIid or branchName must be provided)",
|
|
146
146
|
inputSchema: zodToJsonSchema(UpdateMergeRequestSchema),
|
|
147
147
|
},
|
|
148
148
|
{
|
|
@@ -279,7 +279,12 @@ const allTools = [
|
|
|
279
279
|
name: "delete_wiki_page",
|
|
280
280
|
description: "Delete a wiki page from a GitLab project",
|
|
281
281
|
inputSchema: zodToJsonSchema(DeleteWikiPageSchema),
|
|
282
|
-
}
|
|
282
|
+
},
|
|
283
|
+
{
|
|
284
|
+
name: "get_repository_tree",
|
|
285
|
+
description: "Get the repository tree for a GitLab project (list files and directories)",
|
|
286
|
+
inputSchema: zodToJsonSchema(GetRepositoryTreeSchema),
|
|
287
|
+
},
|
|
283
288
|
];
|
|
284
289
|
// Define which tools are read-only
|
|
285
290
|
const readOnlyTools = [
|
|
@@ -347,7 +352,8 @@ async function handleGitLabError(response) {
|
|
|
347
352
|
if (!response.ok) {
|
|
348
353
|
const errorBody = await response.text();
|
|
349
354
|
// Check specifically for Rate Limit error
|
|
350
|
-
if (response.status === 403 &&
|
|
355
|
+
if (response.status === 403 &&
|
|
356
|
+
errorBody.includes("User API Key Rate limit exceeded")) {
|
|
351
357
|
console.error("GitLab API Rate Limit Exceeded:", errorBody);
|
|
352
358
|
console.log("User API Key Rate limit exceeded. Please try again later.");
|
|
353
359
|
throw new Error(`GitLab API Rate Limit Exceeded: ${errorBody}`);
|
|
@@ -937,27 +943,50 @@ async function createRepository(options) {
|
|
|
937
943
|
* MR ėĄ°í í¨ė (Function to retrieve merge request)
|
|
938
944
|
*
|
|
939
945
|
* @param {string} projectId - The ID or URL-encoded path of the project
|
|
940
|
-
* @param {number} mergeRequestIid - The internal ID of the merge request
|
|
946
|
+
* @param {number} mergeRequestIid - The internal ID of the merge request (Optional)
|
|
947
|
+
* @param {string} [branchName] - The name of the branch to search for merge request by branch name (Optional)
|
|
941
948
|
* @returns {Promise<GitLabMergeRequest>} The merge request details
|
|
942
949
|
*/
|
|
943
|
-
async function getMergeRequest(projectId, mergeRequestIid) {
|
|
944
|
-
|
|
950
|
+
async function getMergeRequest(projectId, mergeRequestIid, branchName) {
|
|
951
|
+
let url;
|
|
952
|
+
if (mergeRequestIid) {
|
|
953
|
+
url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/merge_requests/${mergeRequestIid}`);
|
|
954
|
+
}
|
|
955
|
+
else if (branchName) {
|
|
956
|
+
url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/merge_requests?source_branch=${encodeURIComponent(branchName)}`);
|
|
957
|
+
}
|
|
958
|
+
else {
|
|
959
|
+
throw new Error("Either mergeRequestIid or branchName must be provided");
|
|
960
|
+
}
|
|
945
961
|
const response = await fetch(url.toString(), {
|
|
946
962
|
...DEFAULT_FETCH_CONFIG,
|
|
947
963
|
});
|
|
948
964
|
await handleGitLabError(response);
|
|
949
|
-
|
|
965
|
+
const data = await response.json();
|
|
966
|
+
// If response is an array (Comes from branchName search), return the first item if exist
|
|
967
|
+
if (Array.isArray(data) && data.length > 0) {
|
|
968
|
+
return GitLabMergeRequestSchema.parse(data[0]);
|
|
969
|
+
}
|
|
970
|
+
return GitLabMergeRequestSchema.parse(data);
|
|
950
971
|
}
|
|
951
972
|
/**
|
|
952
973
|
* Get merge request changes/diffs
|
|
953
974
|
* MR ëŗę˛ŊėŦí ėĄ°í í¨ė (Function to retrieve merge request changes)
|
|
954
975
|
*
|
|
955
976
|
* @param {string} projectId - The ID or URL-encoded path of the project
|
|
956
|
-
* @param {number} mergeRequestIid - The internal ID of the merge request
|
|
977
|
+
* @param {number} mergeRequestIid - The internal ID of the merge request (Either mergeRequestIid or branchName must be provided)
|
|
978
|
+
* @param {string} [branchName] - The name of the branch to search for merge request by branch name (Either mergeRequestIid or branchName must be provided)
|
|
957
979
|
* @param {string} [view] - The view type for the diff (inline or parallel)
|
|
958
980
|
* @returns {Promise<GitLabMergeRequestDiff[]>} The merge request diffs
|
|
959
981
|
*/
|
|
960
|
-
async function getMergeRequestDiffs(projectId, mergeRequestIid, view) {
|
|
982
|
+
async function getMergeRequestDiffs(projectId, mergeRequestIid, branchName, view) {
|
|
983
|
+
if (!mergeRequestIid && !branchName) {
|
|
984
|
+
throw new Error("Either mergeRequestIid or branchName must be provided");
|
|
985
|
+
}
|
|
986
|
+
if (branchName && !mergeRequestIid) {
|
|
987
|
+
const mergeRequest = await getMergeRequest(projectId, undefined, branchName);
|
|
988
|
+
mergeRequestIid = mergeRequest.iid;
|
|
989
|
+
}
|
|
961
990
|
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/merge_requests/${mergeRequestIid}/changes`);
|
|
962
991
|
if (view) {
|
|
963
992
|
url.searchParams.append("view", view);
|
|
@@ -974,11 +1003,19 @@ async function getMergeRequestDiffs(projectId, mergeRequestIid, view) {
|
|
|
974
1003
|
* MR ė
ë°ė´í¸ í¨ė (Function to update merge request)
|
|
975
1004
|
*
|
|
976
1005
|
* @param {string} projectId - The ID or URL-encoded path of the project
|
|
977
|
-
* @param {number} mergeRequestIid - The internal ID of the merge request
|
|
1006
|
+
* @param {number} mergeRequestIid - The internal ID of the merge request (Optional)
|
|
1007
|
+
* @param {string} branchName - The name of the branch to search for merge request by branch name (Optional)
|
|
978
1008
|
* @param {Object} options - The update options
|
|
979
1009
|
* @returns {Promise<GitLabMergeRequest>} The updated merge request
|
|
980
1010
|
*/
|
|
981
|
-
async function updateMergeRequest(projectId, mergeRequestIid,
|
|
1011
|
+
async function updateMergeRequest(projectId, options, mergeRequestIid, branchName) {
|
|
1012
|
+
if (!mergeRequestIid && !branchName) {
|
|
1013
|
+
throw new Error("Either mergeRequestIid or branchName must be provided");
|
|
1014
|
+
}
|
|
1015
|
+
if (branchName && !mergeRequestIid) {
|
|
1016
|
+
const mergeRequest = await getMergeRequest(projectId, undefined, branchName);
|
|
1017
|
+
mergeRequestIid = mergeRequest.iid;
|
|
1018
|
+
}
|
|
982
1019
|
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/merge_requests/${mergeRequestIid}`);
|
|
983
1020
|
const response = await fetch(url.toString(), {
|
|
984
1021
|
...DEFAULT_FETCH_CONFIG,
|
|
@@ -1304,9 +1341,9 @@ async function listGroupProjects(options) {
|
|
|
1304
1341
|
async function listWikiPages(projectId, options = {}) {
|
|
1305
1342
|
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/wikis`);
|
|
1306
1343
|
if (options.page)
|
|
1307
|
-
url.searchParams.append(
|
|
1344
|
+
url.searchParams.append("page", options.page.toString());
|
|
1308
1345
|
if (options.per_page)
|
|
1309
|
-
url.searchParams.append(
|
|
1346
|
+
url.searchParams.append("per_page", options.per_page.toString());
|
|
1310
1347
|
const response = await fetch(url.toString(), {
|
|
1311
1348
|
...DEFAULT_FETCH_CONFIG,
|
|
1312
1349
|
});
|
|
@@ -1332,7 +1369,7 @@ async function createWikiPage(projectId, title, content, format) {
|
|
|
1332
1369
|
body.format = format;
|
|
1333
1370
|
const response = await fetch(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/wikis`, {
|
|
1334
1371
|
...DEFAULT_FETCH_CONFIG,
|
|
1335
|
-
method:
|
|
1372
|
+
method: "POST",
|
|
1336
1373
|
body: JSON.stringify(body),
|
|
1337
1374
|
});
|
|
1338
1375
|
await handleGitLabError(response);
|
|
@@ -1352,7 +1389,7 @@ async function updateWikiPage(projectId, slug, title, content, format) {
|
|
|
1352
1389
|
body.format = format;
|
|
1353
1390
|
const response = await fetch(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/wikis/${encodeURIComponent(slug)}`, {
|
|
1354
1391
|
...DEFAULT_FETCH_CONFIG,
|
|
1355
|
-
method:
|
|
1392
|
+
method: "PUT",
|
|
1356
1393
|
body: JSON.stringify(body),
|
|
1357
1394
|
});
|
|
1358
1395
|
await handleGitLabError(response);
|
|
@@ -1365,10 +1402,45 @@ async function updateWikiPage(projectId, slug, title, content, format) {
|
|
|
1365
1402
|
async function deleteWikiPage(projectId, slug) {
|
|
1366
1403
|
const response = await fetch(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/wikis/${encodeURIComponent(slug)}`, {
|
|
1367
1404
|
...DEFAULT_FETCH_CONFIG,
|
|
1368
|
-
method:
|
|
1405
|
+
method: "DELETE",
|
|
1369
1406
|
});
|
|
1370
1407
|
await handleGitLabError(response);
|
|
1371
1408
|
}
|
|
1409
|
+
/**
|
|
1410
|
+
* Get the repository tree for a project
|
|
1411
|
+
* @param {string} projectId - The ID or URL-encoded path of the project
|
|
1412
|
+
* @param {GetRepositoryTreeOptions} options - Options for the tree
|
|
1413
|
+
* @returns {Promise<GitLabTreeItem[]>}
|
|
1414
|
+
*/
|
|
1415
|
+
async function getRepositoryTree(options) {
|
|
1416
|
+
const queryParams = new URLSearchParams();
|
|
1417
|
+
if (options.path)
|
|
1418
|
+
queryParams.append("path", options.path);
|
|
1419
|
+
if (options.ref)
|
|
1420
|
+
queryParams.append("ref", options.ref);
|
|
1421
|
+
if (options.recursive)
|
|
1422
|
+
queryParams.append("recursive", "true");
|
|
1423
|
+
if (options.per_page)
|
|
1424
|
+
queryParams.append("per_page", options.per_page.toString());
|
|
1425
|
+
if (options.page_token)
|
|
1426
|
+
queryParams.append("page_token", options.page_token);
|
|
1427
|
+
if (options.pagination)
|
|
1428
|
+
queryParams.append("pagination", options.pagination);
|
|
1429
|
+
const response = await fetch(`${GITLAB_API_URL}/projects/${encodeURIComponent(options.project_id)}/repository/tree?${queryParams.toString()}`, {
|
|
1430
|
+
headers: {
|
|
1431
|
+
Authorization: `Bearer ${GITLAB_PERSONAL_ACCESS_TOKEN}`,
|
|
1432
|
+
"Content-Type": "application/json",
|
|
1433
|
+
},
|
|
1434
|
+
});
|
|
1435
|
+
if (response.status === 404) {
|
|
1436
|
+
throw new Error("Repository or path not found");
|
|
1437
|
+
}
|
|
1438
|
+
if (!response.ok) {
|
|
1439
|
+
throw new Error(`Failed to get repository tree: ${response.statusText}`);
|
|
1440
|
+
}
|
|
1441
|
+
const data = await response.json();
|
|
1442
|
+
return z.array(GitLabTreeItemSchema).parse(data);
|
|
1443
|
+
}
|
|
1372
1444
|
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
1373
1445
|
// Apply read-only filter first
|
|
1374
1446
|
const tools0 = GITLAB_READ_ONLY_MODE
|
|
@@ -1493,7 +1565,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1493
1565
|
}
|
|
1494
1566
|
case "get_merge_request": {
|
|
1495
1567
|
const args = GetMergeRequestSchema.parse(request.params.arguments);
|
|
1496
|
-
const mergeRequest = await getMergeRequest(args.project_id, args.merge_request_iid);
|
|
1568
|
+
const mergeRequest = await getMergeRequest(args.project_id, args.merge_request_iid, args.source_branch);
|
|
1497
1569
|
return {
|
|
1498
1570
|
content: [
|
|
1499
1571
|
{ type: "text", text: JSON.stringify(mergeRequest, null, 2) },
|
|
@@ -1502,15 +1574,15 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1502
1574
|
}
|
|
1503
1575
|
case "get_merge_request_diffs": {
|
|
1504
1576
|
const args = GetMergeRequestDiffsSchema.parse(request.params.arguments);
|
|
1505
|
-
const diffs = await getMergeRequestDiffs(args.project_id, args.merge_request_iid, args.view);
|
|
1577
|
+
const diffs = await getMergeRequestDiffs(args.project_id, args.merge_request_iid, args.source_branch, args.view);
|
|
1506
1578
|
return {
|
|
1507
1579
|
content: [{ type: "text", text: JSON.stringify(diffs, null, 2) }],
|
|
1508
1580
|
};
|
|
1509
1581
|
}
|
|
1510
1582
|
case "update_merge_request": {
|
|
1511
1583
|
const args = UpdateMergeRequestSchema.parse(request.params.arguments);
|
|
1512
|
-
const { project_id, merge_request_iid, ...options } = args;
|
|
1513
|
-
const mergeRequest = await updateMergeRequest(project_id, merge_request_iid,
|
|
1584
|
+
const { project_id, merge_request_iid, source_branch, ...options } = args;
|
|
1585
|
+
const mergeRequest = await updateMergeRequest(project_id, options, merge_request_iid, source_branch);
|
|
1514
1586
|
return {
|
|
1515
1587
|
content: [
|
|
1516
1588
|
{ type: "text", text: JSON.stringify(mergeRequest, null, 2) },
|
|
@@ -1731,27 +1803,52 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1731
1803
|
case "list_wiki_pages": {
|
|
1732
1804
|
const { project_id, page, per_page } = ListWikiPagesSchema.parse(request.params.arguments);
|
|
1733
1805
|
const wikiPages = await listWikiPages(project_id, { page, per_page });
|
|
1734
|
-
return {
|
|
1806
|
+
return {
|
|
1807
|
+
content: [{ type: "text", text: JSON.stringify(wikiPages, null, 2) }],
|
|
1808
|
+
};
|
|
1735
1809
|
}
|
|
1736
1810
|
case "get_wiki_page": {
|
|
1737
1811
|
const { project_id, slug } = GetWikiPageSchema.parse(request.params.arguments);
|
|
1738
1812
|
const wikiPage = await getWikiPage(project_id, slug);
|
|
1739
|
-
return {
|
|
1813
|
+
return {
|
|
1814
|
+
content: [{ type: "text", text: JSON.stringify(wikiPage, null, 2) }],
|
|
1815
|
+
};
|
|
1740
1816
|
}
|
|
1741
1817
|
case "create_wiki_page": {
|
|
1742
1818
|
const { project_id, title, content, format } = CreateWikiPageSchema.parse(request.params.arguments);
|
|
1743
1819
|
const wikiPage = await createWikiPage(project_id, title, content, format);
|
|
1744
|
-
return {
|
|
1820
|
+
return {
|
|
1821
|
+
content: [{ type: "text", text: JSON.stringify(wikiPage, null, 2) }],
|
|
1822
|
+
};
|
|
1745
1823
|
}
|
|
1746
1824
|
case "update_wiki_page": {
|
|
1747
1825
|
const { project_id, slug, title, content, format } = UpdateWikiPageSchema.parse(request.params.arguments);
|
|
1748
1826
|
const wikiPage = await updateWikiPage(project_id, slug, title, content, format);
|
|
1749
|
-
return {
|
|
1827
|
+
return {
|
|
1828
|
+
content: [{ type: "text", text: JSON.stringify(wikiPage, null, 2) }],
|
|
1829
|
+
};
|
|
1750
1830
|
}
|
|
1751
1831
|
case "delete_wiki_page": {
|
|
1752
1832
|
const { project_id, slug } = DeleteWikiPageSchema.parse(request.params.arguments);
|
|
1753
1833
|
await deleteWikiPage(project_id, slug);
|
|
1754
|
-
return {
|
|
1834
|
+
return {
|
|
1835
|
+
content: [
|
|
1836
|
+
{
|
|
1837
|
+
type: "text",
|
|
1838
|
+
text: JSON.stringify({
|
|
1839
|
+
status: "success",
|
|
1840
|
+
message: "Wiki page deleted successfully",
|
|
1841
|
+
}, null, 2),
|
|
1842
|
+
},
|
|
1843
|
+
],
|
|
1844
|
+
};
|
|
1845
|
+
}
|
|
1846
|
+
case "get_repository_tree": {
|
|
1847
|
+
const args = GetRepositoryTreeSchema.parse(request.params.arguments);
|
|
1848
|
+
const tree = await getRepositoryTree(args);
|
|
1849
|
+
return {
|
|
1850
|
+
content: [{ type: "text", text: JSON.stringify(tree, null, 2) }],
|
|
1851
|
+
};
|
|
1755
1852
|
}
|
|
1756
1853
|
default:
|
|
1757
1854
|
throw new Error(`Unknown tool: ${request.params.name}`);
|
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;
|
|
@@ -134,16 +146,25 @@ export const FileOperationSchema = z.object({
|
|
|
134
146
|
content: z.string(),
|
|
135
147
|
});
|
|
136
148
|
// Tree and commit schemas
|
|
137
|
-
export const
|
|
138
|
-
id: z.string(),
|
|
149
|
+
export const GitLabTreeItemSchema = z.object({
|
|
150
|
+
id: z.string(),
|
|
139
151
|
name: z.string(),
|
|
140
|
-
type: z.enum(["
|
|
152
|
+
type: z.enum(["tree", "blob"]),
|
|
141
153
|
path: z.string(),
|
|
142
154
|
mode: z.string(),
|
|
143
155
|
});
|
|
156
|
+
export const GetRepositoryTreeSchema = z.object({
|
|
157
|
+
project_id: z.string().describe("The ID or URL-encoded path of the project"),
|
|
158
|
+
path: z.string().optional().describe("The path inside the repository"),
|
|
159
|
+
ref: z.string().optional().describe("The name of a repository branch or tag. Defaults to the default branch."),
|
|
160
|
+
recursive: z.boolean().optional().describe("Boolean value to get a recursive tree"),
|
|
161
|
+
per_page: z.number().optional().describe("Number of results to show per page"),
|
|
162
|
+
page_token: z.string().optional().describe("The tree record ID for pagination"),
|
|
163
|
+
pagination: z.string().optional().describe("Pagination method (keyset)")
|
|
164
|
+
});
|
|
144
165
|
export const GitLabTreeSchema = z.object({
|
|
145
166
|
id: z.string(), // Changed from sha to match GitLab API
|
|
146
|
-
tree: z.array(
|
|
167
|
+
tree: z.array(GitLabTreeItemSchema),
|
|
147
168
|
});
|
|
148
169
|
export const GitLabCommitSchema = z.object({
|
|
149
170
|
id: z.string(), // Changed from sha to match GitLab API
|
|
@@ -251,17 +272,21 @@ export const GitLabIssueSchema = z.object({
|
|
|
251
272
|
updated_at: z.string(),
|
|
252
273
|
closed_at: z.string().nullable(),
|
|
253
274
|
web_url: z.string(), // Changed from html_url to match GitLab API
|
|
254
|
-
references: z
|
|
275
|
+
references: z
|
|
276
|
+
.object({
|
|
255
277
|
short: z.string(),
|
|
256
278
|
relative: z.string(),
|
|
257
279
|
full: z.string(),
|
|
258
|
-
})
|
|
259
|
-
|
|
280
|
+
})
|
|
281
|
+
.optional(),
|
|
282
|
+
time_stats: z
|
|
283
|
+
.object({
|
|
260
284
|
time_estimate: z.number(),
|
|
261
285
|
total_time_spent: z.number(),
|
|
262
286
|
human_time_estimate: z.string().nullable(),
|
|
263
287
|
human_total_time_spent: z.string().nullable(),
|
|
264
|
-
})
|
|
288
|
+
})
|
|
289
|
+
.optional(),
|
|
265
290
|
confidential: z.boolean().optional(),
|
|
266
291
|
due_date: z.string().nullable().optional(),
|
|
267
292
|
discussion_locked: z.boolean().nullable().optional(),
|
|
@@ -270,7 +295,7 @@ export const GitLabIssueSchema = z.object({
|
|
|
270
295
|
// NEW SCHEMA: For issue with link details (used in listing issue links)
|
|
271
296
|
export const GitLabIssueWithLinkDetailsSchema = GitLabIssueSchema.extend({
|
|
272
297
|
issue_link_id: z.number(),
|
|
273
|
-
link_type: z.enum([
|
|
298
|
+
link_type: z.enum(["relates_to", "blocks", "is_blocked_by"]),
|
|
274
299
|
link_created_at: z.string(),
|
|
275
300
|
link_updated_at: z.string(),
|
|
276
301
|
});
|
|
@@ -278,11 +303,13 @@ export const GitLabIssueWithLinkDetailsSchema = GitLabIssueSchema.extend({
|
|
|
278
303
|
export const GitLabForkParentSchema = z.object({
|
|
279
304
|
name: z.string(),
|
|
280
305
|
path_with_namespace: z.string(), // Changed from full_name to match GitLab API
|
|
281
|
-
owner: z
|
|
306
|
+
owner: z
|
|
307
|
+
.object({
|
|
282
308
|
username: z.string(), // Changed from login to match GitLab API
|
|
283
309
|
id: z.number(),
|
|
284
310
|
avatar_url: z.string(),
|
|
285
|
-
})
|
|
311
|
+
})
|
|
312
|
+
.optional(), // Made optional to handle cases where GitLab API doesn't include it
|
|
286
313
|
web_url: z.string(), // Changed from html_url to match GitLab API
|
|
287
314
|
});
|
|
288
315
|
export const GitLabForkSchema = GitLabRepositorySchema.extend({
|
|
@@ -346,7 +373,9 @@ export const GitLabDiscussionNoteSchema = z.object({
|
|
|
346
373
|
resolved: z.boolean().optional(),
|
|
347
374
|
resolved_by: GitLabUserSchema.nullable().optional(),
|
|
348
375
|
resolved_at: z.string().nullable().optional(),
|
|
349
|
-
position: z
|
|
376
|
+
position: z
|
|
377
|
+
.object({
|
|
378
|
+
// Only present for DiffNote
|
|
350
379
|
base_sha: z.string(),
|
|
351
380
|
start_sha: z.string(),
|
|
352
381
|
head_sha: z.string(),
|
|
@@ -355,7 +384,8 @@ export const GitLabDiscussionNoteSchema = z.object({
|
|
|
355
384
|
position_type: z.enum(["text", "image", "file"]),
|
|
356
385
|
old_line: z.number().nullable(),
|
|
357
386
|
new_line: z.number().nullable(),
|
|
358
|
-
line_range: z
|
|
387
|
+
line_range: z
|
|
388
|
+
.object({
|
|
359
389
|
start: z.object({
|
|
360
390
|
line_code: z.string(),
|
|
361
391
|
type: z.enum(["new", "old"]),
|
|
@@ -368,12 +398,15 @@ export const GitLabDiscussionNoteSchema = z.object({
|
|
|
368
398
|
old_line: z.number().nullable(),
|
|
369
399
|
new_line: z.number().nullable(),
|
|
370
400
|
}),
|
|
371
|
-
})
|
|
401
|
+
})
|
|
402
|
+
.nullable()
|
|
403
|
+
.optional(), // For multi-line diff notes
|
|
372
404
|
width: z.number().optional(), // For image diff notes
|
|
373
405
|
height: z.number().optional(), // For image diff notes
|
|
374
406
|
x: z.number().optional(), // For image diff notes
|
|
375
407
|
y: z.number().optional(), // For image diff notes
|
|
376
|
-
})
|
|
408
|
+
})
|
|
409
|
+
.optional(),
|
|
377
410
|
});
|
|
378
411
|
export const GitLabDiscussionSchema = z.object({
|
|
379
412
|
id: z.string(),
|
|
@@ -402,10 +435,7 @@ export const CreateOrUpdateFileSchema = ProjectParamsSchema.extend({
|
|
|
402
435
|
.string()
|
|
403
436
|
.optional()
|
|
404
437
|
.describe("Path of the file to move/rename"),
|
|
405
|
-
last_commit_id: z
|
|
406
|
-
.string()
|
|
407
|
-
.optional()
|
|
408
|
-
.describe("Last known file commit ID"),
|
|
438
|
+
last_commit_id: z.string().optional().describe("Last known file commit ID"),
|
|
409
439
|
commit_id: z
|
|
410
440
|
.string()
|
|
411
441
|
.optional()
|
|
@@ -489,7 +519,9 @@ export const GitLabMergeRequestDiffSchema = z.object({
|
|
|
489
519
|
export const GetMergeRequestSchema = ProjectParamsSchema.extend({
|
|
490
520
|
merge_request_iid: z
|
|
491
521
|
.number()
|
|
492
|
-
.
|
|
522
|
+
.optional()
|
|
523
|
+
.describe("The IID of a merge request"),
|
|
524
|
+
source_branch: z.string().optional().describe("Source branch name"),
|
|
493
525
|
});
|
|
494
526
|
export const UpdateMergeRequestSchema = GetMergeRequestSchema.extend({
|
|
495
527
|
title: z.string().optional().describe("The title of the merge request"),
|
|
@@ -531,22 +563,61 @@ export const CreateNoteSchema = z.object({
|
|
|
531
563
|
// Issues API operation schemas
|
|
532
564
|
export const ListIssuesSchema = z.object({
|
|
533
565
|
project_id: z.string().describe("Project ID or URL-encoded path"),
|
|
534
|
-
assignee_id: z
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
566
|
+
assignee_id: z
|
|
567
|
+
.number()
|
|
568
|
+
.optional()
|
|
569
|
+
.describe("Return issues assigned to the given user ID"),
|
|
570
|
+
assignee_username: z
|
|
571
|
+
.string()
|
|
572
|
+
.optional()
|
|
573
|
+
.describe("Return issues assigned to the given username"),
|
|
574
|
+
author_id: z
|
|
575
|
+
.number()
|
|
576
|
+
.optional()
|
|
577
|
+
.describe("Return issues created by the given user ID"),
|
|
578
|
+
author_username: z
|
|
579
|
+
.string()
|
|
580
|
+
.optional()
|
|
581
|
+
.describe("Return issues created by the given username"),
|
|
582
|
+
confidential: z
|
|
583
|
+
.boolean()
|
|
584
|
+
.optional()
|
|
585
|
+
.describe("Filter confidential or public issues"),
|
|
586
|
+
created_after: z
|
|
587
|
+
.string()
|
|
588
|
+
.optional()
|
|
589
|
+
.describe("Return issues created after the given time"),
|
|
590
|
+
created_before: z
|
|
591
|
+
.string()
|
|
592
|
+
.optional()
|
|
593
|
+
.describe("Return issues created before the given time"),
|
|
594
|
+
due_date: z
|
|
595
|
+
.string()
|
|
596
|
+
.optional()
|
|
597
|
+
.describe("Return issues that have the due date"),
|
|
542
598
|
label_name: z.array(z.string()).optional().describe("Array of label names"),
|
|
543
599
|
milestone: z.string().optional().describe("Milestone title"),
|
|
544
|
-
scope: z
|
|
600
|
+
scope: z
|
|
601
|
+
.enum(["created-by-me", "assigned-to-me", "all"])
|
|
602
|
+
.optional()
|
|
603
|
+
.describe("Return issues from a specific scope"),
|
|
545
604
|
search: z.string().optional().describe("Search for specific terms"),
|
|
546
|
-
state: z
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
605
|
+
state: z
|
|
606
|
+
.enum(["opened", "closed", "all"])
|
|
607
|
+
.optional()
|
|
608
|
+
.describe("Return issues with a specific state"),
|
|
609
|
+
updated_after: z
|
|
610
|
+
.string()
|
|
611
|
+
.optional()
|
|
612
|
+
.describe("Return issues updated after the given time"),
|
|
613
|
+
updated_before: z
|
|
614
|
+
.string()
|
|
615
|
+
.optional()
|
|
616
|
+
.describe("Return issues updated before the given time"),
|
|
617
|
+
with_labels_details: z
|
|
618
|
+
.boolean()
|
|
619
|
+
.optional()
|
|
620
|
+
.describe("Return more details for each label"),
|
|
550
621
|
page: z.number().optional().describe("Page number for pagination"),
|
|
551
622
|
per_page: z.number().optional().describe("Number of items per page"),
|
|
552
623
|
});
|
|
@@ -559,13 +630,28 @@ export const UpdateIssueSchema = z.object({
|
|
|
559
630
|
issue_iid: z.number().describe("The internal ID of the project issue"),
|
|
560
631
|
title: z.string().optional().describe("The title of the issue"),
|
|
561
632
|
description: z.string().optional().describe("The description of the issue"),
|
|
562
|
-
assignee_ids: z
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
633
|
+
assignee_ids: z
|
|
634
|
+
.array(z.number())
|
|
635
|
+
.optional()
|
|
636
|
+
.describe("Array of user IDs to assign issue to"),
|
|
637
|
+
confidential: z
|
|
638
|
+
.boolean()
|
|
639
|
+
.optional()
|
|
640
|
+
.describe("Set the issue to be confidential"),
|
|
641
|
+
discussion_locked: z
|
|
642
|
+
.boolean()
|
|
643
|
+
.optional()
|
|
644
|
+
.describe("Flag to lock discussions"),
|
|
645
|
+
due_date: z
|
|
646
|
+
.string()
|
|
647
|
+
.optional()
|
|
648
|
+
.describe("Date the issue is due (YYYY-MM-DD)"),
|
|
566
649
|
labels: z.array(z.string()).optional().describe("Array of label names"),
|
|
567
650
|
milestone_id: z.number().optional().describe("Milestone ID to assign"),
|
|
568
|
-
state_event: z
|
|
651
|
+
state_event: z
|
|
652
|
+
.enum(["close", "reopen"])
|
|
653
|
+
.optional()
|
|
654
|
+
.describe("Update issue state (close/reopen)"),
|
|
569
655
|
weight: z.number().optional().describe("Weight of the issue (0-9)"),
|
|
570
656
|
});
|
|
571
657
|
export const DeleteIssueSchema = z.object({
|
|
@@ -576,7 +662,7 @@ export const DeleteIssueSchema = z.object({
|
|
|
576
662
|
export const GitLabIssueLinkSchema = z.object({
|
|
577
663
|
source_issue: GitLabIssueSchema,
|
|
578
664
|
target_issue: GitLabIssueSchema,
|
|
579
|
-
link_type: z.enum([
|
|
665
|
+
link_type: z.enum(["relates_to", "blocks", "is_blocked_by"]),
|
|
580
666
|
});
|
|
581
667
|
export const ListIssueLinksSchema = z.object({
|
|
582
668
|
project_id: z.string().describe("Project ID or URL-encoded path"),
|
|
@@ -590,9 +676,16 @@ export const GetIssueLinkSchema = z.object({
|
|
|
590
676
|
export const CreateIssueLinkSchema = z.object({
|
|
591
677
|
project_id: z.string().describe("Project ID or URL-encoded path"),
|
|
592
678
|
issue_iid: z.number().describe("The internal ID of a project's issue"),
|
|
593
|
-
target_project_id: z
|
|
594
|
-
|
|
595
|
-
|
|
679
|
+
target_project_id: z
|
|
680
|
+
.string()
|
|
681
|
+
.describe("The ID or URL-encoded path of a target project"),
|
|
682
|
+
target_issue_iid: z
|
|
683
|
+
.number()
|
|
684
|
+
.describe("The internal ID of a target project's issue"),
|
|
685
|
+
link_type: z
|
|
686
|
+
.enum(["relates_to", "blocks", "is_blocked_by"])
|
|
687
|
+
.optional()
|
|
688
|
+
.describe("The type of the relation, defaults to relates_to"),
|
|
596
689
|
});
|
|
597
690
|
export const DeleteIssueLinkSchema = z.object({
|
|
598
691
|
project_id: z.string().describe("Project ID or URL-encoded path"),
|
|
@@ -604,7 +697,10 @@ export const ListNamespacesSchema = z.object({
|
|
|
604
697
|
search: z.string().optional().describe("Search term for namespaces"),
|
|
605
698
|
page: z.number().optional().describe("Page number for pagination"),
|
|
606
699
|
per_page: z.number().optional().describe("Number of items per page"),
|
|
607
|
-
owned: z
|
|
700
|
+
owned: z
|
|
701
|
+
.boolean()
|
|
702
|
+
.optional()
|
|
703
|
+
.describe("Filter for namespaces owned by current user"),
|
|
608
704
|
});
|
|
609
705
|
export const GetNamespaceSchema = z.object({
|
|
610
706
|
namespace_id: z.string().describe("Namespace ID or full path"),
|
|
@@ -620,67 +716,160 @@ export const ListProjectsSchema = z.object({
|
|
|
620
716
|
search: z.string().optional().describe("Search term for projects"),
|
|
621
717
|
page: z.number().optional().describe("Page number for pagination"),
|
|
622
718
|
per_page: z.number().optional().describe("Number of items per page"),
|
|
623
|
-
|
|
624
|
-
|
|
719
|
+
search_namespaces: z
|
|
720
|
+
.boolean()
|
|
721
|
+
.optional()
|
|
722
|
+
.describe("Needs to be true if search is full path"),
|
|
723
|
+
owned: z
|
|
724
|
+
.boolean()
|
|
725
|
+
.optional()
|
|
726
|
+
.describe("Filter for projects owned by current user"),
|
|
727
|
+
membership: z
|
|
728
|
+
.boolean()
|
|
729
|
+
.optional()
|
|
730
|
+
.describe("Filter for projects where current user is a member"),
|
|
625
731
|
simple: z.boolean().optional().describe("Return only limited fields"),
|
|
626
732
|
archived: z.boolean().optional().describe("Filter for archived projects"),
|
|
627
|
-
visibility: z
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
733
|
+
visibility: z
|
|
734
|
+
.enum(["public", "internal", "private"])
|
|
735
|
+
.optional()
|
|
736
|
+
.describe("Filter by project visibility"),
|
|
737
|
+
order_by: z
|
|
738
|
+
.enum([
|
|
739
|
+
"id",
|
|
740
|
+
"name",
|
|
741
|
+
"path",
|
|
742
|
+
"created_at",
|
|
743
|
+
"updated_at",
|
|
744
|
+
"last_activity_at",
|
|
745
|
+
])
|
|
746
|
+
.optional()
|
|
747
|
+
.describe("Return projects ordered by field"),
|
|
748
|
+
sort: z
|
|
749
|
+
.enum(["asc", "desc"])
|
|
750
|
+
.optional()
|
|
751
|
+
.describe("Return projects sorted in ascending or descending order"),
|
|
752
|
+
with_issues_enabled: z
|
|
753
|
+
.boolean()
|
|
754
|
+
.optional()
|
|
755
|
+
.describe("Filter projects with issues feature enabled"),
|
|
756
|
+
with_merge_requests_enabled: z
|
|
757
|
+
.boolean()
|
|
758
|
+
.optional()
|
|
759
|
+
.describe("Filter projects with merge requests feature enabled"),
|
|
760
|
+
min_access_level: z
|
|
761
|
+
.number()
|
|
762
|
+
.optional()
|
|
763
|
+
.describe("Filter by minimum access level"),
|
|
633
764
|
});
|
|
634
765
|
// Label operation schemas
|
|
635
766
|
export const ListLabelsSchema = z.object({
|
|
636
767
|
project_id: z.string().describe("Project ID or URL-encoded path"),
|
|
637
|
-
with_counts: z
|
|
638
|
-
|
|
768
|
+
with_counts: z
|
|
769
|
+
.boolean()
|
|
770
|
+
.optional()
|
|
771
|
+
.describe("Whether or not to include issue and merge request counts"),
|
|
772
|
+
include_ancestor_groups: z
|
|
773
|
+
.boolean()
|
|
774
|
+
.optional()
|
|
775
|
+
.describe("Include ancestor groups"),
|
|
639
776
|
search: z.string().optional().describe("Keyword to filter labels by"),
|
|
640
777
|
});
|
|
641
778
|
export const GetLabelSchema = z.object({
|
|
642
779
|
project_id: z.string().describe("Project ID or URL-encoded path"),
|
|
643
|
-
label_id: z
|
|
644
|
-
|
|
780
|
+
label_id: z
|
|
781
|
+
.union([z.number(), z.string()])
|
|
782
|
+
.describe("The ID or title of a project's label"),
|
|
783
|
+
include_ancestor_groups: z
|
|
784
|
+
.boolean()
|
|
785
|
+
.optional()
|
|
786
|
+
.describe("Include ancestor groups"),
|
|
645
787
|
});
|
|
646
788
|
export const CreateLabelSchema = z.object({
|
|
647
789
|
project_id: z.string().describe("Project ID or URL-encoded path"),
|
|
648
790
|
name: z.string().describe("The name of the label"),
|
|
649
|
-
color: z
|
|
791
|
+
color: z
|
|
792
|
+
.string()
|
|
793
|
+
.describe("The color of the label given in 6-digit hex notation with leading '#' sign"),
|
|
650
794
|
description: z.string().optional().describe("The description of the label"),
|
|
651
|
-
priority: z
|
|
795
|
+
priority: z
|
|
796
|
+
.number()
|
|
797
|
+
.nullable()
|
|
798
|
+
.optional()
|
|
799
|
+
.describe("The priority of the label"),
|
|
652
800
|
});
|
|
653
801
|
export const UpdateLabelSchema = z.object({
|
|
654
802
|
project_id: z.string().describe("Project ID or URL-encoded path"),
|
|
655
|
-
label_id: z
|
|
803
|
+
label_id: z
|
|
804
|
+
.union([z.number(), z.string()])
|
|
805
|
+
.describe("The ID or title of a project's label"),
|
|
656
806
|
new_name: z.string().optional().describe("The new name of the label"),
|
|
657
|
-
color: z
|
|
658
|
-
|
|
659
|
-
|
|
807
|
+
color: z
|
|
808
|
+
.string()
|
|
809
|
+
.optional()
|
|
810
|
+
.describe("The color of the label given in 6-digit hex notation with leading '#' sign"),
|
|
811
|
+
description: z
|
|
812
|
+
.string()
|
|
813
|
+
.optional()
|
|
814
|
+
.describe("The new description of the label"),
|
|
815
|
+
priority: z
|
|
816
|
+
.number()
|
|
817
|
+
.nullable()
|
|
818
|
+
.optional()
|
|
819
|
+
.describe("The new priority of the label"),
|
|
660
820
|
});
|
|
661
821
|
export const DeleteLabelSchema = z.object({
|
|
662
822
|
project_id: z.string().describe("Project ID or URL-encoded path"),
|
|
663
|
-
label_id: z
|
|
823
|
+
label_id: z
|
|
824
|
+
.union([z.number(), z.string()])
|
|
825
|
+
.describe("The ID or title of a project's label"),
|
|
664
826
|
});
|
|
665
827
|
// Group projects schema
|
|
666
828
|
export const ListGroupProjectsSchema = z.object({
|
|
667
829
|
group_id: z.string().describe("Group ID or path"),
|
|
668
|
-
include_subgroups: z
|
|
830
|
+
include_subgroups: z
|
|
831
|
+
.boolean()
|
|
832
|
+
.optional()
|
|
833
|
+
.describe("Include projects from subgroups"),
|
|
669
834
|
search: z.string().optional().describe("Search term to filter projects"),
|
|
670
|
-
order_by: z
|
|
671
|
-
|
|
835
|
+
order_by: z
|
|
836
|
+
.enum(["name", "path", "created_at", "updated_at", "last_activity_at"])
|
|
837
|
+
.optional()
|
|
838
|
+
.describe("Field to sort by"),
|
|
839
|
+
sort: z.enum(["asc", "desc"]).optional().describe("Sort direction"),
|
|
672
840
|
page: z.number().optional().describe("Page number"),
|
|
673
841
|
per_page: z.number().optional().describe("Number of results per page"),
|
|
674
842
|
archived: z.boolean().optional().describe("Filter for archived projects"),
|
|
675
|
-
visibility: z
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
843
|
+
visibility: z
|
|
844
|
+
.enum(["public", "internal", "private"])
|
|
845
|
+
.optional()
|
|
846
|
+
.describe("Filter by project visibility"),
|
|
847
|
+
with_issues_enabled: z
|
|
848
|
+
.boolean()
|
|
849
|
+
.optional()
|
|
850
|
+
.describe("Filter projects with issues feature enabled"),
|
|
851
|
+
with_merge_requests_enabled: z
|
|
852
|
+
.boolean()
|
|
853
|
+
.optional()
|
|
854
|
+
.describe("Filter projects with merge requests feature enabled"),
|
|
855
|
+
min_access_level: z
|
|
856
|
+
.number()
|
|
857
|
+
.optional()
|
|
858
|
+
.describe("Filter by minimum access level"),
|
|
859
|
+
with_programming_language: z
|
|
860
|
+
.string()
|
|
861
|
+
.optional()
|
|
862
|
+
.describe("Filter by programming language"),
|
|
680
863
|
starred: z.boolean().optional().describe("Filter by starred projects"),
|
|
681
864
|
statistics: z.boolean().optional().describe("Include project statistics"),
|
|
682
|
-
with_custom_attributes: z
|
|
683
|
-
|
|
865
|
+
with_custom_attributes: z
|
|
866
|
+
.boolean()
|
|
867
|
+
.optional()
|
|
868
|
+
.describe("Include custom attributes"),
|
|
869
|
+
with_security_reports: z
|
|
870
|
+
.boolean()
|
|
871
|
+
.optional()
|
|
872
|
+
.describe("Include security reports"),
|
|
684
873
|
});
|
|
685
874
|
// Add wiki operation schemas
|
|
686
875
|
export const ListWikiPagesSchema = z.object({
|
|
@@ -696,14 +885,20 @@ export const CreateWikiPageSchema = z.object({
|
|
|
696
885
|
project_id: z.string().describe("Project ID or URL-encoded path"),
|
|
697
886
|
title: z.string().describe("Title of the wiki page"),
|
|
698
887
|
content: z.string().describe("Content of the wiki page"),
|
|
699
|
-
format: z
|
|
888
|
+
format: z
|
|
889
|
+
.string()
|
|
890
|
+
.optional()
|
|
891
|
+
.describe("Content format, e.g., markdown, rdoc"),
|
|
700
892
|
});
|
|
701
893
|
export const UpdateWikiPageSchema = z.object({
|
|
702
894
|
project_id: z.string().describe("Project ID or URL-encoded path"),
|
|
703
895
|
slug: z.string().describe("URL-encoded slug of the wiki page"),
|
|
704
896
|
title: z.string().optional().describe("New title of the wiki page"),
|
|
705
897
|
content: z.string().optional().describe("New content of the wiki page"),
|
|
706
|
-
format: z
|
|
898
|
+
format: z
|
|
899
|
+
.string()
|
|
900
|
+
.optional()
|
|
901
|
+
.describe("Content format, e.g., markdown, rdoc"),
|
|
707
902
|
});
|
|
708
903
|
export const DeleteWikiPageSchema = z.object({
|
|
709
904
|
project_id: z.string().describe("Project ID or URL-encoded path"),
|
|
@@ -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.34",
|
|
4
4
|
"description": "MCP server for using the GitLab API",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "zereight",
|
|
@@ -19,7 +19,8 @@
|
|
|
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",
|