@zereight/mcp-gitlab 1.0.43 → 1.0.46

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -75,7 +75,6 @@ When using with the Claude App, you need to set up your API key and URLs directl
75
75
  ## Tools 🛠️
76
76
 
77
77
  +<!-- TOOLS-START -->
78
-
79
78
  1. `create_or_update_file` - Create or update a single file in a GitLab project
80
79
  2. `search_repositories` - Search for GitLab projects
81
80
  3. `create_repository` - Create a new GitLab project
@@ -93,7 +92,7 @@ When using with the Claude App, you need to set up your API key and URLs directl
93
92
  15. `mr_discussions` - List discussion items for a merge request
94
93
  16. `update_merge_request_note` - Modify an existing merge request thread note
95
94
  17. `create_merge_request_note` - Add a new note to an existing merge request thread
96
- 18. `update_issue_note` - Update the content of an existing issue note
95
+ 18. `update_issue_note` - Modify an existing issue thread note
97
96
  19. `create_issue_note` - Add a new note to an existing issue thread
98
97
  20. `list_issues` - List issues in a GitLab project with filtering options
99
98
  21. `get_issue` - Get details of a specific issue in a GitLab project
@@ -121,4 +120,9 @@ When using with the Claude App, you need to set up your API key and URLs directl
121
120
  43. `update_wiki_page` - Update an existing wiki page in a GitLab project
122
121
  44. `delete_wiki_page` - Delete a wiki page from a GitLab project
123
122
  45. `get_repository_tree` - Get the repository tree for a GitLab project (list files and directories)
123
+ 46. `list_pipelines` - List pipelines in a GitLab project with filtering options
124
+ 47. `get_pipeline` - Get details of a specific pipeline in a GitLab project
125
+ 48. `list_pipeline_jobs` - List all jobs in a specific pipeline
126
+ 49. `get_pipeline_job` - Get details of a GitLab pipeline job number
127
+ 50. `get_pipeline_job_output` - Get the output/trace of a GitLab pipeline job number
124
128
  <!-- TOOLS-END -->
package/build/index.js CHANGED
@@ -13,12 +13,14 @@ 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, ListIssueDiscussionsSchema, GetIssueLinkSchema, CreateIssueLinkSchema, DeleteIssueLinkSchema, ListNamespacesSchema, GetNamespaceSchema, VerifyNamespaceSchema, GetProjectSchema, ListProjectsSchema, ListLabelsSchema, GetLabelSchema, CreateLabelSchema, UpdateLabelSchema, DeleteLabelSchema, CreateNoteSchema, CreateMergeRequestThreadSchema, ListGroupProjectsSchema, ListWikiPagesSchema, GetWikiPageSchema, CreateWikiPageSchema, UpdateWikiPageSchema, DeleteWikiPageSchema, GitLabWikiPageSchema,
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, ListIssueDiscussionsSchema, GetIssueLinkSchema, CreateIssueLinkSchema, DeleteIssueLinkSchema, ListNamespacesSchema, GetNamespaceSchema, VerifyNamespaceSchema, GetProjectSchema, ListProjectsSchema, ListLabelsSchema, GetLabelSchema, CreateLabelSchema, UpdateLabelSchema, DeleteLabelSchema, CreateNoteSchema, CreateMergeRequestThreadSchema, ListGroupProjectsSchema, ListWikiPagesSchema, GetWikiPageSchema, CreateWikiPageSchema, UpdateWikiPageSchema, DeleteWikiPageSchema, GitLabWikiPageSchema, GetRepositoryTreeSchema, GitLabTreeItemSchema, GitLabPipelineSchema, GetPipelineSchema, ListPipelinesSchema, ListPipelineJobsSchema,
17
+ // pipeline job schemas
18
+ GetPipelineJobOutputSchema, GitLabPipelineJobSchema,
17
19
  // Discussion Schemas
18
20
  GitLabDiscussionNoteSchema, // Added
19
21
  GitLabDiscussionSchema, UpdateMergeRequestNoteSchema, // Added
20
22
  CreateMergeRequestNoteSchema, // Added
