@zereight/mcp-gitlab 2.1.6 → 2.1.7
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 +31 -26
- package/build/index.js +129 -1
- package/build/schemas.js +78 -0
- package/build/test/test-tags.js +206 -0
- package/build/test/test-toolset-filtering.js +12 -1
- package/build/tools/registry.js +41 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -8,13 +8,13 @@
|
|
|
8
8
|
|
|
9
9
|
## @zereight/mcp-gitlab
|
|
10
10
|
|
|
11
|
-
A comprehensive GitLab MCP server for AI clients. Manage projects, merge requests, issues, pipelines, wiki, releases, milestones, and more through stdio, SSE, and Streamable HTTP.
|
|
11
|
+
A comprehensive GitLab MCP server for AI clients. Manage projects, merge requests, issues, pipelines, wiki, releases, tags, milestones, and more through stdio, SSE, and Streamable HTTP.
|
|
12
12
|
|
|
13
13
|
Supports PAT, OAuth, read-only mode, dynamic API URLs, and remote authorization for VS Code, Claude, Cursor, Copilot, and other MCP clients.
|
|
14
14
|
|
|
15
15
|
### Why use this GitLab MCP?
|
|
16
16
|
|
|
17
|
-
- Broad GitLab coverage — projects, repository browsing, merge requests, issues, pipelines, wiki, releases, labels, milestones, and more
|
|
17
|
+
- Broad GitLab coverage — projects, repository browsing, merge requests, issues, pipelines, wiki, releases, tags, labels, milestones, and more
|
|
18
18
|
- Flexible auth — Personal Access Token, local OAuth2 browser flow, MCP OAuth proxy, and per-request remote authorization
|
|
19
19
|
- Multiple transports — stdio for local clients, SSE for legacy clients, and Streamable HTTP for modern remote deployments
|
|
20
20
|
- Client-friendly setup — examples for Claude Code, Codex, Antigravity, OpenCode, Copilot, Cline, Roo Code, Cursor, Kilo Code, and Amp Code
|
|
@@ -564,30 +564,35 @@ Register the skill directory in your AI client to get optimal tool usage guidanc
|
|
|
564
564
|
115. `delete_release` - Delete a release from a GitLab project (does not delete the associated tag)
|
|
565
565
|
116. `create_release_evidence` - Create release evidence for an existing release (GitLab Premium/Ultimate only)
|
|
566
566
|
117. `download_release_asset` - Download a release asset file by direct asset path
|
|
567
|
-
118. `
|
|
568
|
-
119. `
|
|
569
|
-
120. `
|
|
570
|
-
121. `
|
|
571
|
-
122. `
|
|
572
|
-
123. `
|
|
573
|
-
124. `
|
|
574
|
-
125. `
|
|
575
|
-
126. `
|
|
576
|
-
127. `
|
|
577
|
-
128. `
|
|
578
|
-
129. `
|
|
579
|
-
130. `
|
|
580
|
-
131. `
|
|
581
|
-
132. `
|
|
582
|
-
133. `
|
|
583
|
-
134. `
|
|
584
|
-
135. `
|
|
585
|
-
136. `
|
|
586
|
-
137. `
|
|
587
|
-
138. `
|
|
588
|
-
139. `
|
|
589
|
-
140. `
|
|
590
|
-
141. `
|
|
567
|
+
118. `list_tags` - List repository tags with filtering and pagination support
|
|
568
|
+
119. `get_tag` - Get details of a specific repository tag
|
|
569
|
+
120. `create_tag` - Create a new tag in the repository
|
|
570
|
+
121. `delete_tag` - Delete a tag from the repository
|
|
571
|
+
122. `get_tag_signature` - Get the signature of a signed tag
|
|
572
|
+
123. `get_users` - Get GitLab user details by usernames
|
|
573
|
+
124. `list_events` - List all events for the currently authenticated user
|
|
574
|
+
125. `get_project_events` - List all visible events for a specified project
|
|
575
|
+
126. `upload_markdown` - Upload a file to a GitLab project for use in markdown content
|
|
576
|
+
127. `download_attachment` - Download an uploaded file from a GitLab project by secret and filename
|
|
577
|
+
128. `get_work_item` - Get a single work item with full details including status, hierarchy (parent/children), type, labels, assignees, and all widgets
|
|
578
|
+
129. `list_work_items` - List work items in a project with filters (type, state, search, assignees, labels). Returns items with status and hierarchy info
|
|
579
|
+
130. `create_work_item` - Create a new work item (issue, task, incident, test_case, epic, key_result, objective, requirement, ticket). Supports setting title, description, labels, assignees, weight, parent, health status, start/due dates, milestone, and confidentiality
|
|
580
|
+
131. `update_work_item` - Update a work item. Can modify title, description, labels, assignees, weight, state, status, parent hierarchy, children, health status, start/due dates, milestone, confidentiality, linked items, and custom fields
|
|
581
|
+
132. `convert_work_item_type` - Convert a work item to a different type (e.g. issue to task, task to incident)
|
|
582
|
+
133. `list_work_item_statuses` - List available statuses for a work item type in a project. Requires GitLab Premium/Ultimate with configurable statuses
|
|
583
|
+
134. `list_custom_field_definitions` - List available custom field definitions for a work item type in a project. Returns field names, types, and IDs needed for setting custom fields via update_work_item
|
|
584
|
+
135. `move_work_item` - Move a work item (issue, task, etc.) to a different project. Uses GitLab GraphQL issueMove mutation
|
|
585
|
+
136. `list_work_item_notes` - List notes and discussions on a work item. Returns threaded discussions with author, body, timestamps, and system/internal flags
|
|
586
|
+
137. `create_work_item_note` - Add a note/comment to a work item. Supports Markdown, internal notes, and threaded replies
|
|
587
|
+
138. `get_timeline_events` - List timeline events for an incident. Returns chronological events with notes, timestamps, and tags
|
|
588
|
+
139. `create_timeline_event` - Create a timeline event on an incident. Supports tags: 'Start time', 'End time', 'Impact detected', 'Response initiated', 'Impact mitigated', 'Cause identified'
|
|
589
|
+
140. `list_webhooks` - List all configured webhooks for a GitLab project or group. Provide either project_id or group_id
|
|
590
|
+
141. `list_webhook_events` - List recent webhook events (past 7 days) for a project or group webhook. Use summary mode for overview, then get_webhook_event for full details
|
|
591
|
+
142. `get_webhook_event` - Get full details of a specific webhook event by ID, including request/response payloads
|
|
592
|
+
143. `search_code` - Search for code across all projects on the GitLab instance (requires advanced search or exact code search to be enabled)
|
|
593
|
+
144. `search_project_code` - Search for code within a specific GitLab project (requires advanced search or exact code search to be enabled)
|
|
594
|
+
145. `search_group_code` - Search for code within a specific GitLab group (requires advanced search or exact code search to be enabled)
|
|
595
|
+
146. `execute_graphql` - Execute a GitLab GraphQL query
|
|
591
596
|
<!-- TOOLS-END -->
|
|
592
597
|
|
|
593
598
|
</details>
|
package/build/index.js
CHANGED
|
@@ -33,7 +33,7 @@ GitLabDiscussionNoteSchema, // Added
|
|
|
33
33
|
GitLabDiscussionSchema,
|
|
34
34
|
// Draft Notes Schemas
|
|
35
35
|
GitLabDraftNoteSchema, GitLabForkSchema, GitLabIssueLinkSchema, GitLabIssueSchema, GitLabIssueWithLinkDetailsSchema, GitLabMarkdownUploadSchema, GitLabMergeRequestSchema, GitLabMilestonesSchema, GitLabNamespaceExistsResponseSchema, GitLabNamespaceSchema, GitLabPipelineJobSchema, GitLabDeploymentSchema, GitLabEnvironmentSchema, GitLabPipelineSchema, GitLabPipelineTriggerJobSchema, GitLabProjectMemberSchema, GitLabProjectSchema, GitLabReferenceSchema, GitLabRepositorySchema, GitLabSearchBlobResultSchema, GitLabSearchResponseSchema, GitLabTreeItemSchema, GitLabUserSchema, GitLabUsersResponseSchema, GitLabWikiPageSchema, GroupIteration, ListCommitsSchema, ListDraftNotesSchema, ListGroupIterationsSchema, ListGroupProjectsSchema, ListIssueDiscussionsSchema, ListIssueLinksSchema, ListIssuesSchema, ListLabelsSchema, ListMergeRequestDiffsSchema, // Added
|
|
36
|
-
GetMergeRequestFileDiffSchema, ListMergeRequestChangedFilesSchema, ListMergeRequestDiscussionsSchema, ListMergeRequestsSchema, ListMergeRequestVersionsSchema, GetMergeRequestVersionSchema, GitLabMergeRequestVersionSchema, GitLabMergeRequestVersionDetailSchema, ListNamespacesSchema, ListPipelineJobsSchema, ListPipelinesSchema, ListDeploymentsSchema, ListEnvironmentsSchema, ListPipelineTriggerJobsSchema, ListProjectMembersSchema, ListProjectMilestonesSchema, ListProjectsSchema, ListWikiPagesSchema, GetGroupWikiPageSchema, ListGroupWikiPagesSchema, UpdateGroupWikiPageSchema, MarkdownUploadSchema, DownloadAttachmentSchema, DownloadJobArtifactsSchema, GetJobArtifactFileSchema, GitLabArtifactEntrySchema, ListJobArtifactsSchema, MergeMergeRequestSchema, ApproveMergeRequestSchema, UnapproveMergeRequestSchema, GetMergeRequestApprovalStateSchema, GetMergeRequestConflictsSchema, GitLabMergeRequestApprovalsResponseSchema, GitLabMergeRequestApprovalStateSchema, MyIssuesSchema, PaginatedDiscussionsResponseSchema, PromoteProjectMilestoneSchema, PublishDraftNoteSchema, PlayPipelineJobSchema, PushFilesSchema, RetryPipelineJobSchema, RetryPipelineSchema, SearchCodeSchema, SearchGroupCodeSchema, SearchProjectCodeSchema, SearchRepositoriesSchema, UpdateDraftNoteSchema, UpdateIssueNoteSchema, UpdateIssueSchema, UpdateLabelSchema, UpdateMergeRequestNoteSchema, UpdateMergeRequestDiscussionNoteSchema, UpdateMergeRequestSchema, UpdateWikiPageSchema, VerifyNamespaceSchema, GitLabEventSchema, ListEventsSchema, GetProjectEventsSchema, ExecuteGraphQLSchema, GitLabReleaseSchema, ListReleasesSchema, GetReleaseSchema, CreateReleaseSchema, UpdateReleaseSchema, DeleteReleaseSchema, CreateReleaseEvidenceSchema, DownloadReleaseAssetSchema, GetMergeRequestNotesSchema, GetMergeRequestNoteSchema, DeleteMergeRequestDiscussionNoteSchema, ResolveMergeRequestThreadSchema, GetWorkItemSchema, ListWorkItemsSchema, CreateWorkItemSchema, UpdateWorkItemSchema, ConvertWorkItemTypeSchema, ListWorkItemStatusesSchema, ListWorkItemNotesSchema, CreateWorkItemNoteSchema, CreateWorkItemEmojiReactionSchema, CreateWorkItemNoteEmojiReactionSchema, ListWorkItemEmojiReactionsSchema, ListWorkItemNoteEmojiReactionsSchema, DeleteWorkItemEmojiReactionSchema, DeleteWorkItemNoteEmojiReactionSchema, MoveWorkItemSchema, ListCustomFieldDefinitionsSchema, GetTimelineEventsSchema, CreateTimelineEventSchema, ListWebhooksSchema, ListWebhookEventsSchema, GetWebhookEventSchema, } from "./schemas.js";
|
|
36
|
+
GetMergeRequestFileDiffSchema, ListMergeRequestChangedFilesSchema, ListMergeRequestDiscussionsSchema, ListMergeRequestsSchema, ListMergeRequestVersionsSchema, GetMergeRequestVersionSchema, GitLabMergeRequestVersionSchema, GitLabMergeRequestVersionDetailSchema, ListNamespacesSchema, ListPipelineJobsSchema, ListPipelinesSchema, ListDeploymentsSchema, ListEnvironmentsSchema, ListPipelineTriggerJobsSchema, ListProjectMembersSchema, ListProjectMilestonesSchema, ListProjectsSchema, ListWikiPagesSchema, GetGroupWikiPageSchema, ListGroupWikiPagesSchema, UpdateGroupWikiPageSchema, MarkdownUploadSchema, DownloadAttachmentSchema, DownloadJobArtifactsSchema, GetJobArtifactFileSchema, GitLabArtifactEntrySchema, ListJobArtifactsSchema, MergeMergeRequestSchema, ApproveMergeRequestSchema, UnapproveMergeRequestSchema, GetMergeRequestApprovalStateSchema, GetMergeRequestConflictsSchema, GitLabMergeRequestApprovalsResponseSchema, GitLabMergeRequestApprovalStateSchema, MyIssuesSchema, PaginatedDiscussionsResponseSchema, PromoteProjectMilestoneSchema, PublishDraftNoteSchema, PlayPipelineJobSchema, PushFilesSchema, RetryPipelineJobSchema, RetryPipelineSchema, SearchCodeSchema, SearchGroupCodeSchema, SearchProjectCodeSchema, SearchRepositoriesSchema, UpdateDraftNoteSchema, UpdateIssueNoteSchema, UpdateIssueSchema, UpdateLabelSchema, UpdateMergeRequestNoteSchema, UpdateMergeRequestDiscussionNoteSchema, UpdateMergeRequestSchema, UpdateWikiPageSchema, VerifyNamespaceSchema, GitLabEventSchema, ListEventsSchema, GetProjectEventsSchema, ExecuteGraphQLSchema, GitLabReleaseSchema, ListReleasesSchema, GetReleaseSchema, CreateReleaseSchema, UpdateReleaseSchema, DeleteReleaseSchema, CreateReleaseEvidenceSchema, DownloadReleaseAssetSchema, ListTagsSchema, GetTagSchema, CreateTagSchema, DeleteTagSchema, GetTagSignatureSchema, GitLabTagSchema, GitLabTagSignatureSchema, GetMergeRequestNotesSchema, GetMergeRequestNoteSchema, DeleteMergeRequestDiscussionNoteSchema, ResolveMergeRequestThreadSchema, GetWorkItemSchema, ListWorkItemsSchema, CreateWorkItemSchema, UpdateWorkItemSchema, ConvertWorkItemTypeSchema, ListWorkItemStatusesSchema, ListWorkItemNotesSchema, CreateWorkItemNoteSchema, CreateWorkItemEmojiReactionSchema, CreateWorkItemNoteEmojiReactionSchema, ListWorkItemEmojiReactionsSchema, ListWorkItemNoteEmojiReactionsSchema, DeleteWorkItemEmojiReactionSchema, DeleteWorkItemNoteEmojiReactionSchema, MoveWorkItemSchema, ListCustomFieldDefinitionsSchema, GetTimelineEventsSchema, CreateTimelineEventSchema, ListWebhooksSchema, ListWebhookEventsSchema, GetWebhookEventSchema, } from "./schemas.js";
|
|
37
37
|
import { randomUUID } from "node:crypto";
|
|
38
38
|
import { pino } from "pino";
|
|
39
39
|
const logger = pino({
|
|
@@ -5700,6 +5700,92 @@ async function downloadReleaseAsset(projectId, tagName, directAssetPath) {
|
|
|
5700
5700
|
await handleGitLabError(response);
|
|
5701
5701
|
return await response.text();
|
|
5702
5702
|
}
|
|
5703
|
+
/**
|
|
5704
|
+
* List repository tags
|
|
5705
|
+
*
|
|
5706
|
+
* @param projectId The ID or URL-encoded path of the project
|
|
5707
|
+
* @param options Optional parameters for filtering and pagination
|
|
5708
|
+
* @returns Array of GitLab tags
|
|
5709
|
+
*/
|
|
5710
|
+
async function listTags(projectId, options = {}) {
|
|
5711
|
+
const effectiveProjectId = getEffectiveProjectId(projectId);
|
|
5712
|
+
const url = new URL(`${getEffectiveApiUrl()}/projects/${encodeURIComponent(effectiveProjectId)}/repository/tags`);
|
|
5713
|
+
Object.entries(options).forEach(([key, value]) => {
|
|
5714
|
+
if (value !== undefined) {
|
|
5715
|
+
url.searchParams.append(key, value.toString());
|
|
5716
|
+
}
|
|
5717
|
+
});
|
|
5718
|
+
const response = await fetch(url.toString(), {
|
|
5719
|
+
...getFetchConfig(),
|
|
5720
|
+
});
|
|
5721
|
+
await handleGitLabError(response);
|
|
5722
|
+
const data = await response.json();
|
|
5723
|
+
return GitLabTagSchema.array().parse(data);
|
|
5724
|
+
}
|
|
5725
|
+
/**
|
|
5726
|
+
* Get a repository tag by name
|
|
5727
|
+
*
|
|
5728
|
+
* @param projectId The ID or URL-encoded path of the project
|
|
5729
|
+
* @param tagName The name of the tag
|
|
5730
|
+
* @returns GitLab tag
|
|
5731
|
+
*/
|
|
5732
|
+
async function getTag(projectId, tagName) {
|
|
5733
|
+
const effectiveProjectId = getEffectiveProjectId(projectId);
|
|
5734
|
+
const response = await fetch(`${getEffectiveApiUrl()}/projects/${encodeURIComponent(effectiveProjectId)}/repository/tags/${encodeURIComponent(tagName)}`, {
|
|
5735
|
+
...getFetchConfig(),
|
|
5736
|
+
});
|
|
5737
|
+
await handleGitLabError(response);
|
|
5738
|
+
const data = await response.json();
|
|
5739
|
+
return GitLabTagSchema.parse(data);
|
|
5740
|
+
}
|
|
5741
|
+
/**
|
|
5742
|
+
* Create a new repository tag
|
|
5743
|
+
*
|
|
5744
|
+
* @param projectId The ID or URL-encoded path of the project
|
|
5745
|
+
* @param options Options for creating the tag
|
|
5746
|
+
* @returns Created GitLab tag
|
|
5747
|
+
*/
|
|
5748
|
+
async function createTag(projectId, options) {
|
|
5749
|
+
const effectiveProjectId = getEffectiveProjectId(projectId);
|
|
5750
|
+
const response = await fetch(`${getEffectiveApiUrl()}/projects/${encodeURIComponent(effectiveProjectId)}/repository/tags`, {
|
|
5751
|
+
...getFetchConfig(),
|
|
5752
|
+
method: "POST",
|
|
5753
|
+
body: JSON.stringify(options),
|
|
5754
|
+
});
|
|
5755
|
+
await handleGitLabError(response);
|
|
5756
|
+
const data = await response.json();
|
|
5757
|
+
return GitLabTagSchema.parse(data);
|
|
5758
|
+
}
|
|
5759
|
+
/**
|
|
5760
|
+
* Delete a repository tag
|
|
5761
|
+
*
|
|
5762
|
+
* @param projectId The ID or URL-encoded path of the project
|
|
5763
|
+
* @param tagName The name of the tag
|
|
5764
|
+
*/
|
|
5765
|
+
async function deleteTag(projectId, tagName) {
|
|
5766
|
+
const effectiveProjectId = getEffectiveProjectId(projectId);
|
|
5767
|
+
const response = await fetch(`${getEffectiveApiUrl()}/projects/${encodeURIComponent(effectiveProjectId)}/repository/tags/${encodeURIComponent(tagName)}`, {
|
|
5768
|
+
...getFetchConfig(),
|
|
5769
|
+
method: "DELETE",
|
|
5770
|
+
});
|
|
5771
|
+
await handleGitLabError(response);
|
|
5772
|
+
}
|
|
5773
|
+
/**
|
|
5774
|
+
* Get the signature of a repository tag
|
|
5775
|
+
*
|
|
5776
|
+
* @param projectId The ID or URL-encoded path of the project
|
|
5777
|
+
* @param tagName The name of the tag
|
|
5778
|
+
* @returns Tag signature
|
|
5779
|
+
*/
|
|
5780
|
+
async function getTagSignature(projectId, tagName) {
|
|
5781
|
+
const effectiveProjectId = getEffectiveProjectId(projectId);
|
|
5782
|
+
const response = await fetch(`${getEffectiveApiUrl()}/projects/${encodeURIComponent(effectiveProjectId)}/repository/tags/${encodeURIComponent(tagName)}/signature`, {
|
|
5783
|
+
...getFetchConfig(),
|
|
5784
|
+
});
|
|
5785
|
+
await handleGitLabError(response);
|
|
5786
|
+
const data = await response.json();
|
|
5787
|
+
return GitLabTagSignatureSchema.parse(data);
|
|
5788
|
+
}
|
|
5703
5789
|
// Request handlers are now registered inside createServer() factory function
|
|
5704
5790
|
// to ensure each transport connection gets its own Server instance (GHSA-345p-7cg4-v4c7).
|
|
5705
5791
|
async function handleToolCall(params) {
|
|
@@ -7191,6 +7277,48 @@ async function handleToolCall(params) {
|
|
|
7191
7277
|
content: [{ type: "text", text: assetContent }],
|
|
7192
7278
|
};
|
|
7193
7279
|
}
|
|
7280
|
+
case "list_tags": {
|
|
7281
|
+
const args = ListTagsSchema.parse(params.arguments);
|
|
7282
|
+
const { project_id, ...options } = args;
|
|
7283
|
+
const tags = await listTags(project_id, options);
|
|
7284
|
+
return {
|
|
7285
|
+
content: [{ type: "text", text: JSON.stringify(tags, null, 2) }],
|
|
7286
|
+
};
|
|
7287
|
+
}
|
|
7288
|
+
case "get_tag": {
|
|
7289
|
+
const args = GetTagSchema.parse(params.arguments);
|
|
7290
|
+
const tag = await getTag(args.project_id, args.tag_name);
|
|
7291
|
+
return {
|
|
7292
|
+
content: [{ type: "text", text: JSON.stringify(tag, null, 2) }],
|
|
7293
|
+
};
|
|
7294
|
+
}
|
|
7295
|
+
case "create_tag": {
|
|
7296
|
+
const args = CreateTagSchema.parse(params.arguments);
|
|
7297
|
+
const { project_id, ...options } = args;
|
|
7298
|
+
const tag = await createTag(project_id, options);
|
|
7299
|
+
return {
|
|
7300
|
+
content: [{ type: "text", text: JSON.stringify(tag, null, 2) }],
|
|
7301
|
+
};
|
|
7302
|
+
}
|
|
7303
|
+
case "delete_tag": {
|
|
7304
|
+
const args = DeleteTagSchema.parse(params.arguments);
|
|
7305
|
+
await deleteTag(args.project_id, args.tag_name);
|
|
7306
|
+
return {
|
|
7307
|
+
content: [
|
|
7308
|
+
{
|
|
7309
|
+
type: "text",
|
|
7310
|
+
text: JSON.stringify({ status: "success", message: `Tag '${args.tag_name}' deleted successfully` }, null, 2),
|
|
7311
|
+
},
|
|
7312
|
+
],
|
|
7313
|
+
};
|
|
7314
|
+
}
|
|
7315
|
+
case "get_tag_signature": {
|
|
7316
|
+
const args = GetTagSignatureSchema.parse(params.arguments);
|
|
7317
|
+
const signature = await getTagSignature(args.project_id, args.tag_name);
|
|
7318
|
+
return {
|
|
7319
|
+
content: [{ type: "text", text: JSON.stringify(signature, null, 2) }],
|
|
7320
|
+
};
|
|
7321
|
+
}
|
|
7194
7322
|
case "list_webhooks": {
|
|
7195
7323
|
const args = ListWebhooksSchema.parse(params.arguments);
|
|
7196
7324
|
const webhooks = await listWebhooks(args);
|
package/build/schemas.js
CHANGED
|
@@ -2570,6 +2570,84 @@ export const DownloadReleaseAssetSchema = z.object({
|
|
|
2570
2570
|
.string()
|
|
2571
2571
|
.describe("Path to the release asset file as specified when creating or updating its link"),
|
|
2572
2572
|
});
|
|
2573
|
+
// Tag schemas
|
|
2574
|
+
export const ListTagsSchema = z
|
|
2575
|
+
.object({
|
|
2576
|
+
project_id: z.coerce.string().describe("Project ID or URL-encoded path"),
|
|
2577
|
+
order_by: z
|
|
2578
|
+
.enum(["name", "updated", "version"])
|
|
2579
|
+
.optional()
|
|
2580
|
+
.describe("Return tags ordered by name, updated, or version. Default is updated."),
|
|
2581
|
+
sort: z.enum(["asc", "desc"]).optional().describe("Sort direction"),
|
|
2582
|
+
search: z
|
|
2583
|
+
.string()
|
|
2584
|
+
.optional()
|
|
2585
|
+
.describe("Restrict on tag name. You can use ^term and term$ to find tags that begin and end with term. No other regular expressions are supported."),
|
|
2586
|
+
})
|
|
2587
|
+
.merge(PaginationOptionsSchema);
|
|
2588
|
+
export const GetTagSchema = z.object({
|
|
2589
|
+
project_id: z.coerce.string().describe("Project ID or URL-encoded path"),
|
|
2590
|
+
tag_name: z.string().describe("The name of the tag"),
|
|
2591
|
+
});
|
|
2592
|
+
export const CreateTagSchema = z.object({
|
|
2593
|
+
project_id: z.coerce.string().describe("Project ID or URL-encoded path"),
|
|
2594
|
+
tag_name: z.string().describe("The name of the tag"),
|
|
2595
|
+
ref: z.string().describe("Create tag using commit SHA, another tag name, or branch name"),
|
|
2596
|
+
message: z.string().optional().describe("Create annotated tag with message"),
|
|
2597
|
+
});
|
|
2598
|
+
export const DeleteTagSchema = z.object({
|
|
2599
|
+
project_id: z.coerce.string().describe("Project ID or URL-encoded path"),
|
|
2600
|
+
tag_name: z.string().describe("The name of the tag"),
|
|
2601
|
+
});
|
|
2602
|
+
export const GetTagSignatureSchema = z.object({
|
|
2603
|
+
project_id: z.coerce.string().describe("Project ID or URL-encoded path"),
|
|
2604
|
+
tag_name: z.string().describe("The name of the tag"),
|
|
2605
|
+
});
|
|
2606
|
+
export const GitLabTagSchema = z.object({
|
|
2607
|
+
name: z.string(),
|
|
2608
|
+
message: z.string().nullable(),
|
|
2609
|
+
target: z.string(),
|
|
2610
|
+
commit: z.object({
|
|
2611
|
+
id: z.string(),
|
|
2612
|
+
short_id: z.string(),
|
|
2613
|
+
title: z.string(),
|
|
2614
|
+
created_at: z.string(),
|
|
2615
|
+
parent_ids: z.array(z.string()),
|
|
2616
|
+
message: z.string(),
|
|
2617
|
+
author_name: z.string(),
|
|
2618
|
+
author_email: z.string(),
|
|
2619
|
+
authored_date: z.string(),
|
|
2620
|
+
committer_name: z.string(),
|
|
2621
|
+
committer_email: z.string(),
|
|
2622
|
+
committed_date: z.string(),
|
|
2623
|
+
}),
|
|
2624
|
+
release: z
|
|
2625
|
+
.object({
|
|
2626
|
+
tag_name: z.string(),
|
|
2627
|
+
description: z.string(),
|
|
2628
|
+
})
|
|
2629
|
+
.nullable(),
|
|
2630
|
+
protected: z.boolean(),
|
|
2631
|
+
created_at: z.string().nullable(),
|
|
2632
|
+
});
|
|
2633
|
+
export const GitLabTagSignatureSchema = z.object({
|
|
2634
|
+
signature_type: z.literal("X509"),
|
|
2635
|
+
verification_status: z.string(),
|
|
2636
|
+
x509_certificate: z.object({
|
|
2637
|
+
id: z.number(),
|
|
2638
|
+
subject: z.string(),
|
|
2639
|
+
subject_key_identifier: z.string(),
|
|
2640
|
+
email: z.string().nullable().optional(),
|
|
2641
|
+
serial_number: z.number(),
|
|
2642
|
+
certificate_status: z.string(),
|
|
2643
|
+
x509_issuer: z.object({
|
|
2644
|
+
id: z.number(),
|
|
2645
|
+
subject: z.string(),
|
|
2646
|
+
subject_key_identifier: z.string(),
|
|
2647
|
+
crl_url: z.string().nullable().optional(),
|
|
2648
|
+
}),
|
|
2649
|
+
}),
|
|
2650
|
+
});
|
|
2573
2651
|
// --- Work item schemas (GraphQL-based) ---
|
|
2574
2652
|
// Case-insensitive work item type enum (accepts "ISSUE", "Issue", "issue")
|
|
2575
2653
|
const workItemTypeEnum = z.string().transform(v => v.toLowerCase()).pipe(z.enum(["issue", "task", "incident", "test_case", "epic", "key_result", "objective", "requirement", "ticket"]));
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import { after, before, describe, test } from "node:test";
|
|
2
|
+
import assert from "node:assert";
|
|
3
|
+
import { spawn } from "child_process";
|
|
4
|
+
import { MockGitLabServer, findMockServerPort } from "./utils/mock-gitlab-server.js";
|
|
5
|
+
const MOCK_TOKEN = "glpat-mock-token-tags";
|
|
6
|
+
const TEST_PROJECT_ID = "123";
|
|
7
|
+
const TEST_TAG_NAME = "v1.0.0";
|
|
8
|
+
function buildTag(overrides = {}) {
|
|
9
|
+
return {
|
|
10
|
+
name: TEST_TAG_NAME,
|
|
11
|
+
message: "Annotated release tag",
|
|
12
|
+
target: "abc123def4567890",
|
|
13
|
+
commit: {
|
|
14
|
+
id: "abc123def4567890",
|
|
15
|
+
short_id: "abc123de",
|
|
16
|
+
title: "Release v1.0.0",
|
|
17
|
+
created_at: "2026-03-13T10:00:00.000Z",
|
|
18
|
+
parent_ids: ["1111111111111111"],
|
|
19
|
+
message: "Release v1.0.0",
|
|
20
|
+
author_name: "Test User",
|
|
21
|
+
author_email: "test@example.com",
|
|
22
|
+
authored_date: "2026-03-13T09:55:00.000Z",
|
|
23
|
+
committer_name: "Test User",
|
|
24
|
+
committer_email: "test@example.com",
|
|
25
|
+
committed_date: "2026-03-13T10:00:00.000Z",
|
|
26
|
+
},
|
|
27
|
+
release: {
|
|
28
|
+
tag_name: TEST_TAG_NAME,
|
|
29
|
+
description: "Release notes",
|
|
30
|
+
},
|
|
31
|
+
protected: false,
|
|
32
|
+
created_at: "2026-03-13T10:00:00.000Z",
|
|
33
|
+
...overrides,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
async function callTool(toolName, args, env) {
|
|
37
|
+
return new Promise((resolve, reject) => {
|
|
38
|
+
const proc = spawn("node", ["build/index.js"], {
|
|
39
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
40
|
+
env: {
|
|
41
|
+
...process.env,
|
|
42
|
+
...env,
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
let output = "";
|
|
46
|
+
let errorOutput = "";
|
|
47
|
+
proc.stdout?.on("data", (d) => (output += d));
|
|
48
|
+
proc.stderr?.on("data", (d) => (errorOutput += d));
|
|
49
|
+
proc.on("close", code => {
|
|
50
|
+
if (code !== 0) {
|
|
51
|
+
return reject(new Error(`Process exited with code ${code}: ${errorOutput}`));
|
|
52
|
+
}
|
|
53
|
+
const line = output.split("\n").find(l => l.startsWith("{"));
|
|
54
|
+
if (!line) {
|
|
55
|
+
return reject(new Error("No JSON output found"));
|
|
56
|
+
}
|
|
57
|
+
try {
|
|
58
|
+
const response = JSON.parse(line);
|
|
59
|
+
if (response.error) {
|
|
60
|
+
reject(response.error);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
const content = response.result?.content?.[0]?.text;
|
|
64
|
+
if (!content) {
|
|
65
|
+
resolve(response.result);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
try {
|
|
69
|
+
resolve(JSON.parse(content));
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
resolve(content);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
reject(error);
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
proc.stdin?.end(JSON.stringify({
|
|
80
|
+
jsonrpc: "2.0",
|
|
81
|
+
id: 1,
|
|
82
|
+
method: "tools/call",
|
|
83
|
+
params: { name: toolName, arguments: args },
|
|
84
|
+
}) + "\n");
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
describe("tag tools", () => {
|
|
88
|
+
let mockGitLab;
|
|
89
|
+
let mockGitLabUrl;
|
|
90
|
+
before(async () => {
|
|
91
|
+
const mockPort = await findMockServerPort(20000, 50);
|
|
92
|
+
mockGitLab = new MockGitLabServer({
|
|
93
|
+
port: mockPort,
|
|
94
|
+
validTokens: [MOCK_TOKEN],
|
|
95
|
+
});
|
|
96
|
+
mockGitLab.addMockHandler("get", `/projects/${TEST_PROJECT_ID}/repository/tags`, (req, res) => {
|
|
97
|
+
assert.strictEqual(req.query.search, "^v");
|
|
98
|
+
assert.strictEqual(req.query.order_by, "version");
|
|
99
|
+
assert.strictEqual(req.query.sort, "desc");
|
|
100
|
+
assert.strictEqual(req.query.page, "2");
|
|
101
|
+
assert.strictEqual(req.query.per_page, "10");
|
|
102
|
+
res.json([buildTag()]);
|
|
103
|
+
});
|
|
104
|
+
mockGitLab.addMockHandler("get", `/projects/${TEST_PROJECT_ID}/repository/tags/${encodeURIComponent(TEST_TAG_NAME)}`, (_req, res) => {
|
|
105
|
+
res.json(buildTag());
|
|
106
|
+
});
|
|
107
|
+
mockGitLab.addMockHandler("post", `/projects/${TEST_PROJECT_ID}/repository/tags`, (req, res) => {
|
|
108
|
+
assert.deepStrictEqual(req.body, {
|
|
109
|
+
tag_name: TEST_TAG_NAME,
|
|
110
|
+
ref: "main",
|
|
111
|
+
message: "Release tag",
|
|
112
|
+
});
|
|
113
|
+
res.json(buildTag({ created_at: null }));
|
|
114
|
+
});
|
|
115
|
+
mockGitLab.addMockHandler("delete", `/projects/${TEST_PROJECT_ID}/repository/tags/${encodeURIComponent(TEST_TAG_NAME)}`, (_req, res) => {
|
|
116
|
+
res.status(204).send();
|
|
117
|
+
});
|
|
118
|
+
mockGitLab.addMockHandler("get", `/projects/${TEST_PROJECT_ID}/repository/tags/${encodeURIComponent(TEST_TAG_NAME)}/signature`, (_req, res) => {
|
|
119
|
+
res.json({
|
|
120
|
+
signature_type: "X509",
|
|
121
|
+
verification_status: "unverified",
|
|
122
|
+
x509_certificate: {
|
|
123
|
+
id: 1,
|
|
124
|
+
subject: "CN=Test User,O=Example",
|
|
125
|
+
subject_key_identifier: "A1725E379E7B25B2",
|
|
126
|
+
email: null,
|
|
127
|
+
serial_number: 123456789,
|
|
128
|
+
certificate_status: "good",
|
|
129
|
+
x509_issuer: {
|
|
130
|
+
id: 1,
|
|
131
|
+
subject: "CN=Example CA,O=Example",
|
|
132
|
+
subject_key_identifier: "C6411E6F5B9E2CFD",
|
|
133
|
+
crl_url: null,
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
await mockGitLab.start();
|
|
139
|
+
mockGitLabUrl = mockGitLab.getUrl();
|
|
140
|
+
});
|
|
141
|
+
after(async () => {
|
|
142
|
+
await mockGitLab.stop();
|
|
143
|
+
});
|
|
144
|
+
const env = () => ({
|
|
145
|
+
GITLAB_API_URL: `${mockGitLabUrl}/api/v4`,
|
|
146
|
+
GITLAB_PERSONAL_ACCESS_TOKEN: MOCK_TOKEN,
|
|
147
|
+
GITLAB_TOOLSETS: "tags",
|
|
148
|
+
});
|
|
149
|
+
test("list_tags returns parsed tags with query filters", async () => {
|
|
150
|
+
const result = await callTool("list_tags", {
|
|
151
|
+
project_id: TEST_PROJECT_ID,
|
|
152
|
+
search: "^v",
|
|
153
|
+
order_by: "version",
|
|
154
|
+
sort: "desc",
|
|
155
|
+
page: 2,
|
|
156
|
+
per_page: 10,
|
|
157
|
+
}, env());
|
|
158
|
+
assert.ok(Array.isArray(result));
|
|
159
|
+
assert.strictEqual(result.length, 1);
|
|
160
|
+
assert.strictEqual(result[0].name, TEST_TAG_NAME);
|
|
161
|
+
});
|
|
162
|
+
test("get_tag returns a single tag", async () => {
|
|
163
|
+
const result = await callTool("get_tag", { project_id: TEST_PROJECT_ID, tag_name: TEST_TAG_NAME }, env());
|
|
164
|
+
assert.strictEqual(result.name, TEST_TAG_NAME);
|
|
165
|
+
assert.strictEqual(result.commit.short_id, "abc123de");
|
|
166
|
+
});
|
|
167
|
+
test("create_tag posts the expected payload", async () => {
|
|
168
|
+
const result = await callTool("create_tag", {
|
|
169
|
+
project_id: TEST_PROJECT_ID,
|
|
170
|
+
tag_name: TEST_TAG_NAME,
|
|
171
|
+
ref: "main",
|
|
172
|
+
message: "Release tag",
|
|
173
|
+
}, env());
|
|
174
|
+
assert.strictEqual(result.name, TEST_TAG_NAME);
|
|
175
|
+
assert.strictEqual(result.release.description, "Release notes");
|
|
176
|
+
assert.strictEqual(result.created_at, null);
|
|
177
|
+
});
|
|
178
|
+
test("delete_tag returns a success payload", async () => {
|
|
179
|
+
const result = await callTool("delete_tag", { project_id: TEST_PROJECT_ID, tag_name: TEST_TAG_NAME }, env());
|
|
180
|
+
assert.deepStrictEqual(result, {
|
|
181
|
+
status: "success",
|
|
182
|
+
message: `Tag '${TEST_TAG_NAME}' deleted successfully`,
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
test("get_tag_signature returns signature data", async () => {
|
|
186
|
+
const result = await callTool("get_tag_signature", { project_id: TEST_PROJECT_ID, tag_name: TEST_TAG_NAME }, env());
|
|
187
|
+
assert.deepStrictEqual(result, {
|
|
188
|
+
signature_type: "X509",
|
|
189
|
+
verification_status: "unverified",
|
|
190
|
+
x509_certificate: {
|
|
191
|
+
id: 1,
|
|
192
|
+
subject: "CN=Test User,O=Example",
|
|
193
|
+
subject_key_identifier: "A1725E379E7B25B2",
|
|
194
|
+
email: null,
|
|
195
|
+
serial_number: 123456789,
|
|
196
|
+
certificate_status: "good",
|
|
197
|
+
x509_issuer: {
|
|
198
|
+
id: 1,
|
|
199
|
+
subject: "CN=Example CA,O=Example",
|
|
200
|
+
subject_key_identifier: "C6411E6F5B9E2CFD",
|
|
201
|
+
crl_url: null,
|
|
202
|
+
},
|
|
203
|
+
},
|
|
204
|
+
});
|
|
205
|
+
});
|
|
206
|
+
});
|
|
@@ -26,6 +26,7 @@ const TOOLSET_TOOL_COUNTS = {
|
|
|
26
26
|
milestones: 9,
|
|
27
27
|
wiki: 10,
|
|
28
28
|
releases: 7,
|
|
29
|
+
tags: 5,
|
|
29
30
|
users: 5,
|
|
30
31
|
search: 3,
|
|
31
32
|
workitems: 18,
|
|
@@ -40,7 +41,16 @@ const DEFAULT_TOOLSETS = [
|
|
|
40
41
|
"labels",
|
|
41
42
|
"users",
|
|
42
43
|
];
|
|
43
|
-
const NON_DEFAULT_TOOLSETS = [
|
|
44
|
+
const NON_DEFAULT_TOOLSETS = [
|
|
45
|
+
"pipelines",
|
|
46
|
+
"milestones",
|
|
47
|
+
"wiki",
|
|
48
|
+
"releases",
|
|
49
|
+
"tags",
|
|
50
|
+
"workitems",
|
|
51
|
+
"webhooks",
|
|
52
|
+
"search",
|
|
53
|
+
];
|
|
44
54
|
// discover_tools meta-tool is always force-injected (Step 5.5)
|
|
45
55
|
const DISCOVER_TOOLS_COUNT = 1;
|
|
46
56
|
const DEFAULT_TOOL_COUNT = DEFAULT_TOOLSETS.reduce((sum, id) => sum + TOOLSET_TOOL_COUNTS[id], 0) + DISCOVER_TOOLS_COUNT;
|
|
@@ -57,6 +67,7 @@ const TOOLSET_SAMPLE_TOOLS = {
|
|
|
57
67
|
milestones: ["list_milestones", "create_milestone", "get_milestone_burndown_events"],
|
|
58
68
|
wiki: ["list_wiki_pages", "create_wiki_page", "list_group_wiki_pages", "create_group_wiki_page"],
|
|
59
69
|
releases: ["list_releases", "create_release", "download_release_asset"],
|
|
70
|
+
tags: ["list_tags", "create_tag", "get_tag_signature"],
|
|
60
71
|
users: ["get_users", "upload_markdown", "download_attachment"],
|
|
61
72
|
search: ["search_code", "search_project_code", "search_group_code"],
|
|
62
73
|
webhooks: ["list_webhooks", "list_webhook_events", "get_webhook_event"],
|
package/build/tools/registry.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { zodToJsonSchema } from "zod-to-json-schema";
|
|
2
2
|
import { toJSONSchema } from "../utils/schema.js";
|
|
3
3
|
import { USE_GITLAB_WIKI, USE_MILESTONE, USE_PIPELINE, } from "../config.js";
|
|
4
|
-
import { ApproveMergeRequestSchema, BulkPublishDraftNotesSchema, CancelPipelineJobSchema, CancelPipelineSchema, ConvertWorkItemTypeSchema, CreateBranchSchema, CreateDraftNoteSchema, CreateGroupWikiPageSchema, CreateIssueLinkSchema, CreateIssueNoteSchema, CreateIssueSchema, CreateIssueEmojiReactionSchema, CreateIssueNoteEmojiReactionSchema, ListIssueEmojiReactionsSchema, ListIssueNoteEmojiReactionsSchema, CreateLabelSchema, CreateMergeRequestDiscussionNoteSchema, CreateMergeRequestEmojiReactionSchema, ListMergeRequestEmojiReactionsSchema, ListMergeRequestNoteEmojiReactionsSchema, CreateMergeRequestNoteSchema, CreateMergeRequestNoteEmojiReactionSchema, CreateMergeRequestSchema, CreateMergeRequestThreadSchema, CreateNoteSchema, CreateOrUpdateFileSchema, CreatePipelineSchema, CreateProjectMilestoneSchema, CreateReleaseEvidenceSchema, CreateReleaseSchema, CreateRepositorySchema, CreateTimelineEventSchema, CreateWikiPageSchema, CreateWorkItemNoteSchema, CreateWorkItemEmojiReactionSchema, CreateWorkItemNoteEmojiReactionSchema, ListWorkItemEmojiReactionsSchema, ListWorkItemNoteEmojiReactionsSchema, CreateWorkItemSchema, DeleteDraftNoteSchema, DeleteGroupWikiPageSchema, DeleteIssueLinkSchema, DeleteIssueSchema, DeleteIssueEmojiReactionSchema, DeleteIssueNoteEmojiReactionSchema, DeleteLabelSchema, DeleteMergeRequestDiscussionNoteSchema, DeleteMergeRequestNoteSchema, DeleteMergeRequestEmojiReactionSchema, DeleteMergeRequestNoteEmojiReactionSchema, DeleteProjectMilestoneSchema, DeleteReleaseSchema, DeleteWikiPageSchema, DeleteWorkItemEmojiReactionSchema, DeleteWorkItemNoteEmojiReactionSchema, DownloadAttachmentSchema, DownloadJobArtifactsSchema, DownloadReleaseAssetSchema, EditProjectMilestoneSchema, ExecuteGraphQLSchema, ForkRepositorySchema, GetBranchDiffsSchema, GetCommitDiffSchema, GetCommitSchema, GetDeploymentSchema, GetDraftNoteSchema, GetEnvironmentSchema, GetFileContentsSchema, GetGroupWikiPageSchema, GetIssueLinkSchema, GetIssueSchema, GetJobArtifactFileSchema, GetLabelSchema, GetMergeRequestApprovalStateSchema, GetMergeRequestConflictsSchema, GetMergeRequestDiffsSchema, GetMergeRequestFileDiffSchema, GetMergeRequestNoteSchema, GetMergeRequestNotesSchema, GetMergeRequestSchema, GetMergeRequestVersionSchema, GetMilestoneBurndownEventsSchema, GetMilestoneIssuesSchema, GetMilestoneMergeRequestsSchema, GetNamespaceSchema, GetPipelineJobOutputSchema, GetPipelineSchema, GetProjectEventsSchema, GetProjectMilestoneSchema, GetProjectSchema, GetReleaseSchema, GetRepositoryTreeSchema, GetTimelineEventsSchema, GetUsersSchema, GetWebhookEventSchema, GetWikiPageSchema, GetWorkItemSchema, ListCommitsSchema, ListCustomFieldDefinitionsSchema, ListDeploymentsSchema, ListDraftNotesSchema, ListEnvironmentsSchema, ListEventsSchema, ListGroupIterationsSchema, ListGroupProjectsSchema, ListGroupWikiPagesSchema, ListIssueDiscussionsSchema, ListIssueLinksSchema, ListIssuesSchema, ListJobArtifactsSchema, ListLabelsSchema, ListMergeRequestChangedFilesSchema, ListMergeRequestDiffsSchema, ListMergeRequestDiscussionsSchema, ListMergeRequestVersionsSchema, ListMergeRequestsSchema, ListNamespacesSchema, ListPipelineJobsSchema, ListPipelineTriggerJobsSchema, ListPipelinesSchema, ListProjectMembersSchema, ListProjectMilestonesSchema, ListProjectsSchema, ListReleasesSchema, ListWebhookEventsSchema, ListWebhooksSchema, ListWikiPagesSchema, ListWorkItemNotesSchema, ListWorkItemStatusesSchema, ListWorkItemsSchema, MarkdownUploadSchema, MergeMergeRequestSchema, MoveWorkItemSchema, MyIssuesSchema, PlayPipelineJobSchema, PromoteProjectMilestoneSchema, PublishDraftNoteSchema, PushFilesSchema, ResolveMergeRequestThreadSchema, RetryPipelineJobSchema, RetryPipelineSchema, SearchCodeSchema, SearchGroupCodeSchema, SearchProjectCodeSchema, SearchRepositoriesSchema, UnapproveMergeRequestSchema, UpdateDraftNoteSchema, UpdateGroupWikiPageSchema, UpdateIssueNoteSchema, UpdateIssueSchema, UpdateLabelSchema, UpdateMergeRequestDiscussionNoteSchema, UpdateMergeRequestNoteSchema, UpdateMergeRequestSchema, UpdateReleaseSchema, UpdateWikiPageSchema, UpdateWorkItemSchema, VerifyNamespaceSchema, } from "../schemas.js";
|
|
4
|
+
import { ApproveMergeRequestSchema, BulkPublishDraftNotesSchema, CancelPipelineJobSchema, CancelPipelineSchema, ConvertWorkItemTypeSchema, CreateBranchSchema, CreateDraftNoteSchema, CreateGroupWikiPageSchema, CreateIssueLinkSchema, CreateIssueNoteSchema, CreateIssueSchema, CreateIssueEmojiReactionSchema, CreateIssueNoteEmojiReactionSchema, ListIssueEmojiReactionsSchema, ListIssueNoteEmojiReactionsSchema, CreateLabelSchema, CreateMergeRequestDiscussionNoteSchema, CreateMergeRequestEmojiReactionSchema, ListMergeRequestEmojiReactionsSchema, ListMergeRequestNoteEmojiReactionsSchema, CreateMergeRequestNoteSchema, CreateMergeRequestNoteEmojiReactionSchema, CreateMergeRequestSchema, CreateMergeRequestThreadSchema, CreateNoteSchema, CreateOrUpdateFileSchema, CreatePipelineSchema, CreateProjectMilestoneSchema, CreateReleaseEvidenceSchema, CreateReleaseSchema, CreateRepositorySchema, CreateTagSchema, CreateTimelineEventSchema, CreateWikiPageSchema, CreateWorkItemNoteSchema, CreateWorkItemEmojiReactionSchema, CreateWorkItemNoteEmojiReactionSchema, ListWorkItemEmojiReactionsSchema, ListWorkItemNoteEmojiReactionsSchema, CreateWorkItemSchema, DeleteDraftNoteSchema, DeleteGroupWikiPageSchema, DeleteIssueLinkSchema, DeleteIssueSchema, DeleteIssueEmojiReactionSchema, DeleteIssueNoteEmojiReactionSchema, DeleteLabelSchema, DeleteMergeRequestDiscussionNoteSchema, DeleteMergeRequestNoteSchema, DeleteMergeRequestEmojiReactionSchema, DeleteMergeRequestNoteEmojiReactionSchema, DeleteProjectMilestoneSchema, DeleteReleaseSchema, DeleteTagSchema, DeleteWikiPageSchema, DeleteWorkItemEmojiReactionSchema, DeleteWorkItemNoteEmojiReactionSchema, DownloadAttachmentSchema, DownloadJobArtifactsSchema, DownloadReleaseAssetSchema, EditProjectMilestoneSchema, ExecuteGraphQLSchema, ForkRepositorySchema, GetBranchDiffsSchema, GetCommitDiffSchema, GetCommitSchema, GetDeploymentSchema, GetDraftNoteSchema, GetEnvironmentSchema, GetFileContentsSchema, GetGroupWikiPageSchema, GetIssueLinkSchema, GetIssueSchema, GetJobArtifactFileSchema, GetLabelSchema, GetMergeRequestApprovalStateSchema, GetMergeRequestConflictsSchema, GetMergeRequestDiffsSchema, GetMergeRequestFileDiffSchema, GetMergeRequestNoteSchema, GetMergeRequestNotesSchema, GetMergeRequestSchema, GetMergeRequestVersionSchema, GetMilestoneBurndownEventsSchema, GetMilestoneIssuesSchema, GetMilestoneMergeRequestsSchema, GetNamespaceSchema, GetPipelineJobOutputSchema, GetPipelineSchema, GetProjectEventsSchema, GetProjectMilestoneSchema, GetProjectSchema, GetReleaseSchema, GetRepositoryTreeSchema, GetTagSchema, GetTagSignatureSchema, GetTimelineEventsSchema, GetUsersSchema, GetWebhookEventSchema, GetWikiPageSchema, GetWorkItemSchema, ListCommitsSchema, ListCustomFieldDefinitionsSchema, ListDeploymentsSchema, ListDraftNotesSchema, ListEnvironmentsSchema, ListEventsSchema, ListGroupIterationsSchema, ListGroupProjectsSchema, ListGroupWikiPagesSchema, ListIssueDiscussionsSchema, ListIssueLinksSchema, ListIssuesSchema, ListJobArtifactsSchema, ListLabelsSchema, ListMergeRequestChangedFilesSchema, ListMergeRequestDiffsSchema, ListMergeRequestDiscussionsSchema, ListMergeRequestVersionsSchema, ListMergeRequestsSchema, ListNamespacesSchema, ListPipelineJobsSchema, ListPipelineTriggerJobsSchema, ListPipelinesSchema, ListProjectMembersSchema, ListProjectMilestonesSchema, ListProjectsSchema, ListReleasesSchema, ListTagsSchema, ListWebhookEventsSchema, ListWebhooksSchema, ListWikiPagesSchema, ListWorkItemNotesSchema, ListWorkItemStatusesSchema, ListWorkItemsSchema, MarkdownUploadSchema, MergeMergeRequestSchema, MoveWorkItemSchema, MyIssuesSchema, PlayPipelineJobSchema, PromoteProjectMilestoneSchema, PublishDraftNoteSchema, PushFilesSchema, ResolveMergeRequestThreadSchema, RetryPipelineJobSchema, RetryPipelineSchema, SearchCodeSchema, SearchGroupCodeSchema, SearchProjectCodeSchema, SearchRepositoriesSchema, UnapproveMergeRequestSchema, UpdateDraftNoteSchema, UpdateGroupWikiPageSchema, UpdateIssueNoteSchema, UpdateIssueSchema, UpdateLabelSchema, UpdateMergeRequestDiscussionNoteSchema, UpdateMergeRequestNoteSchema, UpdateMergeRequestSchema, UpdateReleaseSchema, UpdateWikiPageSchema, UpdateWorkItemSchema, VerifyNamespaceSchema, } from "../schemas.js";
|
|
5
5
|
// Define all available tools
|
|
6
6
|
export const allTools = [
|
|
7
7
|
{
|
|
@@ -681,6 +681,31 @@ export const allTools = [
|
|
|
681
681
|
description: "Download a release asset file by direct asset path",
|
|
682
682
|
inputSchema: toJSONSchema(DownloadReleaseAssetSchema),
|
|
683
683
|
},
|
|
684
|
+
{
|
|
685
|
+
name: "list_tags",
|
|
686
|
+
description: "List repository tags for a project",
|
|
687
|
+
inputSchema: toJSONSchema(ListTagsSchema),
|
|
688
|
+
},
|
|
689
|
+
{
|
|
690
|
+
name: "get_tag",
|
|
691
|
+
description: "Get a repository tag by name",
|
|
692
|
+
inputSchema: toJSONSchema(GetTagSchema),
|
|
693
|
+
},
|
|
694
|
+
{
|
|
695
|
+
name: "create_tag",
|
|
696
|
+
description: "Create a new repository tag",
|
|
697
|
+
inputSchema: toJSONSchema(CreateTagSchema),
|
|
698
|
+
},
|
|
699
|
+
{
|
|
700
|
+
name: "delete_tag",
|
|
701
|
+
description: "Delete a repository tag",
|
|
702
|
+
inputSchema: toJSONSchema(DeleteTagSchema),
|
|
703
|
+
},
|
|
704
|
+
{
|
|
705
|
+
name: "get_tag_signature",
|
|
706
|
+
description: "Get the X.509 signature of a signed tag (404 if unsigned)",
|
|
707
|
+
inputSchema: toJSONSchema(GetTagSignatureSchema),
|
|
708
|
+
},
|
|
684
709
|
// --- Work item tools (GraphQL-based) ---
|
|
685
710
|
{
|
|
686
711
|
name: "get_work_item",
|
|
@@ -892,6 +917,9 @@ export const readOnlyTools = new Set([
|
|
|
892
917
|
"list_releases",
|
|
893
918
|
"get_release",
|
|
894
919
|
"download_release_asset",
|
|
920
|
+
"list_tags",
|
|
921
|
+
"get_tag",
|
|
922
|
+
"get_tag_signature",
|
|
895
923
|
"get_merge_request_approval_state",
|
|
896
924
|
"get_work_item",
|
|
897
925
|
"list_work_items",
|
|
@@ -919,6 +947,7 @@ export const destructiveTools = new Set([
|
|
|
919
947
|
"delete_group_wiki_page",
|
|
920
948
|
"delete_milestone",
|
|
921
949
|
"delete_release",
|
|
950
|
+
"delete_tag",
|
|
922
951
|
"delete_merge_request_note",
|
|
923
952
|
"delete_merge_request_discussion_note",
|
|
924
953
|
"delete_draft_note",
|
|
@@ -1169,6 +1198,17 @@ export const TOOLSET_DEFINITIONS = [
|
|
|
1169
1198
|
"download_release_asset",
|
|
1170
1199
|
]),
|
|
1171
1200
|
},
|
|
1201
|
+
{
|
|
1202
|
+
id: "tags",
|
|
1203
|
+
isDefault: false,
|
|
1204
|
+
tools: new Set([
|
|
1205
|
+
"list_tags",
|
|
1206
|
+
"get_tag",
|
|
1207
|
+
"create_tag",
|
|
1208
|
+
"delete_tag",
|
|
1209
|
+
"get_tag_signature",
|
|
1210
|
+
]),
|
|
1211
|
+
},
|
|
1172
1212
|
{
|
|
1173
1213
|
id: "users",
|
|
1174
1214
|
isDefault: true,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zereight/mcp-gitlab",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.7",
|
|
4
4
|
"mcpName": "io.github.zereight/gitlab-mcp",
|
|
5
5
|
"description": "GitLab MCP server for projects, merge requests, issues, pipelines, wiki, releases, and more",
|
|
6
6
|
"keywords": [
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"changelog": "auto-changelog -p",
|
|
52
52
|
"test": "npm run test:all",
|
|
53
53
|
"test:all": "npm run build && npm run test:mock && npm run test:live",
|
|
54
|
-
"test:mock": "node --import tsx/esm --test test/remote-auth-simple-test.ts && node --import tsx/esm --test test/mcp-oauth-tests.ts && tsx test/oauth-tests.ts && tsx test/test-list-merge-requests.ts && tsx test/test-list-project-members.ts && tsx test/test-download-attachment.ts && node --import tsx/esm --test test/test-job-artifacts.ts && node --import tsx/esm --test test/test-deployment-tools.ts && node --import tsx/esm --test test/test-merge-request-approval-state-tools.ts && node --import tsx/esm --test test/test-search-code.ts && node --import tsx/esm --test test/test-toolset-filtering.ts && node --import tsx/esm --test test/test-auth-retry.ts && node --import tsx/esm --test test/stateless/codec.test.ts test/stateless/client-id.test.ts test/stateless/callback-proxy.test.ts test/stateless/session-id.test.ts test/stateless/session-id-integration.test.ts test/stateless/config-ttl.test.ts",
|
|
54
|
+
"test:mock": "node --import tsx/esm --test test/remote-auth-simple-test.ts && node --import tsx/esm --test test/mcp-oauth-tests.ts && tsx test/oauth-tests.ts && tsx test/test-list-merge-requests.ts && tsx test/test-list-project-members.ts && tsx test/test-download-attachment.ts && node --import tsx/esm --test test/test-job-artifacts.ts && node --import tsx/esm --test test/test-deployment-tools.ts && node --import tsx/esm --test test/test-merge-request-approval-state-tools.ts && node --import tsx/esm --test test/test-search-code.ts && node --import tsx/esm --test test/test-tags.ts && node --import tsx/esm --test test/test-toolset-filtering.ts && node --import tsx/esm --test test/test-auth-retry.ts && node --import tsx/esm --test test/stateless/codec.test.ts test/stateless/client-id.test.ts test/stateless/callback-proxy.test.ts test/stateless/session-id.test.ts test/stateless/session-id-integration.test.ts test/stateless/config-ttl.test.ts",
|
|
55
55
|
"test:stateless": "npm run build && node --import tsx/esm --test test/stateless/codec.test.ts test/stateless/client-id.test.ts test/stateless/callback-proxy.test.ts test/stateless/session-id.test.ts test/stateless/session-id-integration.test.ts test/stateless/config-ttl.test.ts",
|
|
56
56
|
"test:mcp-oauth": "npm run build && node --import tsx/esm --test test/mcp-oauth-tests.ts",
|
|
57
57
|
"test:live": "node test/validate-api.js",
|