@zereight/mcp-gitlab 2.1.7 → 2.1.9
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.ko.md +25 -0
- package/README.md +150 -98
- package/README.zh-CN.md +25 -0
- package/build/index.js +183 -9
- package/build/schemas.js +160 -0
- package/build/test/schema-tests.js +228 -3
- package/build/test/streamable-http-static-token-auth.test.js +154 -0
- package/build/test/test-ci-lint.js +191 -0
- package/build/test/test-todos.js +195 -0
- package/build/test/test-toolset-filtering.js +13 -6
- package/build/tools/registry.js +52 -1
- package/package.json +2 -2
package/build/index.js
CHANGED
|
@@ -25,15 +25,13 @@ import { requireBearerAuth } from "@modelcontextprotocol/sdk/server/auth/middlew
|
|
|
25
25
|
import { GitLabClientPool } from "./gitlab-client-pool.js";
|
|
26
26
|
import { allTools, readOnlyTools, destructiveTools, parseEnabledToolsets, parseIndividualTools, buildFeatureFlagOverrides, isToolInEnabledToolset, TOOLSET_DEFINITIONS, ALL_TOOLSET_IDS, } from "./tools/registry.js";
|
|
27
27
|
import { BulkPublishDraftNotesSchema, CancelPipelineJobSchema, CancelPipelineSchema, CreateBranchSchema, CreateDraftNoteSchema, CreateIssueLinkSchema, CreateIssueNoteSchema, CreateIssueSchema, CreateIssueEmojiReactionSchema, CreateIssueNoteEmojiReactionSchema, ListIssueEmojiReactionsSchema, ListIssueNoteEmojiReactionsSchema, CreateLabelSchema, // Added
|
|
28
|
-
CreateMergeRequestNoteSchema, CreateMergeRequestDiscussionNoteSchema, CreateMergeRequestEmojiReactionSchema, CreateMergeRequestNoteEmojiReactionSchema, ListMergeRequestEmojiReactionsSchema, ListMergeRequestNoteEmojiReactionsSchema, CreateMergeRequestSchema, CreateMergeRequestThreadSchema, CreateNoteSchema, CreateOrUpdateFileSchema, CreatePipelineSchema, CreateProjectMilestoneSchema, CreateRepositorySchema, CreateWikiPageSchema, CreateGroupWikiPageSchema, DeleteDraftNoteSchema, DeleteGroupWikiPageSchema, DeleteIssueLinkSchema, DeleteIssueSchema, DeleteIssueEmojiReactionSchema, DeleteIssueNoteEmojiReactionSchema, DeleteLabelSchema, DeleteProjectMilestoneSchema, DeleteWikiPageSchema, DeleteMergeRequestNoteSchema, DeleteMergeRequestEmojiReactionSchema, DeleteMergeRequestNoteEmojiReactionSchema, EditProjectMilestoneSchema, ForkRepositorySchema, GetBranchDiffsSchema, GetCommitDiffSchema, GetCommitSchema, GetDraftNoteSchema, GetFileContentsSchema, GetIssueLinkSchema, GetIssueSchema, GetLabelSchema, GetMergeRequestDiffsSchema, GetMergeRequestSchema, GetMilestoneBurndownEventsSchema, GetMilestoneIssuesSchema, GetMilestoneMergeRequestsSchema, GetDeploymentSchema, GetEnvironmentSchema, GetNamespaceSchema,
|
|
29
|
-
// pipeline job schemas
|
|
30
|
-
GetPipelineJobOutputSchema, GetPipelineSchema, GetProjectMilestoneSchema, GetProjectSchema, GetRepositoryTreeSchema, GetUsersSchema, GetWikiPageSchema, GitLabCommitSchema, GitLabCompareResultSchema, GitLabContentSchema, GitLabCreateUpdateFileResponseSchema, GitLabDiffSchema,
|
|
28
|
+
CreateMergeRequestNoteSchema, CreateMergeRequestDiscussionNoteSchema, CreateMergeRequestEmojiReactionSchema, CreateMergeRequestNoteEmojiReactionSchema, ListMergeRequestEmojiReactionsSchema, ListMergeRequestNoteEmojiReactionsSchema, CreateMergeRequestSchema, CreateMergeRequestThreadSchema, CreateNoteSchema, CreateCommitStatusSchema, CreateOrUpdateFileSchema, CreatePipelineSchema, CreateProjectMilestoneSchema, CreateRepositorySchema, CreateWikiPageSchema, CreateGroupWikiPageSchema, DeleteDraftNoteSchema, DeleteGroupWikiPageSchema, DeleteIssueLinkSchema, DeleteIssueSchema, DeleteIssueEmojiReactionSchema, DeleteIssueNoteEmojiReactionSchema, DeleteLabelSchema, DeleteProjectMilestoneSchema, DeleteWikiPageSchema, DeleteMergeRequestNoteSchema, DeleteMergeRequestEmojiReactionSchema, DeleteMergeRequestNoteEmojiReactionSchema, EditProjectMilestoneSchema, ForkRepositorySchema, GetBranchDiffsSchema, GetCommitDiffSchema, GetCommitSchema, GetDraftNoteSchema, GetFileContentsSchema, GetIssueLinkSchema, GetIssueSchema, GetLabelSchema, GetMergeRequestDiffsSchema, GetMergeRequestSchema, GetMilestoneBurndownEventsSchema, GetMilestoneIssuesSchema, GetMilestoneMergeRequestsSchema, GetDeploymentSchema, GetEnvironmentSchema, GetNamespaceSchema, GitLabCiLintResultSchema, GetPipelineJobOutputSchema, GetPipelineSchema, GetProjectMilestoneSchema, GetProjectSchema, GetRepositoryTreeSchema, GetUsersSchema, GetWikiPageSchema, GitLabCommitSchema, GitLabCommitStatusSchema, GitLabCompareResultSchema, GitLabContentSchema, GitLabCreateUpdateFileResponseSchema, GitLabDiffSchema,
|
|
31
29
|
// Discussion Schemas
|
|
32
30
|
GitLabDiscussionNoteSchema, // Added
|
|
33
31
|
GitLabDiscussionSchema,
|
|
34
32
|
// Draft Notes Schemas
|
|
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, 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";
|
|
33
|
+
GitLabDraftNoteSchema, GitLabForkSchema, GitLabIssueLinkSchema, GitLabIssueSchema, GitLabIssueWithLinkDetailsSchema, GitLabMarkdownUploadSchema, GitLabMergeRequestSchema, GitLabMilestonesSchema, GitLabNamespaceExistsResponseSchema, GitLabNamespaceSchema, GitLabPipelineJobSchema, GitLabDeploymentSchema, GitLabEnvironmentSchema, GitLabPipelineSchema, GitLabPipelineTriggerJobSchema, GitLabProjectMemberSchema, GitLabProjectSchema, GitLabTodoSchema, GitLabReferenceSchema, GitLabRepositorySchema, GitLabSearchBlobResultSchema, GitLabSearchResponseSchema, GitLabTreeItemSchema, GitLabUserSchema, GitLabUsersResponseSchema, GitLabWikiPageSchema, GroupIteration, ListCommitStatusesSchema, ListCommitsSchema, ListDraftNotesSchema, ListGroupIterationsSchema, ListGroupProjectsSchema, ListIssueDiscussionsSchema, ListIssueLinksSchema, ListIssuesSchema, ListTodosSchema, ListLabelsSchema, ListMergeRequestDiffsSchema, // Added
|
|
34
|
+
GetMergeRequestFileDiffSchema, ListMergeRequestChangedFilesSchema, ListMergeRequestDiscussionsSchema, ListMergeRequestsSchema, ListMergeRequestVersionsSchema, GetMergeRequestVersionSchema, GitLabMergeRequestVersionSchema, GitLabMergeRequestVersionDetailSchema, ListNamespacesSchema, ListPipelineJobsSchema, ListPipelinesSchema, ListDeploymentsSchema, ListEnvironmentsSchema, ListPipelineTriggerJobsSchema, ValidateCiLintSchema, ValidateProjectCiLintSchema, ListProjectMembersSchema, ListProjectMilestonesSchema, ListProjectsSchema, ListWikiPagesSchema, GetGroupWikiPageSchema, ListGroupWikiPagesSchema, UpdateGroupWikiPageSchema, MarkdownUploadSchema, DownloadAttachmentSchema, DownloadJobArtifactsSchema, GetJobArtifactFileSchema, GitLabArtifactEntrySchema, ListJobArtifactsSchema, MergeMergeRequestSchema, ApproveMergeRequestSchema, UnapproveMergeRequestSchema, GetMergeRequestApprovalStateSchema, GetMergeRequestConflictsSchema, GitLabMergeRequestApprovalsResponseSchema, GitLabMergeRequestApprovalStateSchema, MyIssuesSchema, MarkAllTodosDoneSchema, MarkTodoDoneSchema, 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
35
|
import { randomUUID } from "node:crypto";
|
|
38
36
|
import { pino } from "pino";
|
|
39
37
|
const logger = pino({
|
|
@@ -396,9 +394,13 @@ function validateConfiguration() {
|
|
|
396
394
|
const hasCookie = !!getConfig("cookie-path", "GITLAB_AUTH_COOKIE_PATH");
|
|
397
395
|
const mcpOAuth = getConfig("mcp-oauth", "GITLAB_MCP_OAUTH") === "true";
|
|
398
396
|
const mcpServerUrl = getConfig("mcp-server-url", "MCP_SERVER_URL");
|
|
397
|
+
const streamableHttp = getConfig("streamable-http", "STREAMABLE_HTTP") === "true";
|
|
399
398
|
if (!remoteAuth && !useOAuth && !hasToken && !hasJobToken && !hasCookie && !mcpOAuth) {
|
|
400
399
|
errors.push("Either --token, --job-token, --cookie-path, --use-oauth=true, --remote-auth=true, or --mcp-oauth=true must be set (or use environment variables)");
|
|
401
400
|
}
|
|
401
|
+
if (streamableHttp && (hasToken || hasJobToken) && !remoteAuth && !mcpOAuth) {
|
|
402
|
+
errors.push("STREAMABLE_HTTP=true/--streamable-http with GITLAB_PERSONAL_ACCESS_TOKEN/--token or GITLAB_JOB_TOKEN/--job-token requires REMOTE_AUTHORIZATION=true/--remote-auth=true or GITLAB_MCP_OAUTH=true/--mcp-oauth=true");
|
|
403
|
+
}
|
|
402
404
|
if (mcpOAuth) {
|
|
403
405
|
if (!mcpServerUrl) {
|
|
404
406
|
errors.push("MCP_SERVER_URL is required when GITLAB_MCP_OAUTH=true (e.g. https://mcp.example.com)");
|
|
@@ -1097,6 +1099,36 @@ async function listIssues(projectId, options = {}) {
|
|
|
1097
1099
|
const data = await response.json();
|
|
1098
1100
|
return z.array(GitLabIssueSchema).parse(data);
|
|
1099
1101
|
}
|
|
1102
|
+
async function listTodos(options = {}) {
|
|
1103
|
+
const url = new URL(`${getEffectiveApiUrl()}/todos`);
|
|
1104
|
+
Object.entries(options).forEach(([key, value]) => {
|
|
1105
|
+
if (value !== undefined) {
|
|
1106
|
+
url.searchParams.append(key, String(value));
|
|
1107
|
+
}
|
|
1108
|
+
});
|
|
1109
|
+
const response = await fetch(url.toString(), {
|
|
1110
|
+
...getFetchConfig(),
|
|
1111
|
+
});
|
|
1112
|
+
await handleGitLabError(response);
|
|
1113
|
+
const data = await response.json();
|
|
1114
|
+
return z.array(GitLabTodoSchema).parse(data);
|
|
1115
|
+
}
|
|
1116
|
+
async function markTodoDone(id) {
|
|
1117
|
+
const response = await fetch(`${getEffectiveApiUrl()}/todos/${id}/mark_as_done`, {
|
|
1118
|
+
...getFetchConfig(),
|
|
1119
|
+
method: "POST",
|
|
1120
|
+
});
|
|
1121
|
+
await handleGitLabError(response);
|
|
1122
|
+
const data = await response.json();
|
|
1123
|
+
return GitLabTodoSchema.parse(data);
|
|
1124
|
+
}
|
|
1125
|
+
async function markAllTodosDone() {
|
|
1126
|
+
const response = await fetch(`${getEffectiveApiUrl()}/todos/mark_as_done`, {
|
|
1127
|
+
...getFetchConfig(),
|
|
1128
|
+
method: "POST",
|
|
1129
|
+
});
|
|
1130
|
+
await handleGitLabError(response);
|
|
1131
|
+
}
|
|
1100
1132
|
/**
|
|
1101
1133
|
* List merge requests globally or for a specific GitLab project
|
|
1102
1134
|
*
|
|
@@ -4769,6 +4801,38 @@ async function getPipelineJobOutput(projectId, jobId, limit, offset) {
|
|
|
4769
4801
|
}
|
|
4770
4802
|
return fullTrace;
|
|
4771
4803
|
}
|
|
4804
|
+
async function validateCiLint(projectId, options) {
|
|
4805
|
+
projectId = decodeURIComponent(projectId);
|
|
4806
|
+
const url = new URL(`${getEffectiveApiUrl()}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/ci/lint`);
|
|
4807
|
+
const response = await fetch(url.toString(), {
|
|
4808
|
+
...getFetchConfig(),
|
|
4809
|
+
method: "POST",
|
|
4810
|
+
body: JSON.stringify(options),
|
|
4811
|
+
});
|
|
4812
|
+
await handleGitLabError(response);
|
|
4813
|
+
const data = await response.json();
|
|
4814
|
+
return GitLabCiLintResultSchema.parse(data);
|
|
4815
|
+
}
|
|
4816
|
+
async function validateProjectCiLint(projectId, options) {
|
|
4817
|
+
projectId = decodeURIComponent(projectId);
|
|
4818
|
+
const url = new URL(`${getEffectiveApiUrl()}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/ci/lint`);
|
|
4819
|
+
Object.entries(options).forEach(([key, value]) => {
|
|
4820
|
+
if (value !== undefined) {
|
|
4821
|
+
if (typeof value === "boolean") {
|
|
4822
|
+
url.searchParams.append(key, value ? "true" : "false");
|
|
4823
|
+
}
|
|
4824
|
+
else {
|
|
4825
|
+
url.searchParams.append(key, value.toString());
|
|
4826
|
+
}
|
|
4827
|
+
}
|
|
4828
|
+
});
|
|
4829
|
+
const response = await fetch(url.toString(), {
|
|
4830
|
+
...getFetchConfig(),
|
|
4831
|
+
});
|
|
4832
|
+
await handleGitLabError(response);
|
|
4833
|
+
const data = await response.json();
|
|
4834
|
+
return GitLabCiLintResultSchema.parse(data);
|
|
4835
|
+
}
|
|
4772
4836
|
/**
|
|
4773
4837
|
* List artifact files in a job's artifacts archive
|
|
4774
4838
|
*
|
|
@@ -5327,6 +5391,56 @@ async function getCommitDiff(projectId, sha, full_diff) {
|
|
|
5327
5391
|
}
|
|
5328
5392
|
return allDiffs;
|
|
5329
5393
|
}
|
|
5394
|
+
/**
|
|
5395
|
+
* List statuses for a commit.
|
|
5396
|
+
*
|
|
5397
|
+
* @param {string} projectId - Project ID or URL-encoded path
|
|
5398
|
+
* @param {string} sha - The commit hash or name of a repository branch or tag
|
|
5399
|
+
* @param {ListCommitStatusesOptions} options - List commit statuses options
|
|
5400
|
+
* @returns {Promise<GitLabCommitStatus[]>} List of commit statuses
|
|
5401
|
+
*/
|
|
5402
|
+
async function listCommitStatuses(projectId, sha, options = {}) {
|
|
5403
|
+
projectId = decodeURIComponent(projectId);
|
|
5404
|
+
const url = new URL(`${getEffectiveApiUrl()}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/repository/commits/${encodeURIComponent(sha)}/statuses`);
|
|
5405
|
+
Object.entries(options).forEach(([key, value]) => {
|
|
5406
|
+
if (value !== undefined) {
|
|
5407
|
+
url.searchParams.append(key, value.toString());
|
|
5408
|
+
}
|
|
5409
|
+
});
|
|
5410
|
+
const response = await fetch(url.toString(), {
|
|
5411
|
+
...getFetchConfig(),
|
|
5412
|
+
});
|
|
5413
|
+
await handleGitLabError(response);
|
|
5414
|
+
const data = await response.json();
|
|
5415
|
+
return z.array(GitLabCommitStatusSchema).parse(data);
|
|
5416
|
+
}
|
|
5417
|
+
/**
|
|
5418
|
+
* Create or update a commit status.
|
|
5419
|
+
*
|
|
5420
|
+
* @param {string} projectId - Project ID or URL-encoded path
|
|
5421
|
+
* @param {string} sha - The commit hash
|
|
5422
|
+
* @param {CreateCommitStatusOptions} options - Commit status fields
|
|
5423
|
+
* @returns {Promise<GitLabCommitStatus>} The created commit status
|
|
5424
|
+
*/
|
|
5425
|
+
async function createCommitStatus(projectId, sha, options) {
|
|
5426
|
+
if (options.name && options.context) {
|
|
5427
|
+
throw new Error("Use either name or context when creating a commit status, not both.");
|
|
5428
|
+
}
|
|
5429
|
+
projectId = decodeURIComponent(projectId);
|
|
5430
|
+
const url = new URL(`${getEffectiveApiUrl()}/projects/${encodeURIComponent(getEffectiveProjectId(projectId))}/statuses/${encodeURIComponent(sha)}`);
|
|
5431
|
+
Object.entries(options).forEach(([key, value]) => {
|
|
5432
|
+
if (value !== undefined) {
|
|
5433
|
+
url.searchParams.append(key, value.toString());
|
|
5434
|
+
}
|
|
5435
|
+
});
|
|
5436
|
+
const response = await fetch(url.toString(), {
|
|
5437
|
+
...getFetchConfig(),
|
|
5438
|
+
method: "POST",
|
|
5439
|
+
});
|
|
5440
|
+
await handleGitLabError(response);
|
|
5441
|
+
const data = await response.json();
|
|
5442
|
+
return GitLabCommitStatusSchema.parse(data);
|
|
5443
|
+
}
|
|
5330
5444
|
/**
|
|
5331
5445
|
* Get the current authenticated user
|
|
5332
5446
|
* 현재 인증된 사용자 가져오기
|
|
@@ -5791,7 +5905,7 @@ async function getTagSignature(projectId, tagName) {
|
|
|
5791
5905
|
async function handleToolCall(params) {
|
|
5792
5906
|
try {
|
|
5793
5907
|
if (!params.arguments) {
|
|
5794
|
-
|
|
5908
|
+
params.arguments = {};
|
|
5795
5909
|
}
|
|
5796
5910
|
// Ensure session is established for every request if cookie authentication is enabled
|
|
5797
5911
|
if (GITLAB_AUTH_COOKIE_PATH) {
|
|
@@ -6150,6 +6264,35 @@ async function handleToolCall(params) {
|
|
|
6150
6264
|
await deleteRestAwardEmoji(path);
|
|
6151
6265
|
return { content: [{ type: "text", text: "Issue note emoji reaction deleted successfully" }] };
|
|
6152
6266
|
}
|
|
6267
|
+
case "list_todos": {
|
|
6268
|
+
const args = ListTodosSchema.parse(params.arguments);
|
|
6269
|
+
const todos = await listTodos(args);
|
|
6270
|
+
return {
|
|
6271
|
+
content: [{ type: "text", text: JSON.stringify(todos, null, 2) }],
|
|
6272
|
+
};
|
|
6273
|
+
}
|
|
6274
|
+
case "mark_todo_done": {
|
|
6275
|
+
const args = MarkTodoDoneSchema.parse(params.arguments);
|
|
6276
|
+
const todo = await markTodoDone(args.id);
|
|
6277
|
+
return {
|
|
6278
|
+
content: [{ type: "text", text: JSON.stringify(todo, null, 2) }],
|
|
6279
|
+
};
|
|
6280
|
+
}
|
|
6281
|
+
case "mark_all_todos_done": {
|
|
6282
|
+
MarkAllTodosDoneSchema.parse(params.arguments);
|
|
6283
|
+
await markAllTodosDone();
|
|
6284
|
+
return {
|
|
6285
|
+
content: [
|
|
6286
|
+
{
|
|
6287
|
+
type: "text",
|
|
6288
|
+
text: JSON.stringify({
|
|
6289
|
+
status: "success",
|
|
6290
|
+
message: "All pending to-do items marked as done",
|
|
6291
|
+
}, null, 2),
|
|
6292
|
+
},
|
|
6293
|
+
],
|
|
6294
|
+
};
|
|
6295
|
+
}
|
|
6153
6296
|
case "get_merge_request": {
|
|
6154
6297
|
const args = GetMergeRequestSchema.parse(params.arguments);
|
|
6155
6298
|
const mergeRequest = await getMergeRequest(args.project_id, args.merge_request_iid, args.source_branch);
|
|
@@ -6902,6 +7045,22 @@ async function handleToolCall(params) {
|
|
|
6902
7045
|
],
|
|
6903
7046
|
};
|
|
6904
7047
|
}
|
|
7048
|
+
case "validate_ci_lint": {
|
|
7049
|
+
const args = ValidateCiLintSchema.parse(params.arguments);
|
|
7050
|
+
const { project_id, ...options } = args;
|
|
7051
|
+
const result = await validateCiLint(project_id, options);
|
|
7052
|
+
return {
|
|
7053
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
7054
|
+
};
|
|
7055
|
+
}
|
|
7056
|
+
case "validate_project_ci_lint": {
|
|
7057
|
+
const args = ValidateProjectCiLintSchema.parse(params.arguments);
|
|
7058
|
+
const { project_id, ...options } = args;
|
|
7059
|
+
const result = await validateProjectCiLint(project_id, options);
|
|
7060
|
+
return {
|
|
7061
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
7062
|
+
};
|
|
7063
|
+
}
|
|
6905
7064
|
case "create_pipeline": {
|
|
6906
7065
|
const { project_id, ref, variables, inputs } = CreatePipelineSchema.parse(params.arguments);
|
|
6907
7066
|
const pipeline = await createPipeline(project_id, ref, variables, inputs);
|
|
@@ -7161,6 +7320,22 @@ async function handleToolCall(params) {
|
|
|
7161
7320
|
content: [{ type: "text", text: JSON.stringify(diff, null, 2) }],
|
|
7162
7321
|
};
|
|
7163
7322
|
}
|
|
7323
|
+
case "list_commit_statuses": {
|
|
7324
|
+
const args = ListCommitStatusesSchema.parse(params.arguments);
|
|
7325
|
+
const { project_id, sha, ...options } = args;
|
|
7326
|
+
const statuses = await listCommitStatuses(project_id, sha, options);
|
|
7327
|
+
return {
|
|
7328
|
+
content: [{ type: "text", text: JSON.stringify(statuses, null, 2) }],
|
|
7329
|
+
};
|
|
7330
|
+
}
|
|
7331
|
+
case "create_commit_status": {
|
|
7332
|
+
const args = CreateCommitStatusSchema.parse(params.arguments);
|
|
7333
|
+
const { project_id, sha, ...options } = args;
|
|
7334
|
+
const status = await createCommitStatus(project_id, sha, options);
|
|
7335
|
+
return {
|
|
7336
|
+
content: [{ type: "text", text: JSON.stringify(status, null, 2) }],
|
|
7337
|
+
};
|
|
7338
|
+
}
|
|
7164
7339
|
case "list_group_iterations": {
|
|
7165
7340
|
const args = ListGroupIterationsSchema.parse(params.arguments);
|
|
7166
7341
|
const iterations = await listGroupIterations(args.group_id, args);
|
|
@@ -7872,11 +8047,10 @@ async function startStreamableHTTPServer() {
|
|
|
7872
8047
|
app._mcpOAuthProvider = oauthProvider;
|
|
7873
8048
|
// Mount /callback route for callback proxy mode
|
|
7874
8049
|
if (GITLAB_OAUTH_CALLBACK_PROXY) {
|
|
7875
|
-
|
|
7876
|
-
app.get(callbackPath, (req, res, next) => {
|
|
8050
|
+
app.get("/callback", (req, res, next) => {
|
|
7877
8051
|
oauthProvider.handleCallback(req, res).catch(next);
|
|
7878
8052
|
});
|
|
7879
|
-
logger.info(`Callback proxy mode enabled —
|
|
8053
|
+
logger.info(`Callback proxy mode enabled — /callback route mounted`);
|
|
7880
8054
|
}
|
|
7881
8055
|
}
|
|
7882
8056
|
// Build bearer-auth middleware — no-op unless GITLAB_MCP_OAUTH is enabled.
|
package/build/schemas.js
CHANGED
|
@@ -12,6 +12,16 @@ const coerceStringArray = z.preprocess((val) => {
|
|
|
12
12
|
}
|
|
13
13
|
return val;
|
|
14
14
|
}, z.array(z.string()));
|
|
15
|
+
const coerceBooleanString = z.preprocess((val) => {
|
|
16
|
+
if (typeof val === "string") {
|
|
17
|
+
const normalized = val.trim().toLowerCase();
|
|
18
|
+
if (normalized === "true")
|
|
19
|
+
return true;
|
|
20
|
+
if (normalized === "false")
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
return val;
|
|
24
|
+
}, z.boolean());
|
|
15
25
|
// Base schemas for common types
|
|
16
26
|
export const GitLabAuthorSchema = z.object({
|
|
17
27
|
name: z.string(),
|
|
@@ -275,6 +285,34 @@ export const ListPipelineTriggerJobsSchema = z
|
|
|
275
285
|
.describe("The scope of trigger jobs to show"),
|
|
276
286
|
})
|
|
277
287
|
.merge(PaginationOptionsSchema);
|
|
288
|
+
export const GitLabCiLintResultSchema = z.object({
|
|
289
|
+
valid: z.coerce.boolean(),
|
|
290
|
+
errors: z.array(z.string()),
|
|
291
|
+
warnings: z.array(z.string()).optional(),
|
|
292
|
+
merged_yaml: z.string().optional(),
|
|
293
|
+
includes: z.array(z.unknown()).optional(),
|
|
294
|
+
jobs: z.array(z.unknown()).optional(),
|
|
295
|
+
});
|
|
296
|
+
export const ValidateCiLintSchema = z.object({
|
|
297
|
+
project_id: z.coerce.string().describe("Project ID or URL-encoded path"),
|
|
298
|
+
content: z.string().describe("GitLab CI/CD YAML content to validate"),
|
|
299
|
+
dry_run: z.coerce.boolean().optional().describe("Run pipeline creation simulation"),
|
|
300
|
+
include_jobs: z.coerce.boolean().optional().describe("Include jobs in the lint response"),
|
|
301
|
+
ref: z.string().optional().describe("Branch or tag context for dry_run validation"),
|
|
302
|
+
});
|
|
303
|
+
export const ValidateProjectCiLintSchema = z.object({
|
|
304
|
+
project_id: z.coerce.string().describe("Project ID or URL-encoded path"),
|
|
305
|
+
content_ref: z
|
|
306
|
+
.string()
|
|
307
|
+
.optional()
|
|
308
|
+
.describe("Commit SHA, branch, or tag to read the existing CI config from"),
|
|
309
|
+
dry_run: z.coerce.boolean().optional().describe("Run pipeline creation simulation"),
|
|
310
|
+
dry_run_ref: z
|
|
311
|
+
.string()
|
|
312
|
+
.optional()
|
|
313
|
+
.describe("Branch or tag context for dry_run validation"),
|
|
314
|
+
include_jobs: z.coerce.boolean().optional().describe("Include jobs in the lint response"),
|
|
315
|
+
});
|
|
278
316
|
// Deployment related schemas
|
|
279
317
|
export const GitLabDeploymentSchema = z.object({
|
|
280
318
|
id: z.coerce.string(),
|
|
@@ -671,6 +709,35 @@ export const GitLabCommitSchema = z.object({
|
|
|
671
709
|
trailers: z.record(z.string()).optional().default({}), // Git trailers, may be empty object
|
|
672
710
|
extended_trailers: z.record(z.array(z.string())).optional().default({}), // Extended trailers, may be empty object
|
|
673
711
|
});
|
|
712
|
+
export const GitLabCommitStatusSchema = z
|
|
713
|
+
.object({
|
|
714
|
+
id: z.coerce.number().optional(),
|
|
715
|
+
sha: z.string(),
|
|
716
|
+
ref: z.string().nullable().optional(),
|
|
717
|
+
status: z.string(),
|
|
718
|
+
name: z.string().optional(),
|
|
719
|
+
context: z.string().optional(),
|
|
720
|
+
target_url: z.string().nullable().optional(),
|
|
721
|
+
description: z.string().nullable().optional(),
|
|
722
|
+
coverage: z.coerce.number().nullable().optional(),
|
|
723
|
+
allow_failure: z.coerce.boolean().optional(),
|
|
724
|
+
created_at: z.string().optional(),
|
|
725
|
+
started_at: z.string().nullable().optional(),
|
|
726
|
+
finished_at: z.string().nullable().optional(),
|
|
727
|
+
author: z
|
|
728
|
+
.object({
|
|
729
|
+
id: z.coerce.number().optional(),
|
|
730
|
+
name: z.string().optional(),
|
|
731
|
+
username: z.string().optional(),
|
|
732
|
+
state: z.string().optional(),
|
|
733
|
+
avatar_url: z.string().nullable().optional(),
|
|
734
|
+
web_url: z.string().optional(),
|
|
735
|
+
})
|
|
736
|
+
.passthrough()
|
|
737
|
+
.nullable()
|
|
738
|
+
.optional(),
|
|
739
|
+
})
|
|
740
|
+
.passthrough();
|
|
674
741
|
// Reference schema
|
|
675
742
|
export const GitLabReferenceSchema = z.object({
|
|
676
743
|
name: z.string(), // Changed from ref to match GitLab API
|
|
@@ -898,6 +965,7 @@ export const GitLabMergeRequestSchema = z.object({
|
|
|
898
965
|
author: GitLabUserSchema,
|
|
899
966
|
assignees: z.array(GitLabUserSchema).optional(),
|
|
900
967
|
reviewers: z.array(GitLabUserSchema).optional(),
|
|
968
|
+
milestone: GitLabMilestoneSchema.nullable().optional(),
|
|
901
969
|
source_branch: z.string(),
|
|
902
970
|
target_branch: z.string(),
|
|
903
971
|
diff_refs: GitLabMergeRequestDiffRefSchema.nullable().optional(),
|
|
@@ -1234,6 +1302,60 @@ export const CreateIssueSchema = ProjectParamsSchema.extend({
|
|
|
1234
1302
|
.describe("The type of issue. One of issue, incident, test_case or task."),
|
|
1235
1303
|
weight: z.coerce.number().optional().describe("Weight of the issue (numeric, typically hours of work)"),
|
|
1236
1304
|
});
|
|
1305
|
+
export const GitLabTodoSchema = z.object({
|
|
1306
|
+
id: z.coerce.number(),
|
|
1307
|
+
project: z.unknown().optional(),
|
|
1308
|
+
author: z.unknown().optional(),
|
|
1309
|
+
action_name: z.string().optional(),
|
|
1310
|
+
target_type: z.string().optional(),
|
|
1311
|
+
target: z.unknown().optional(),
|
|
1312
|
+
target_url: z.string().optional(),
|
|
1313
|
+
body: z.string().optional(),
|
|
1314
|
+
state: z.string(),
|
|
1315
|
+
created_at: z.string().optional(),
|
|
1316
|
+
updated_at: z.string().optional(),
|
|
1317
|
+
});
|
|
1318
|
+
export const ListTodosSchema = z
|
|
1319
|
+
.object({
|
|
1320
|
+
action: z
|
|
1321
|
+
.enum([
|
|
1322
|
+
"assigned",
|
|
1323
|
+
"mentioned",
|
|
1324
|
+
"build_failed",
|
|
1325
|
+
"marked",
|
|
1326
|
+
"approval_required",
|
|
1327
|
+
"unmergeable",
|
|
1328
|
+
"directly_addressed",
|
|
1329
|
+
"merge_train_removed",
|
|
1330
|
+
"member_access_requested",
|
|
1331
|
+
])
|
|
1332
|
+
.optional()
|
|
1333
|
+
.describe("Filter by to-do action"),
|
|
1334
|
+
author_id: z.coerce.number().optional().describe("Filter by author ID"),
|
|
1335
|
+
project_id: z.coerce.number().optional().describe("Filter by project ID"),
|
|
1336
|
+
group_id: z.coerce.number().optional().describe("Filter by group ID"),
|
|
1337
|
+
state: z.enum(["pending", "done"]).optional().describe("Filter by to-do state"),
|
|
1338
|
+
type: z
|
|
1339
|
+
.enum([
|
|
1340
|
+
"Issue",
|
|
1341
|
+
"MergeRequest",
|
|
1342
|
+
"Commit",
|
|
1343
|
+
"Epic",
|
|
1344
|
+
"DesignManagement::Design",
|
|
1345
|
+
"AlertManagement::Alert",
|
|
1346
|
+
"Project",
|
|
1347
|
+
"Namespace",
|
|
1348
|
+
"Vulnerability",
|
|
1349
|
+
"WikiPage::Meta",
|
|
1350
|
+
])
|
|
1351
|
+
.optional()
|
|
1352
|
+
.describe("Filter by to-do target type"),
|
|
1353
|
+
})
|
|
1354
|
+
.merge(PaginationOptionsSchema);
|
|
1355
|
+
export const MarkTodoDoneSchema = z.object({
|
|
1356
|
+
id: z.coerce.number().describe("The ID of the to-do item"),
|
|
1357
|
+
});
|
|
1358
|
+
export const MarkAllTodosDoneSchema = z.object({});
|
|
1237
1359
|
const MergeRequestOptionsSchema = {
|
|
1238
1360
|
title: z.string().describe("Merge request title"),
|
|
1239
1361
|
description: z.string().optional().describe("Merge request description"),
|
|
@@ -2132,6 +2254,44 @@ export const GetCommitDiffSchema = z.object({
|
|
|
2132
2254
|
.optional()
|
|
2133
2255
|
.describe("Whether to return the full diff or only first page (default: false)"),
|
|
2134
2256
|
});
|
|
2257
|
+
export const ListCommitStatusesSchema = z
|
|
2258
|
+
.object({
|
|
2259
|
+
project_id: z.coerce.string().describe("Project ID or complete URL-encoded path to project"),
|
|
2260
|
+
sha: z.string().describe("The commit hash or name of a repository branch or tag"),
|
|
2261
|
+
ref: z.string().optional().describe("Filter statuses by Git ref"),
|
|
2262
|
+
stage: z.string().optional().describe("Filter statuses by build stage"),
|
|
2263
|
+
name: z.string().optional().describe("Filter statuses by status name or context"),
|
|
2264
|
+
pipeline_id: z.coerce.number().optional().describe("Filter statuses by pipeline ID"),
|
|
2265
|
+
order_by: z
|
|
2266
|
+
.enum(["id", "pipeline_id"])
|
|
2267
|
+
.optional()
|
|
2268
|
+
.describe("Field to order statuses by"),
|
|
2269
|
+
sort: z.enum(["asc", "desc"]).optional().describe("Sort direction"),
|
|
2270
|
+
all: coerceBooleanString.optional().describe("Return all statuses, not only latest ones"),
|
|
2271
|
+
})
|
|
2272
|
+
.merge(PaginationOptionsSchema);
|
|
2273
|
+
export const CreateCommitStatusSchema = z.object({
|
|
2274
|
+
project_id: z.coerce.string().describe("Project ID or complete URL-encoded path to project"),
|
|
2275
|
+
sha: z.string().describe("The commit hash to set the status on"),
|
|
2276
|
+
state: z
|
|
2277
|
+
.enum(["pending", "running", "success", "failed", "canceled", "skipped"])
|
|
2278
|
+
.describe("Commit status state"),
|
|
2279
|
+
ref: z.string().max(255).optional().describe("The branch or tag ref"),
|
|
2280
|
+
name: z
|
|
2281
|
+
.string()
|
|
2282
|
+
.max(255)
|
|
2283
|
+
.optional()
|
|
2284
|
+
.describe("Status name. GitLab defaults to 'default' when omitted."),
|
|
2285
|
+
context: z
|
|
2286
|
+
.string()
|
|
2287
|
+
.max(255)
|
|
2288
|
+
.optional()
|
|
2289
|
+
.describe("Alias for name. Provide either name or context, not both."),
|
|
2290
|
+
target_url: z.string().max(255).optional().describe("Target URL associated with this status"),
|
|
2291
|
+
description: z.string().max(255).optional().describe("Short status description"),
|
|
2292
|
+
coverage: z.coerce.number().optional().describe("Total code coverage for this status"),
|
|
2293
|
+
pipeline_id: z.coerce.number().optional().describe("Pipeline ID to attach the status to"),
|
|
2294
|
+
});
|
|
2135
2295
|
// Schema for listing issues assigned to the current user
|
|
2136
2296
|
export const MyIssuesSchema = z.object({
|
|
2137
2297
|
project_id: z
|