21
- ListMergeRequestDiscussionsSchema, GitLabTreeItemSchema, GetRepositoryTreeSchema, UpdateIssueNoteSchema, CreateIssueNoteSchema, } from "./schemas.js";
23
+ ListMergeRequestDiscussionsSchema, UpdateIssueNoteSchema, CreateIssueNoteSchema, } from "./schemas.js";
22
24
  /**
23
25
  * Read version from package.json
24
26
  */
@@ -311,6 +313,31 @@ const allTools = [
311
313
  description: "Get the repository tree for a GitLab project (list files and directories)",
312
314
  inputSchema: zodToJsonSchema(GetRepositoryTreeSchema),
313
315
  },
316
+ {
317
+ name: "list_pipelines",
318
+ description: "List pipelines in a GitLab project with filtering options",
319
+ inputSchema: zodToJsonSchema(ListPipelinesSchema),
320
+ },
321
+ {
322
+ name: "get_pipeline",
323
+ description: "Get details of a specific pipeline in a GitLab project",
324
+ inputSchema: zodToJsonSchema(GetPipelineSchema),
325
+ },
326
+ {
327
+ name: "list_pipeline_jobs",
328
+ description: "List all jobs in a specific pipeline",
329
+ inputSchema: zodToJsonSchema(ListPipelineJobsSchema),
330
+ },
331
+ {
332
+ name: "get_pipeline_job",
333
+ description: "Get details of a GitLab pipeline job number",
334
+ inputSchema: zodToJsonSchema(GetPipelineJobOutputSchema),
335
+ },
336
+ {
337
+ name: "get_pipeline_job_output",
338
+ description: "Get the output/trace of a GitLab pipeline job number",
339
+ inputSchema: zodToJsonSchema(GetPipelineJobOutputSchema),
340
+ },
314
341
  ];
315
342
  // Define which tools are read-only
316
343
  const readOnlyTools = [
@@ -328,6 +355,11 @@ const readOnlyTools = [
328
355
  "get_namespace",
329
356
  "verify_namespace",
330
357
  "get_project",
358
+ "get_pipeline",
359
+ "list_pipelines",
360
+ "list_pipeline_jobs",
361
+ "get_pipeline_job",
362
+ "get_pipeline_job_output",
331
363
  "list_projects",
332
364
  "list_labels",
333
365
  "get_label",
@@ -1616,6 +1648,117 @@ async function deleteWikiPage(projectId, slug) {
1616
1648
  });
1617
1649
  await handleGitLabError(response);
1618
1650
  }
