@zereight/mcp-gitlab 1.0.31 → 1.0.32

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/build/index.js CHANGED
@@ -13,7 +13,7 @@ import { dirname } from "path";
13
13
  import fs from "fs";
14
14
  import path from "path";
15
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,
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;
@@ -150,7 +151,7 @@ const allTools = [
150
151
  inputSchema: zodToJsonSchema(CreateNoteSchema),
151
152
  },
152
153
  {
153
- name: "list_merge_request_discussions",
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
- "list_merge_request_discussions",
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
  *
@@ -1262,11 +1297,87 @@ async function listGroupProjects(options) {
1262
1297
  const projects = await response.json();
1263
1298
  return GitLabProjectSchema.array().parse(projects);
1264
1299
  }
1300
+ // Wiki API helper functions
1301
+ /**
1302
+ * List wiki pages in a project
1303
+ */
1304
+ async function listWikiPages(projectId, options = {}) {
1305
+ const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/wikis`);
1306
+ if (options.page)
1307
+ url.searchParams.append('page', options.page.toString());
1308
+ if (options.per_page)
1309
+ url.searchParams.append('per_page', options.per_page.toString());
1310
+ const response = await fetch(url.toString(), {
1311
+ ...DEFAULT_FETCH_CONFIG,
1312
+ });
1313
+ await handleGitLabError(response);
1314
+ const data = await response.json();
1315
+ return GitLabWikiPageSchema.array().parse(data);
1316
+ }
1317
+ /**
1318
+ * Get a specific wiki page
1319
+ */
1320
+ async function getWikiPage(projectId, slug) {
1321
+ const response = await fetch(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/wikis/${encodeURIComponent(slug)}`, { ...DEFAULT_FETCH_CONFIG });
1322
+ await handleGitLabError(response);
1323
+ const data = await response.json();
1324
+ return GitLabWikiPageSchema.parse(data);
1325
+ }
1326
+ /**
1327
+ * Create a new wiki page
1328
+ */
1329
+ async function createWikiPage(projectId, title, content, format) {
1330
+ const body = { title, content };
1331
+ if (format)
1332
+ body.format = format;
1333
+ const response = await fetch(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/wikis`, {
1334
+ ...DEFAULT_FETCH_CONFIG,
1335
+ method: 'POST',
1336
+ body: JSON.stringify(body),
1337
+ });
1338
+ await handleGitLabError(response);
1339
+ const data = await response.json();
1340
+ return GitLabWikiPageSchema.parse(data);
1341
+ }
1342
+ /**
1343
+ * Update an existing wiki page
1344
+ */
1345
+ async function updateWikiPage(projectId, slug, title, content, format) {
1346
+ const body = {};
1347
+ if (title)
1348
+ body.title = title;
1349
+ if (content)
1350
+ body.content = content;
1351
+ if (format)
1352
+ body.format = format;
1353
+ const response = await fetch(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/wikis/${encodeURIComponent(slug)}`, {
1354
+ ...DEFAULT_FETCH_CONFIG,
1355
+ method: 'PUT',
1356
+ body: JSON.stringify(body),
1357
+ });
1358
+ await handleGitLabError(response);
1359
+ const data = await response.json();
1360
+ return GitLabWikiPageSchema.parse(data);
1361
+ }
1362
+ /**
1363
+ * Delete a wiki page
1364
+ */
1365
+ async function deleteWikiPage(projectId, slug) {
1366
+ const response = await fetch(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/wikis/${encodeURIComponent(slug)}`, {
1367
+ ...DEFAULT_FETCH_CONFIG,
1368
+ method: 'DELETE',
1369
+ });
1370
+ await handleGitLabError(response);
1371
+ }
1265
1372
  server.setRequestHandler(ListToolsRequestSchema, async () => {
1266
- // If read-only mode is enabled, filter out write operations
1267
- const tools = GITLAB_READ_ONLY_MODE
1373
+ // Apply read-only filter first
1374
+ const tools0 = GITLAB_READ_ONLY_MODE
1268
1375
  ? allTools.filter((tool) => readOnlyTools.includes(tool.name))
1269
1376
  : allTools;
1377
+ // Toggle wiki tools by USE_GITLAB_WIKI flag
1378
+ const tools = USE_GITLAB_WIKI
1379
+ ? tools0
1380
+ : tools0.filter((tool) => !wikiToolNames.includes(tool.name));
1270
1381
  return {
1271
1382
  tools,
1272
1383
  };
@@ -1406,7 +1517,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
1406
1517
  ],
1407
1518
  };
1408
1519
  }
1409
- case "list_merge_request_discussions": {
1520
+ case "mr_discussions": {
1410
1521
  const args = ListMergeRequestDiscussionsSchema.parse(request.params.arguments);
1411
1522
  const discussions = await listMergeRequestDiscussions(args.project_id, args.merge_request_iid);
1412
1523
  return {
@@ -1617,6 +1728,31 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
1617
1728
  content: [{ type: "text", text: JSON.stringify(projects, null, 2) }],
1618
1729
  };
1619
1730
  }
1731
+ case "list_wiki_pages": {
1732
+ const { project_id, page, per_page } = ListWikiPagesSchema.parse(request.params.arguments);
1733
+ const wikiPages = await listWikiPages(project_id, { page, per_page });
1734
+ return { content: [{ type: "text", text: JSON.stringify(wikiPages, null, 2) }] };
1735
+ }
1736
+ case "get_wiki_page": {
1737
+ const { project_id, slug } = GetWikiPageSchema.parse(request.params.arguments);
1738
+ const wikiPage = await getWikiPage(project_id, slug);
1739
+ return { content: [{ type: "text", text: JSON.stringify(wikiPage, null, 2) }] };
1740
+ }
1741
+ case "create_wiki_page": {
1742
+ const { project_id, title, content, format } = CreateWikiPageSchema.parse(request.params.arguments);
1743
+ const wikiPage = await createWikiPage(project_id, title, content, format);
1744
+ return { content: [{ type: "text", text: JSON.stringify(wikiPage, null, 2) }] };
1745
+ }
1746
+ case "update_wiki_page": {
1747
+ const { project_id, slug, title, content, format } = UpdateWikiPageSchema.parse(request.params.arguments);
1748
+ const wikiPage = await updateWikiPage(project_id, slug, title, content, format);
1749
+ return { content: [{ type: "text", text: JSON.stringify(wikiPage, null, 2) }] };
1750
+ }
1751
+ case "delete_wiki_page": {
1752
+ const { project_id, slug } = DeleteWikiPageSchema.parse(request.params.arguments);
1753
+ await deleteWikiPage(project_id, slug);
1754
+ return { content: [{ type: "text", text: JSON.stringify({ status: "success", message: "Wiki page deleted successfully" }, null, 2) }] };
1755
+ }
1620
1756
  default:
1621
1757
  throw new Error(`Unknown tool: ${request.params.name}`);
1622
1758
  }
package/build/schemas.js CHANGED
@@ -682,3 +682,39 @@ export const ListGroupProjectsSchema = z.object({
682
682
  with_custom_attributes: z.boolean().optional().describe("Include custom attributes"),
683
683
  with_security_reports: z.boolean().optional().describe("Include security reports")
684
684
  });
685
+ // Add wiki operation schemas
686
+ export const ListWikiPagesSchema = z.object({
687
+ project_id: z.string().describe("Project ID or URL-encoded path"),
688
+ page: z.number().optional().describe("Page number for pagination"),
689
+ per_page: z.number().optional().describe("Number of items per page"),
690
+ });
691
+ export const GetWikiPageSchema = z.object({
692
+ project_id: z.string().describe("Project ID or URL-encoded path"),
693
+ slug: z.string().describe("URL-encoded slug of the wiki page"),
694
+ });
695
+ export const CreateWikiPageSchema = z.object({
696
+ project_id: z.string().describe("Project ID or URL-encoded path"),
697
+ title: z.string().describe("Title of the wiki page"),
698
+ content: z.string().describe("Content of the wiki page"),
699
+ format: z.string().optional().describe("Content format, e.g., markdown, rdoc"),
700
+ });
701
+ export const UpdateWikiPageSchema = z.object({
702
+ project_id: z.string().describe("Project ID or URL-encoded path"),
703
+ slug: z.string().describe("URL-encoded slug of the wiki page"),
704
+ title: z.string().optional().describe("New title of the wiki page"),
705
+ content: z.string().optional().describe("New content of the wiki page"),
706
+ format: z.string().optional().describe("Content format, e.g., markdown, rdoc"),
707
+ });
708
+ export const DeleteWikiPageSchema = z.object({
709
+ project_id: z.string().describe("Project ID or URL-encoded path"),
710
+ slug: z.string().describe("URL-encoded slug of the wiki page"),
711
+ });
712
+ // Define wiki response schemas
713
+ export const GitLabWikiPageSchema = z.object({
714
+ title: z.string(),
715
+ slug: z.string(),
716
+ format: z.string(),
717
+ content: z.string(),
718
+ created_at: z.string().optional(),
719
+ updated_at: z.string().optional(),
720
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zereight/mcp-gitlab",
3
- "version": "1.0.31",
3
+ "version": "1.0.32",
4
4
  "description": "MCP server for using the GitLab API",
5
5
  "license": "MIT",
6
6
  "author": "zereight",
@@ -23,6 +23,7 @@
23
23
  },
24
24
  "dependencies": {
25
25
  "@modelcontextprotocol/sdk": "1.8.0",
26
+ "form-data": "^4.0.0",
26
27
  "@types/node-fetch": "^2.6.12",
27
28
  "http-proxy-agent": "^7.0.2",
28
29
  "https-proxy-agent": "^7.0.6",