@zereight/mcp-gitlab 2.0.0-beta.0 → 2.0.2

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.
@@ -1,21 +1,16 @@
1
1
  import { z } from "zod";
2
- import { pino } from 'pino';
3
2
  const DEFAULT_NULL = process.env.DEFAULT_NULL === "true";
4
- export const logger = pino({
5
- level: process.env.LOG_LEVEL || 'info',
6
- transport: {
7
- target: 'pino-pretty',
8
- options: {
9
- colorize: true,
10
- levelFirst: true,
11
- destination: 2,
12
- },
13
- },
14
- });
15
- export const flexibleBoolean = z.preprocess((val) => {
16
- if (typeof val === 'string') {
17
- return val.toLowerCase() === 'true';
3
+ export const flexibleBoolean = z.preprocess(val => {
4
+ if (typeof val === "boolean") {
5
+ return val;
18
6
  }
19
- return val;
7
+ let result = "false";
8
+ try {
9
+ result = String(val).toLowerCase();
10
+ }
11
+ catch {
12
+ return false;
13
+ }
14
+ return ["true", "t", "1"].includes(result);
20
15
  }, z.boolean());
21
16
  export const flexibleBooleanNullable = DEFAULT_NULL ? flexibleBoolean.nullable().default(null) : flexibleBoolean.nullable();
@@ -1646,4 +1646,21 @@ export class GitlabHandler extends GitlabSession {
1646
1646
  const data = await response.json();
1647
1647
  return GitLabMarkdownUploadSchema.parse(data);
1648
1648
  }
1649
+ /**
1650
+ * Download an attachment from a GitLab project
1651
+ */
1652
+ async downloadAttachment(projectId, secret, filename, localPath) {
1653
+ projectId = decodeURIComponent(projectId);
1654
+ const effectiveProjectId = this.getEffectiveProjectId(projectId);
1655
+ const url = new URL(`${config.GITLAB_API_URL}/projects/${encodeURIComponent(effectiveProjectId)}/uploads/${secret}/${filename}`);
1656
+ const response = await this.fetch(url.toString(), {});
1657
+ await this.handleGitLabError(response);
1658
+ // Get the file content as buffer
1659
+ const buffer = await response.arrayBuffer();
1660
+ // Determine the save path
1661
+ const savePath = localPath ? path.join(localPath, filename) : filename;
1662
+ // Write the file to disk
1663
+ fs.writeFileSync(savePath, Buffer.from(buffer));
1664
+ return savePath;
1665
+ }
1649
1666
  }
@@ -1,6 +1,6 @@
1
1
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
2
2
  import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
3
- import { logger } from "./customSchemas.js";
3
+ import { logger } from "./logger.js";
4
4
  import { z } from "zod";
5
5
  import { zodToJsonSchema } from "zod-to-json-schema";
6
6
  import { fileURLToPath } from "url";
@@ -9,7 +9,7 @@ import fs from "fs";
9
9
  import path from "path";
10
10
  import { config } from "./config.js";
11
11
  import { GitlabHandler } from "./gitlabhandler.js";
12
- import { ForkRepositorySchema, CreateBranchSchema, CreateOrUpdateFileSchema, SearchRepositoriesSchema, CreateRepositorySchema, GetFileContentsSchema, PushFilesSchema, CreateIssueSchema, CreateMergeRequestSchema, GetMergeRequestSchema, GetMergeRequestDiffsSchema, UpdateMergeRequestSchema, ListIssuesSchema, GetIssueSchema, UpdateIssueSchema, DeleteIssueSchema, ListIssueLinksSchema, ListIssueDiscussionsSchema, GetIssueLinkSchema, CreateIssueLinkSchema, DeleteIssueLinkSchema, ListNamespacesSchema, GetNamespaceSchema, VerifyNamespaceSchema, GetProjectSchema, ListProjectsSchema, ListLabelsSchema, GetLabelSchema, CreateLabelSchema, UpdateLabelSchema, DeleteLabelSchema, CreateNoteSchema, CreateMergeRequestThreadSchema, ListGroupProjectsSchema, ListWikiPagesSchema, GetWikiPageSchema, CreateWikiPageSchema, UpdateWikiPageSchema, DeleteWikiPageSchema, GetRepositoryTreeSchema, GetPipelineSchema, ListPipelinesSchema, ListPipelineJobsSchema, CreatePipelineSchema, RetryPipelineSchema, CancelPipelineSchema, GetPipelineJobOutputSchema, UpdateMergeRequestNoteSchema, CreateMergeRequestNoteSchema, ListMergeRequestDiscussionsSchema, UpdateIssueNoteSchema, CreateIssueNoteSchema, ListMergeRequestsSchema, ListProjectMilestonesSchema, GetProjectMilestoneSchema, CreateProjectMilestoneSchema, EditProjectMilestoneSchema, DeleteProjectMilestoneSchema, GetMilestoneIssuesSchema, GetMilestoneMergeRequestsSchema, PromoteProjectMilestoneSchema, GetMilestoneBurndownEventsSchema, GetBranchDiffsSchema, GetUsersSchema, ListCommitsSchema, GetCommitSchema, GetCommitDiffSchema, ListMergeRequestDiffsSchema, GetCurrentUserSchema, GetDraftNoteSchema, ListDraftNotesSchema, CreateDraftNoteSchema, UpdateDraftNoteSchema, DeleteDraftNoteSchema, PublishDraftNoteSchema, BulkPublishDraftNotesSchema, MergeMergeRequestSchema, MyIssuesSchema, ListProjectMembersSchema, MarkdownUploadSchema, } from "./schemas.js";
12
+ import { ForkRepositorySchema, CreateBranchSchema, CreateOrUpdateFileSchema, SearchRepositoriesSchema, CreateRepositorySchema, GetFileContentsSchema, PushFilesSchema, CreateIssueSchema, CreateMergeRequestSchema, GetMergeRequestSchema, GetMergeRequestDiffsSchema, UpdateMergeRequestSchema, ListIssuesSchema, GetIssueSchema, UpdateIssueSchema, DeleteIssueSchema, ListIssueLinksSchema, ListIssueDiscussionsSchema, GetIssueLinkSchema, CreateIssueLinkSchema, DeleteIssueLinkSchema, ListNamespacesSchema, GetNamespaceSchema, VerifyNamespaceSchema, GetProjectSchema, ListProjectsSchema, ListLabelsSchema, GetLabelSchema, CreateLabelSchema, UpdateLabelSchema, DeleteLabelSchema, CreateNoteSchema, CreateMergeRequestThreadSchema, ListGroupProjectsSchema, ListWikiPagesSchema, GetWikiPageSchema, CreateWikiPageSchema, UpdateWikiPageSchema, DeleteWikiPageSchema, GetRepositoryTreeSchema, GetPipelineSchema, ListPipelinesSchema, ListPipelineJobsSchema, CreatePipelineSchema, RetryPipelineSchema, CancelPipelineSchema, GetPipelineJobOutputSchema, UpdateMergeRequestNoteSchema, CreateMergeRequestNoteSchema, ListMergeRequestDiscussionsSchema, UpdateIssueNoteSchema, CreateIssueNoteSchema, ListMergeRequestsSchema, ListProjectMilestonesSchema, GetProjectMilestoneSchema, CreateProjectMilestoneSchema, EditProjectMilestoneSchema, DeleteProjectMilestoneSchema, GetMilestoneIssuesSchema, GetMilestoneMergeRequestsSchema, PromoteProjectMilestoneSchema, GetMilestoneBurndownEventsSchema, GetBranchDiffsSchema, GetUsersSchema, ListCommitsSchema, GetCommitSchema, GetCommitDiffSchema, ListMergeRequestDiffsSchema, GetCurrentUserSchema, GetDraftNoteSchema, ListDraftNotesSchema, CreateDraftNoteSchema, UpdateDraftNoteSchema, DeleteDraftNoteSchema, PublishDraftNoteSchema, BulkPublishDraftNotesSchema, MergeMergeRequestSchema, MyIssuesSchema, ListProjectMembersSchema, MarkdownUploadSchema, DownloadAttachmentSchema, } from "./schemas.js";
13
13
  import { createCookieJar } from "./authhelpers.js";
14
14
  /**
15
15
  * Read version from package.json
@@ -442,6 +442,11 @@ const allTools = [
442
442
  name: "upload_markdown",
443
443
  description: "Upload a file to a GitLab project for use in markdown content",
444
444
  inputSchema: zodToJsonSchema(MarkdownUploadSchema),
445
+ },
446
+ {
447
+ name: "download_attachment",
448
+ description: "Download an uploaded file from a GitLab project by secret and filename",
449
+ inputSchema: zodToJsonSchema(DownloadAttachmentSchema),
445
450
  }
446
451
  ];
447
452
  // Define which tools are read-only
@@ -484,6 +489,7 @@ const readOnlyTools = [
484
489
  "get_commit",
485
490
  "get_commit_diff",
486
491
  "get_current_user",
492
+ "download_attachment",
487
493
  ];
488
494
  // Define which tools are related to wiki and can be toggled by USE_GITLAB_WIKI
489
495
  const wikiToolNames = [
@@ -1314,6 +1320,13 @@ server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
1314
1320
  content: [{ type: "text", text: JSON.stringify(upload, null, 2) }],
1315
1321
  };
1316
1322
  }
1323
+ case "download_attachment": {
1324
+ const args = DownloadAttachmentSchema.parse(request.params.arguments);
1325
+ const filePath = await gitlabSession.downloadAttachment(args.project_id, args.secret, args.filename, args.local_path);
1326
+ return {
1327
+ content: [{ type: "text", text: JSON.stringify({ success: true, file_path: filePath }, null, 2) }],
1328
+ };
1329
+ }
1317
1330
  default:
1318
1331
  throw new Error(`Unknown tool: ${request.params.name}`);
1319
1332
  }
@@ -1631,6 +1631,12 @@ export const MarkdownUploadSchema = z.object({
1631
1631
  project_id: z.string().describe("Project ID or URL-encoded path of the project"),
1632
1632
  file_path: z.string().describe("Path to the file to upload"),
1633
1633
  });
1634
+ export const DownloadAttachmentSchema = z.object({
1635
+ project_id: z.string().describe("Project ID or URL-encoded path of the project"),
1636
+ secret: z.string().describe("The 32-character secret of the upload"),
1637
+ filename: z.string().describe("The filename of the upload"),
1638
+ local_path: z.string().optional().describe("Local path to save the file (optional, defaults to current directory)"),
1639
+ });
1634
1640
  export const GroupIteration = z.object({
1635
1641
  id: z.coerce.string(),
1636
1642
  iid: z.coerce.string(),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zereight/mcp-gitlab",
3
- "version": "2.0.0-beta.0",
3
+ "version": "2.0.2",
4
4
  "description": "MCP server for using the GitLab API",
5
5
  "license": "MIT",
6
6
  "author": "zereight",
@@ -33,8 +33,11 @@
33
33
  "format:check": "prettier --check \"**/*.{js,ts,json,md}\""
34
34
  },
35
35
  "dependencies": {
36
- "@modelcontextprotocol/sdk": "^1.10.0",
36
+ "@modelcontextprotocol/sdk": "1.13.3",
37
+ "@noble/hashes": "^1.8.0",
38
+ "@types/better-sqlite3": "^7.6.13",
37
39
  "@types/node-fetch": "^2.6.12",
40
+ "better-sqlite3": "^12.2.0",
38
41
  "express": "^5.1.0",
39
42
  "fetch-cookie": "^3.1.0",
40
43
  "form-data": "^4.0.0",
@@ -44,6 +47,7 @@
44
47
  "pino": "^9.7.0",
45
48
  "pino-pretty": "^13.0.0",
46
49
  "socks-proxy-agent": "^8.0.5",
50
+ "sqlite3": "^5.1.7",
47
51
  "tough-cookie": "^5.1.2",
48
52
  "zod-to-json-schema": "^3.23.5"
49
53
  },
@@ -1,28 +0,0 @@
1
- import { z } from "zod";
2
- import { pino } from 'pino';
3
- const DEFAULT_NULL = process.env.DEFAULT_NULL === "true";
4
- const logger = pino({
5
- level: process.env.LOG_LEVEL || 'info',
6
- transport: {
7
- target: 'pino-pretty',
8
- options: {
9
- colorize: true,
10
- levelFirst: true,
11
- destination: 2,
12
- },
13
- },
14
- });
15
- export const flexibleBoolean = z.preprocess(val => {
16
- if (typeof val === "boolean") {
17
- return val;
18
- }
19
- let result = "false";
20
- try {
21
- result = String(val).toLowerCase();
22
- }
23
- catch {
24
- return false;
25
- }
26
- return ["true", "t", "1"].includes(result);
27
- }, z.boolean());
28
- export const flexibleBooleanNullable = DEFAULT_NULL ? flexibleBoolean.nullable().default(null) : flexibleBoolean.nullable();