1651
+ /**
1652
+ * List pipelines in a GitLab project
1653
+ *
1654
+ * @param {string} projectId - The ID or URL-encoded path of the project
1655
+ * @param {ListPipelinesOptions} options - Options for filtering pipelines
1656
+ * @returns {Promise<GitLabPipeline[]>} List of pipelines
1657
+ */
1658
+ async function listPipelines(projectId, options = {}) {
1659
+ projectId = decodeURIComponent(projectId); // Decode project ID
1660
+ const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/pipelines`);
1661
+ // Add all query parameters
1662
+ Object.entries(options).forEach(([key, value]) => {
1663
+ if (value !== undefined) {
1664
+ url.searchParams.append(key, value.toString());
1665
+ }
1666
+ });
1667
+ const response = await fetch(url.toString(), {
1668
+ ...DEFAULT_FETCH_CONFIG,
1669
+ });
1670
+ await handleGitLabError(response);
1671
+ const data = await response.json();
1672
+ return z.array(GitLabPipelineSchema).parse(data);
1673
+ }
1674
+ /**
1675
+ * Get details of a specific pipeline
1676
+ *
1677
+ * @param {string} projectId - The ID or URL-encoded path of the project
1678
+ * @param {number} pipelineId - The ID of the pipeline
1679
+ * @returns {Promise<GitLabPipeline>} Pipeline details
1680
+ */
1681
+ async function getPipeline(projectId, pipelineId) {
1682
+ projectId = decodeURIComponent(projectId); // Decode project ID
1683
+ const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/pipelines/${pipelineId}`);
1684
+ const response = await fetch(url.toString(), {
1685
+ ...DEFAULT_FETCH_CONFIG,
1686
+ });
1687
+ if (response.status === 404) {
1688
+ throw new Error(`Pipeline not found`);
1689
+ }
1690
+ await handleGitLabError(response);
1691
+ const data = await response.json();
1692
+ return GitLabPipelineSchema.parse(data);
1693
+ }
1694
+ /**
1695
+ * List all jobs in a specific pipeline
1696
+ *
1697
+ * @param {string} projectId - The ID or URL-encoded path of the project
1698
+ * @param {number} pipelineId - The ID of the pipeline
1699
+ * @param {Object} options - Options for filtering jobs
1700
+ * @returns {Promise<GitLabPipelineJob[]>} List of pipeline jobs
1701
+ */
1702
+ async function listPipelineJobs(projectId, pipelineId, options = {}) {
1703
+ projectId = decodeURIComponent(projectId); // Decode project ID
1704
+ const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/pipelines/${pipelineId}/jobs`);
1705
+ // Add all query parameters
1706
+ Object.entries(options).forEach(([key, value]) => {
1707
+ if (value !== undefined) {
1708
+ if (typeof value === "boolean") {
1709
+ url.searchParams.append(key, value ? "true" : "false");
1710
+ }
1711
+ else {
1712
+ url.searchParams.append(key, value.toString());
1713
+ }
1714
+ }
1715
+ });
1716
+ const response = await fetch(url.toString(), {
1717
+ ...DEFAULT_FETCH_CONFIG,
1718
+ });
1719
+ if (response.status === 404) {
1720
+ throw new Error(`Pipeline not found`);
1721
+ }
1722
+ await handleGitLabError(response);
1723
+ const data = await response.json();
1724
+ return z.array(GitLabPipelineJobSchema).parse(data);
1725
+ }
1726
+ async function getPipelineJob(projectId, jobId) {
1727
+ projectId = decodeURIComponent(projectId); // Decode project ID
1728
+ const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/jobs/${jobId}`);
1729
+ const response = await fetch(url.toString(), {
1730
+ ...DEFAULT_FETCH_CONFIG,
1731
+ });
1732
+ if (response.status === 404) {
1733
+ throw new Error(`Job not found`);
1734
+ }
1735
+ await handleGitLabError(response);
1736
+ const data = await response.json();
1737
+ return GitLabPipelineJobSchema.parse(data);
1738
+ }
1739
+ /**
1740
+ * Get the output/trace of a pipeline job
1741
+ *
1742
+ * @param {string} projectId - The ID or URL-encoded path of the project
1743
+ * @param {number} jobId - The ID of the job
1744
+ * @returns {Promise<string>} The job output/trace
1745
+ */
1746
+ async function getPipelineJobOutput(projectId, jobId) {
1747
+ projectId = decodeURIComponent(projectId); // Decode project ID
1748
+ const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/jobs/${jobId}/trace`);
1749
+ const response = await fetch(url.toString(), {
1750
+ ...DEFAULT_FETCH_CONFIG,
1751
+ headers: {
1752
+ ...DEFAULT_HEADERS,
1753
+ Accept: "text/plain", // Override Accept header to get plain text
1754
+ },
1755
+ });
1756
+ if (response.status === 404) {
1757
+ throw new Error(`Job trace not found or job is not finished yet`);
1758
+ }
1759
+ await handleGitLabError(response);
1760
+ return await response.text();
1761
+ }
1619
1762
  /**
1620
1763
  * Get the repository tree for a project
1621
1764
  * @param {string} projectId - The ID or URL-encoded path of the project
@@ -2119,6 +2262,62 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
2119
2262
  content: [{ type: "text", text: JSON.stringify(tree, null, 2) }],
2120
2263
  };
2121
2264
  }
2265
+ case "list_pipelines": {
2266
+ const args = ListPipelinesSchema.parse(request.params.arguments);
2267
+ const { project_id, ...options } = args;
2268
+ const pipelines = await listPipelines(project_id, options);
2269
+ return {
2270
+ content: [{ type: "text", text: JSON.stringify(pipelines, null, 2) }],
2271
+ };
2272
+ }
2273
+ case "get_pipeline": {
2274
+ const { project_id, pipeline_id } = GetPipelineSchema.parse(request.params.arguments);
2275
+ const pipeline = await getPipeline(project_id, pipeline_id);
2276
+ return {
2277
+ content: [
2278
+ {
2279
+ type: "text",
2280
+ text: JSON.stringify(pipeline, null, 2),
2281
+ },
2282
+ ],
2283
+ };
2284
+ }
2285
+ case "list_pipeline_jobs": {
2286
+ const { project_id, pipeline_id, ...options } = ListPipelineJobsSchema.parse(request.params.arguments);
2287
+ const jobs = await listPipelineJobs(project_id, pipeline_id, options);
2288
+ return {
2289
+ content: [
2290
+ {
2291
+ type: "text",
2292
+ text: JSON.stringify(jobs, null, 2),
2293
+ },
2294
+ ],
2295
+ };
2296
+ }
2297
+ case "get_pipeline_job": {
2298
+ const { project_id, job_id } = GetPipelineJobOutputSchema.parse(request.params.arguments);
2299
+ const jobDetails = await getPipelineJob(project_id, job_id);
2300
+ return {
2301
+ content: [
2302
+ {
2303
+ type: "text",
2304
+ text: JSON.stringify(jobDetails, null, 2),
2305
+ },
2306
+ ],
2307
+ };
2308
+ }
2309
+ case "get_pipeline_job_output": {
2310
+ const { project_id, job_id } = GetPipelineJobOutputSchema.parse(request.params.arguments);
2311
+ const jobOutput = await getPipelineJobOutput(project_id, job_id);
2312
+ return {
2313
+ content: [
2314
+ {
2315
+ type: "text",
2316
+ text: jobOutput,
2317
+ },
2318
+ ],
2319
+ };
2320
+ }
2122
2321
  default:
2123
2322
  throw new Error(`Unknown tool: ${request.params.name}`);
2124
2323
  }
package/build/schemas.js CHANGED
@@ -5,6 +5,113 @@ export const GitLabAuthorSchema = z.object({
5
5
  email: z.string(),
6
6
  date: z.string(),
7
7
  });
8
+ // Pipeline related schemas
9
+ export const GitLabPipelineSchema = z.object({
10
+ id: z.number(),
11
+ project_id: z.number(),
12
+ sha: z.string(),
13
+ ref: z.string(),
14
+ status: z.string(),
15
+ source: z.string().optional(),
16
+ created_at: z.string(),
17
+ updated_at: z.string(),
18
+ web_url: z.string(),
19
+ duration: z.number().nullable().optional(),
20
+ started_at: z.string().nullable().optional(),
21
+ finished_at: z.string().nullable().optional(),
22
+ coverage: z.number().nullable().optional(),
23
+ user: z.object({
24
+ id: z.number(),
25
+ name: z.string(),
26
+ username: z.string(),
27
+ avatar_url: z.string().nullable().optional(),
28
+ }).optional(),
29
+ detailed_status: z.object({
30
+ icon: z.string().optional(),
31
+ text: z.string().optional(),
32
+ label: z.string().optional(),
33
+ group: z.string().optional(),
34
+ tooltip: z.string().optional(),
35
+ has_details: z.boolean().optional(),
36
+ details_path: z.string().optional(),
37
+ illustration: z.object({
38
+ image: z.string().optional(),
39
+ size: z.string().optional(),
40
+ title: z.string().optional(),
41
+ }).optional(),
42
+ favicon: z.string().optional(),
43
+ }).optional(),
44
+ });
45
+ // Pipeline job related schemas
46
+ export const GitLabPipelineJobSchema = z.object({
47
+ id: z.number(),
48
+ status: z.string(),
49
+ stage: z.string(),
50
+ name: z.string(),
51
+ ref: z.string(),
52
+ tag: z.boolean(),
53
+ coverage: z.number().nullable().optional(),
54
+ created_at: z.string(),
55
+ started_at: z.string().nullable().optional(),
56
+ finished_at: z.string().nullable().optional(),
57
+ duration: z.number().nullable().optional(),
58
+ user: z.object({
59
+ id: z.number(),
60
+ name: z.string(),
61
+ username: z.string(),
62
+ avatar_url: z.string().nullable().optional(),
63
+ }).optional(),
64
+ commit: z.object({
65
+ id: z.string(),
66
+ short_id: z.string(),
67
+ title: z.string(),
68
+ author_name: z.string(),
69
+ author_email: z.string(),
70
+ }).optional(),
71
+ pipeline: z.object({
72
+ id: z.number(),
73
+ project_id: z.number(),
74
+ status: z.string(),
75
+ ref: z.string(),
76
+ sha: z.string(),
77
+ }).optional(),
78
+ web_url: z.string().optional(),
79
+ });
80
+ // Schema for listing pipelines
81
+ export const ListPipelinesSchema = z.object({
82
+ project_id: z.string().describe("Project ID or URL-encoded path"),
83
+ scope: z.enum(['running', 'pending', 'finished', 'branches', 'tags']).optional().describe("The scope of pipelines"),
84
+ status: z.enum(['created', 'waiting_for_resource', 'preparing', 'pending', 'running', 'success', 'failed', 'canceled', 'skipped', 'manual', 'scheduled']).optional().describe("The status of pipelines"),
85
+ ref: z.string().optional().describe("The ref of pipelines"),
86
+ sha: z.string().optional().describe("The SHA of pipelines"),
87
+ yaml_errors: z.boolean().optional().describe("Returns pipelines with invalid configurations"),
88
+ username: z.string().optional().describe("The username of the user who triggered pipelines"),
89
+ updated_after: z.string().optional().describe("Return pipelines updated after the specified date"),
90
+ updated_before: z.string().optional().describe("Return pipelines updated before the specified date"),
91
+ order_by: z.enum(['id', 'status', 'ref', 'updated_at', 'user_id']).optional().describe("Order pipelines by"),
92
+ sort: z.enum(['asc', 'desc']).optional().describe("Sort pipelines"),
93
+ page: z.number().optional().describe("Page number for pagination"),
94
+ per_page: z.number().optional().describe("Number of items per page (max 100)"),
95
+ });
96
+ // Schema for getting a specific pipeline
97
+ export const GetPipelineSchema = z.object({
98
+ project_id: z.string().describe("Project ID or URL-encoded path"),
99
+ pipeline_id: z.number().describe("The ID of the pipeline"),
100
+ });
101
+ // Schema for listing jobs in a pipeline
102
+ export const ListPipelineJobsSchema = z.object({
103
+ project_id: z.string().describe("Project ID or URL-encoded path"),
104
+ pipeline_id: z.number().describe("The ID of the pipeline"),
105
+ scope: z.enum(['created', 'pending', 'running', 'failed', 'success', 'canceled', 'skipped', 'manual']).optional().describe("The scope of jobs to show"),
106
+ include_retried: z.boolean().optional().describe("Whether to include retried jobs"),
107
+ page: z.number().optional().describe("Page number for pagination"),
108
+ per_page: z.number().optional().describe("Number of items per page (max 100)"),
109
+ });
110
+ // Schema for the input parameters for pipeline job operations
111
+ export const GetPipelineJobOutputSchema = z.object({
112
+ project_id: z.string().describe("Project ID or URL-encoded path"),
113
+ job_id: z.number().describe("The ID of the job"),
114
+ });
8
115
  // Namespace related schemas
9
116
  // Base schema for project-related operations
10
117
  const ProjectParamsSchema = z.object({
@@ -265,7 +372,7 @@ export const GitLabMilestoneSchema = z.object({
265
372
  id: z.number(),
266
373
  iid: z.number(), // Added to match GitLab API
267
374
  title: z.string(),
268
- description: z.string(),
375
+ description: z.string().nullable().default(""),
269
376
  state: z.string(),
270
377
  web_url: z.string(), // Changed from html_url to match GitLab API
271
378
  });
@@ -274,7 +381,7 @@ export const GitLabIssueSchema = z.object({
274
381
  iid: z.number(), // Added to match GitLab API
275
382
  project_id: z.number(), // Added to match GitLab API
276
383
  title: z.string(),
277
- description: z.string(), // Changed from body to match GitLab API
384
+ description: z.string().nullable().default(""), // Changed from body to match GitLab API
278
385
  state: z.string(),
279
386
  author: GitLabUserSchema,
280
387
  assignees: z.array(GitLabUserSchema),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zereight/mcp-gitlab",
3
- "version": "1.0.43",
3
+ "version": "1.0.46",
4
4
  "description": "MCP server for using the GitLab API",
5
5
  "license": "MIT",
6
6
  "author": "zereight",