@zereight/mcp-gitlab 2.2.6 → 2.3.1
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 +7 -4
- package/README.md +11 -7
- package/README.pt-BR.md +7 -4
- package/README.zh-CN.md +7 -4
- package/build/cli/args.js +2 -0
- package/build/config.js +4 -0
- package/build/deprecated-env.js +3 -1
- package/build/index.js +316 -82
- package/build/oauth-consent.js +323 -0
- package/build/oauth-proxy.js +99 -12
- package/build/oauth.js +147 -3
- package/build/schemas.js +124 -147
- package/build/stateless/types.js +2 -0
- package/build/tools/exposed-tools.js +14 -0
- package/build/tools/registry.js +24 -4
- package/build/tools/tool-descriptions.js +59 -17
- package/build/utils/graphql-query.js +1 -2
- package/build/utils/helpers.js +63 -4
- package/build/utils/safe-redirect-fetch.js +1 -1
- package/build/utils/url.js +1 -0
- package/package.json +4 -3
package/build/stateless/types.js
CHANGED
|
@@ -38,3 +38,17 @@ export function selectExposedTools(input) {
|
|
|
38
38
|
}
|
|
39
39
|
return withoutHidden.filter(tool => !isExcludedBySlimProfile(tool.name, true, input.individuallyEnabledTools));
|
|
40
40
|
}
|
|
41
|
+
/**
|
|
42
|
+
* Hidden tools that would be listed if the hidden policy were ignored.
|
|
43
|
+
* Hiding a tool keeps it callable only while toolsets, `GITLAB_TOOLS`, legacy
|
|
44
|
+
* flags, permission mode, and the regex denylist still expose it.
|
|
45
|
+
*/
|
|
46
|
+
export function selectCallableHiddenToolNames(input) {
|
|
47
|
+
if (input.hiddenToolNames.size === 0) {
|
|
48
|
+
return new Set();
|
|
49
|
+
}
|
|
50
|
+
const exposedIgnoringHidden = selectExposedTools({ ...input, hiddenToolNames: new Set() });
|
|
51
|
+
return new Set(exposedIgnoringHidden
|
|
52
|
+
.map(tool => tool.name)
|
|
53
|
+
.filter(toolName => input.hiddenToolNames.has(toolName)));
|
|
54
|
+
}
|
package/build/tools/registry.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { toJSONSchema } from "../utils/schema.js";
|
|
2
2
|
import { USE_GITLAB_WIKI, USE_MILESTONE, USE_PIPELINE, SSE, STREAMABLE_HTTP } from "../config.js";
|
|
3
3
|
import { getToolDescription } from "./tool-descriptions.js";
|
|
4
|
-
import { ApproveMergeRequestSchema, BulkPublishDraftNotesSchema, CancelPipelineJobSchema, ErasePipelineJobSchema, CancelPipelineSchema, ConvertWorkItemTypeSchema, CreateBranchSchema, CreateDraftNoteSchema, CreateGroupSchema, CreateGroupWikiPageSchema, CreateIssueLinkSchema, CreateIssueNoteSchema, CreateIssueSchema, CreateIssueEmojiReactionSchema, CreateIssueNoteEmojiReactionSchema, ListIssueEmojiReactionsSchema, ListIssueNoteEmojiReactionsSchema, CreateLabelSchema, MarkAllTodosDoneSchema, ListTodosSchema, MarkTodoDoneSchema, CreateMergeRequestDiscussionNoteSchema, CreateMergeRequestEmojiReactionSchema, ListMergeRequestEmojiReactionsSchema, ListMergeRequestNoteEmojiReactionsSchema, CreateMergeRequestNoteSchema, CreateMergeRequestNoteEmojiReactionSchema, CreateMergeRequestSchema, CreateMergeRequestThreadSchema, CreateNoteSchema, CreateCommitStatusSchema, CreateOrUpdateFileSchema, CreatePipelineSchema, CreateProjectMilestoneSchema, CreateGroupMilestoneSchema, CreateReleaseEvidenceSchema, CreateReleaseSchema, CreateRepositorySchema, CreateTagSchema, CreateTimelineEventSchema, CreateWebhookSchema, CreateWikiPageSchema, CreateWorkItemNoteSchema, CreateWorkItemEmojiReactionSchema, CreateWorkItemNoteEmojiReactionSchema, ListWorkItemEmojiReactionsSchema, ListWorkItemNoteEmojiReactionsSchema, CreateWorkItemSchema, DeleteBranchSchema, GetProtectedBranchSchema, ListProtectedBranchesSchema, ProtectBranchSchema, ProtectTagSchema, UnprotectBranchSchema, UnprotectTagSchema, UpdateDefaultBranchSchema, DeleteDraftNoteSchema, DeleteGroupMilestoneSchema, DeleteGroupWikiPageSchema, DeleteIssueLinkSchema, DeleteIssueSchema, DeleteIssueEmojiReactionSchema, DeleteIssueNoteEmojiReactionSchema, DeleteLabelSchema, DeleteMergeRequestDiscussionNoteSchema, DeleteMergeRequestNoteSchema, DeleteMergeRequestEmojiReactionSchema, DeleteMergeRequestNoteEmojiReactionSchema, DeleteProjectMilestoneSchema, DeleteReleaseSchema, DeleteTagSchema, DeleteWebhookSchema, DeleteWikiPageSchema, DeleteWorkItemEmojiReactionSchema, DeleteWorkItemNoteEmojiReactionSchema, DownloadAttachmentSchema, DownloadAttachmentRemoteSchema, DownloadJobArtifactsSchema, DownloadJobArtifactsRemoteSchema, DownloadReleaseAssetSchema, EditProjectMilestoneSchema, EditGroupMilestoneSchema, ExecuteGraphQLSchema, ForkRepositorySchema, HealthCheckSchema, GetBranchSchema, GetBranchDiffsSchema, GetCommitDiffSchema, GetCommitSchema, GetFileBlameSchema, GetDeploymentSchema, CreateDeploymentSchema, UpdateDeploymentSchema, DeploymentApprovalSchema, ListDeploymentMergeRequestsSchema, GetDraftNoteSchema, GetEnvironmentSchema, UpdateEnvironmentSchema, StopEnvironmentSchema, StopStaleEnvironmentsSchema, DeleteReviewAppEnvironmentsSchema, PipelineTriggerIdSchema, ListPipelineTriggersSchema, CreatePipelineTriggerSchema, UpdatePipelineTriggerSchema, TriggerPipelineSchema, GetFileContentsSchema, GetGroupWikiPageSchema, GetIssueLinkSchema, GetIssueSchema, GetJobArtifactFileSchema, GetLabelSchema, GetMergeRequestApprovalStateSchema, GetMergeRequestConflictsSchema, GetMergeRequestDiffsSchema, GetMergeRequestFileDiffSchema, GetMergeRequestDiscussionSchema, GetMergeRequestNoteSchema, GetMergeRequestNotesSchema, GetMergeRequestSchema, GetMergeRequestVersionSchema, GetMilestoneBurndownEventsSchema, GetMilestoneIssuesSchema, GetMilestoneMergeRequestsSchema, GetGroupMilestoneSchema, GetGroupMilestoneIssuesSchema, GetGroupMilestoneMergeRequestsSchema, GetGroupMilestoneBurndownEventsSchema, GetNamespaceSchema, GetPipelineJobOutputSchema, PipelineJobControlSchema, GetPipelineSchema, GetRunnerSchema, GetPipelineVariablesSchema, UpdatePipelineMetadataSchema, DeletePipelineSchema, PipelineReportSchema, WaitForPipelineSchema, WaitForPipelineJobSchema, PlayPipelineJobsSchema, GetProjectEventsSchema, GetProjectMilestoneSchema, GetProjectSchema, GetReleaseSchema, GetRepositoryTreeSchema, GetTagSchema, GetTagSignatureSchema, GetProtectedTagSchema, GetTimelineEventsSchema, GetUsersSchema, GetUserSchema, WhoAmISchema, GetWebhookEventSchema, GetWikiPageSchema, GetWorkItemSchema, ListBranchesSchema, ListCommitsSchema, ListCommitStatusesSchema, ListCustomFieldDefinitionsSchema, ListDeploymentsSchema, ListDraftNotesSchema, ListEnvironmentsSchema, ListEventsSchema, ListGroupIterationsSchema, ListGroupMilestonesSchema, ListGroupProjectsSchema, ListGroupWikiPagesSchema, ListIssueDiscussionsSchema, ListIssueLinksSchema, ListIssuesSchema, ListJobArtifactsSchema, ListLabelsSchema, ListMergeRequestChangedFilesSchema, ListMergeRequestDiffsSchema, ListMergeRequestDiscussionsSchema, ListMergeRequestPipelinesSchema, ListMergeRequestVersionsSchema, ListMergeRequestsSchema, ListGroupMergeRequestsSchema, ListNamespacesSchema, ListPipelineJobsSchema, ListPipelineTriggerJobsSchema, ValidateCiLintSchema, ValidateProjectCiLintSchema, ListCiCatalogResourcesSchema, GetCiCatalogResourceSchema, ListPipelinesSchema, ListPipelineSchedulesSchema, GetPipelineScheduleSchema, ListPipelineSchedulePipelinesSchema, CreatePipelineScheduleSchema, UpdatePipelineScheduleSchema, DeletePipelineScheduleSchema, PlayPipelineScheduleSchema, TakeOwnershipPipelineScheduleSchema, GetPipelineScheduleVariableSchema, CreatePipelineScheduleVariableSchema, UpdatePipelineScheduleVariableSchema, DeletePipelineScheduleVariableSchema, ListGroupMembersSchema, ListProjectMembersSchema, ListProjectMilestonesSchema, ListProjectsSchema, ListProjectRunnersSchema, ListReleasesSchema, ListTagsSchema, ListProtectedTagsSchema, ListWebhookEventsSchema, ListWebhooksSchema, ListWikiPagesSchema, ListWorkItemNotesSchema, ListWorkItemStatusesSchema, ListWorkItemsSchema, MarkdownUploadSchema, MarkdownUploadRemoteSchema, MergeMergeRequestSchema, MoveWorkItemSchema, MyIssuesSchema, OrbitQuerySchema, OrbitSchemaSchema, OrbitStatusSchema, OrbitToolsSchema, PlayPipelineJobSchema, PromoteProjectMilestoneSchema, PublishDraftNoteSchema, PushFilesSchema, ResolveMergeRequestThreadSchema, RetryPipelineJobSchema, RetryPipelineSchema, SearchCodeSchema, SearchGroupCodeSchema, SearchProjectCodeSchema, SearchRepositoriesSchema, ListSnippetsSchema, GetSnippetSchema, CreateSnippetSchema, UpdateSnippetSchema, DeleteSnippetSchema, UnapproveMergeRequestSchema, UpdateDraftNoteSchema, UpdateGroupWikiPageSchema, UpdateIssueNoteSchema, UpdateIssueSchema, UpdateIssueDescriptionPatchSchema, UpdateLabelSchema, UpdateProjectSchema, UpdateMergeRequestDiscussionNoteSchema, UpdateMergeRequestNoteSchema, UpdateMergeRequestSchema, UpdateReleaseSchema, UpdateWebhookSchema, UpdateWikiPageSchema, UpdateWorkItemSchema, VerifyNamespaceSchema, ListProjectVariablesSchema, GetProjectVariableSchema, CreateProjectVariableSchema, UpdateProjectVariableSchema, DeleteProjectVariableSchema, ListGroupVariablesSchema, GetGroupVariableSchema, CreateGroupVariableSchema, UpdateGroupVariableSchema, DeleteGroupVariableSchema, GetDependencyProxySettingsSchema, UpdateDependencyProxySettingsSchema, ListDependencyProxyBlobsSchema, PurgeDependencyProxyCacheSchema, ListProjectVulnerabilitiesSchema, GetVulnerabilitySchema, DismissVulnerabilitySchema, ConfirmVulnerabilitySchema, } from "../schemas.js";
|
|
4
|
+
import { ApproveMergeRequestSchema, BulkPublishDraftNotesSchema, CancelPipelineJobSchema, ErasePipelineJobSchema, CancelPipelineSchema, ConvertWorkItemTypeSchema, CreateBranchSchema, CreateDraftNoteSchema, CreateGroupSchema, CreateGroupWikiPageSchema, CreateIssueLinkSchema, CreateIssueNoteSchema, CreateIssueSchema, CreateIssueEmojiReactionSchema, CreateIssueNoteEmojiReactionSchema, ListIssueEmojiReactionsSchema, ListIssueNoteEmojiReactionsSchema, CreateLabelSchema, MarkAllTodosDoneSchema, ListTodosSchema, MarkTodoDoneSchema, CreateMergeRequestDiscussionNoteSchema, CreateMergeRequestEmojiReactionSchema, ListMergeRequestEmojiReactionsSchema, ListMergeRequestNoteEmojiReactionsSchema, CreateMergeRequestNoteSchema, CreateMergeRequestNoteEmojiReactionSchema, CreateMergeRequestSchema, CreateMergeRequestThreadSchema, CreateNoteSchema, CreateCommitStatusSchema, CreateOrUpdateFileSchema, CreatePipelineSchema, CreateProjectMilestoneSchema, CreateGroupMilestoneSchema, CreateReleaseEvidenceSchema, CreateReleaseSchema, CreateRepositorySchema, CreateTagSchema, CreateTimelineEventSchema, CreateWebhookSchema, CreateWikiPageSchema, CreateWorkItemNoteSchema, CreateWorkItemEmojiReactionSchema, CreateWorkItemNoteEmojiReactionSchema, ListWorkItemEmojiReactionsSchema, ListWorkItemNoteEmojiReactionsSchema, CreateWorkItemSchema, DeleteBranchSchema, GetProtectedBranchSchema, ListProtectedBranchesSchema, ProtectBranchSchema, ProtectTagSchema, UnprotectBranchSchema, UnprotectTagSchema, UpdateDefaultBranchSchema, DeleteDraftNoteSchema, DeleteGroupMilestoneSchema, DeleteGroupWikiPageSchema, DeleteIssueLinkSchema, DeleteIssueSchema, DeleteIssueEmojiReactionSchema, DeleteIssueNoteEmojiReactionSchema, DeleteLabelSchema, DeleteMergeRequestDiscussionNoteSchema, DeleteMergeRequestNoteSchema, DeleteMergeRequestEmojiReactionSchema, DeleteMergeRequestNoteEmojiReactionSchema, DeleteProjectMilestoneSchema, DeleteReleaseSchema, DeleteTagSchema, DeleteWebhookSchema, DeleteWikiPageSchema, DeleteWorkItemEmojiReactionSchema, DeleteWorkItemNoteEmojiReactionSchema, DownloadAttachmentSchema, DownloadAttachmentRemoteSchema, DownloadJobArtifactsSchema, DownloadJobArtifactsRemoteSchema, DownloadReleaseAssetSchema, EditProjectMilestoneSchema, EditGroupMilestoneSchema, ExecuteGraphQLSchema, ForkRepositorySchema, HealthCheckSchema, GetBranchSchema, GetBranchDiffsSchema, GetCommitDiffSchema, GetCommitSchema, GetFileBlameSchema, GetDeploymentSchema, CreateDeploymentSchema, UpdateDeploymentSchema, DeploymentApprovalSchema, ListDeploymentMergeRequestsSchema, GetDraftNoteSchema, GetEnvironmentSchema, UpdateEnvironmentSchema, StopEnvironmentSchema, StopStaleEnvironmentsSchema, DeleteReviewAppEnvironmentsSchema, PipelineTriggerIdSchema, ListPipelineTriggersSchema, CreatePipelineTriggerSchema, UpdatePipelineTriggerSchema, TriggerPipelineSchema, GetFileContentsSchema, GetGroupWikiPageSchema, GetIssueLinkSchema, GetIssueSchema, GetJobArtifactFileSchema, GetLabelSchema, GetMergeRequestApprovalStateSchema, GetMergeRequestConflictsSchema, GetMergeRequestDiffsSchema, GetMergeRequestFileDiffSchema, GetMergeRequestDiscussionSchema, GetMergeRequestNoteSchema, GetMergeRequestNotesSchema, GetMergeRequestSchema, GetMergeRequestVersionSchema, GetMilestoneBurndownEventsSchema, GetMilestoneIssuesSchema, GetMilestoneMergeRequestsSchema, GetGroupMilestoneSchema, GetGroupMilestoneIssuesSchema, GetGroupMilestoneMergeRequestsSchema, GetGroupMilestoneBurndownEventsSchema, GetNamespaceSchema, GetPipelineJobOutputSchema, PipelineJobControlSchema, GetPipelineSchema, GetRunnerSchema, GetPipelineVariablesSchema, UpdatePipelineMetadataSchema, DeletePipelineSchema, PipelineReportSchema, WaitForPipelineSchema, WaitForPipelineJobSchema, PlayPipelineJobsSchema, GetProjectEventsSchema, GetProjectMilestoneSchema, GetProjectSchema, GetReleaseSchema, GetRepositoryTreeSchema, GetTagSchema, GetTagSignatureSchema, GetProtectedTagSchema, GetTimelineEventsSchema, GetUsersSchema, GetUserSchema, WhoAmISchema, GetWebhookEventSchema, GetWikiPageSchema, GetWorkItemSchema, ListBranchesSchema, ListCommitsSchema, ListCommitStatusesSchema, ListCustomFieldDefinitionsSchema, ListDeploymentsSchema, ListDraftNotesSchema, ListEnvironmentsSchema, ListEventsSchema, ListGroupIterationsSchema, ListGroupMilestonesSchema, ListGroupProjectsSchema, ListGroupWikiPagesSchema, ListIssueDiscussionsSchema, ListIssueLinksSchema, ListIssuesSchema, ListJobArtifactsSchema, ListLabelsSchema, ListMergeRequestChangedFilesSchema, ListMergeRequestDiffsSchema, ListMergeRequestDiscussionsSchema, ListMergeRequestPipelinesSchema, ListMergeRequestVersionsSchema, ListMergeRequestsSchema, ListGroupMergeRequestsSchema, ListNamespacesSchema, ListPipelineJobsSchema, ListPipelineTriggerJobsSchema, ValidateCiLintSchema, ValidateProjectCiLintSchema, ListCiCatalogResourcesSchema, GetCiCatalogResourceSchema, ListPipelinesSchema, ListPipelineSchedulesSchema, GetPipelineScheduleSchema, ListPipelineSchedulePipelinesSchema, CreatePipelineScheduleSchema, UpdatePipelineScheduleSchema, DeletePipelineScheduleSchema, PlayPipelineScheduleSchema, TakeOwnershipPipelineScheduleSchema, GetPipelineScheduleVariableSchema, CreatePipelineScheduleVariableSchema, UpdatePipelineScheduleVariableSchema, DeletePipelineScheduleVariableSchema, ListGroupMembersSchema, ListProjectMembersSchema, ListProjectMilestonesSchema, ListProjectsSchema, ListProjectRunnersSchema, ListReleasesSchema, ListTagsSchema, ListProtectedTagsSchema, ListWebhookEventsSchema, ListWebhooksSchema, ListWikiPagesSchema, ListWorkItemNotesSchema, ListWorkItemStatusesSchema, ListWorkItemsSchema, MarkdownUploadSchema, MarkdownUploadRemoteSchema, MergeMergeRequestSchema, MoveWorkItemSchema, MyIssuesSchema, OrbitQuerySchema, OrbitSchemaSchema, OrbitStatusSchema, OrbitToolsSchema, PlayPipelineJobSchema, PromoteProjectMilestoneSchema, PublishDraftNoteSchema, PushFilesSchema, ResolveMergeRequestThreadSchema, RetryPipelineJobSchema, RetryPipelineSchema, SearchCodeSchema, SearchGroupCodeSchema, SearchProjectCodeSchema, SearchRepositoriesSchema, ListSnippetsSchema, GetSnippetSchema, CreateSnippetSchema, UpdateSnippetSchema, DeleteSnippetSchema, UnapproveMergeRequestSchema, RebaseMergeRequestSchema, UpdateDraftNoteSchema, UpdateGroupWikiPageSchema, UpdateIssueNoteSchema, UpdateIssueSchema, UpdateIssueDescriptionPatchSchema, UpdateLabelSchema, UpdateProjectSchema, UpdateMergeRequestDiscussionNoteSchema, UpdateMergeRequestNoteSchema, UpdateMergeRequestSchema, UpdateReleaseSchema, UpdateWebhookSchema, UpdateWikiPageSchema, UpdateWorkItemSchema, VerifyNamespaceSchema, ListProjectVariablesSchema, GetProjectVariableSchema, CreateProjectVariableSchema, UpdateProjectVariableSchema, DeleteProjectVariableSchema, ListGroupVariablesSchema, GetGroupVariableSchema, CreateGroupVariableSchema, UpdateGroupVariableSchema, DeleteGroupVariableSchema, GetDependencyProxySettingsSchema, UpdateDependencyProxySettingsSchema, ListDependencyProxyBlobsSchema, PurgeDependencyProxyCacheSchema, ListProjectVulnerabilitiesSchema, GetVulnerabilitySchema, DismissVulnerabilitySchema, ConfirmVulnerabilitySchema, } from "../schemas.js";
|
|
5
5
|
import { GitLabApiRequestSchema } from "./gitlab-api-request.js";
|
|
6
6
|
const IS_REMOTE = SSE || STREAMABLE_HTTP;
|
|
7
7
|
// Define all available tools
|
|
@@ -1007,7 +1007,7 @@ export const allTools = [
|
|
|
1007
1007
|
name: "download_attachment",
|
|
1008
1008
|
description: IS_REMOTE
|
|
1009
1009
|
? "Download an uploaded file from a project (images returned inline as base64, other files returned as download URL)"
|
|
1010
|
-
: "Download an uploaded file from a project (images returned as base64;
|
|
1010
|
+
: "Download an uploaded file from a project (images returned as base64; other files, or images with local_path, are saved as new files under the download directory)",
|
|
1011
1011
|
inputSchema: IS_REMOTE
|
|
1012
1012
|
? toJSONSchema(DownloadAttachmentRemoteSchema)
|
|
1013
1013
|
: toJSONSchema(DownloadAttachmentSchema),
|
|
@@ -1397,6 +1397,11 @@ export const allTools = [
|
|
|
1397
1397
|
description: "Get one runner by ID",
|
|
1398
1398
|
inputSchema: toJSONSchema(GetRunnerSchema),
|
|
1399
1399
|
},
|
|
1400
|
+
{
|
|
1401
|
+
name: "rebase_merge_request",
|
|
1402
|
+
description: "Rebase the source branch of a merge request onto its target branch",
|
|
1403
|
+
inputSchema: toJSONSchema(RebaseMergeRequestSchema),
|
|
1404
|
+
},
|
|
1400
1405
|
// --- Explicit opt-in raw API. Not in `all` and not activatable via discover_tools. ---
|
|
1401
1406
|
{
|
|
1402
1407
|
name: "gitlab_api_request",
|
|
@@ -1570,8 +1575,14 @@ export const readOnlyTools = new Set([
|
|
|
1570
1575
|
// Stays in readOnlyTools so readonly mode can still run queries, but mutations
|
|
1571
1576
|
// are allowed in other permission modes and rejected only at call time.
|
|
1572
1577
|
const MIXED_ACCESS_TOOLS = new Set(["execute_graphql", "gitlab_api_request"]);
|
|
1578
|
+
// Read-only on GitLab, but in stdio mode they save files to the local disk. They stay
|
|
1579
|
+
// listed in readonly mode, where the handlers refuse anything that would write a file
|
|
1580
|
+
// (only inline images are returned), and never advertise readOnlyHint.
|
|
1581
|
+
const LOCAL_FILE_WRITE_TOOLS = new Set(IS_REMOTE ? [] : ["download_attachment", "download_job_artifacts"]);
|
|
1573
1582
|
export function advertisesReadOnly(toolName) {
|
|
1574
|
-
return readOnlyTools.has(toolName) &&
|
|
1583
|
+
return (readOnlyTools.has(toolName) &&
|
|
1584
|
+
!MIXED_ACCESS_TOOLS.has(toolName) &&
|
|
1585
|
+
!LOCAL_FILE_WRITE_TOOLS.has(toolName));
|
|
1575
1586
|
}
|
|
1576
1587
|
// Define which tools are destructive (data loss potential)
|
|
1577
1588
|
export const destructiveTools = new Set([
|
|
@@ -1614,6 +1625,7 @@ export const destructiveTools = new Set([
|
|
|
1614
1625
|
"protect_tag",
|
|
1615
1626
|
"update_default_branch",
|
|
1616
1627
|
"merge_merge_request",
|
|
1628
|
+
"rebase_merge_request",
|
|
1617
1629
|
"push_files",
|
|
1618
1630
|
"delete_project_variable",
|
|
1619
1631
|
"delete_group_variable",
|
|
@@ -1817,6 +1829,7 @@ export const TOOLSET_DEFINITIONS = [
|
|
|
1817
1829
|
isDefault: false,
|
|
1818
1830
|
tools: new Set([
|
|
1819
1831
|
"merge_merge_request",
|
|
1832
|
+
"rebase_merge_request",
|
|
1820
1833
|
"approve_merge_request",
|
|
1821
1834
|
"unapprove_merge_request",
|
|
1822
1835
|
"get_merge_request_approval_state",
|
|
@@ -2254,8 +2267,15 @@ const discoverTool = allTools.find(t => t.name === "discover_tools");
|
|
|
2254
2267
|
if (discoverTool) {
|
|
2255
2268
|
discoverTool.description = `Discover and activate additional tool categories for this session. Available categories: ${[...DISCOVERABLE_TOOLSET_IDS].join(", ")}. Already-active categories are listed in the response. Explicit-only toolsets are omitted; list them in GITLAB_TOOLSETS.`;
|
|
2256
2269
|
}
|
|
2270
|
+
function acceptsProjectOrGroupId(inputSchema) {
|
|
2271
|
+
const properties = inputSchema?.properties;
|
|
2272
|
+
return (typeof properties === "object" &&
|
|
2273
|
+
properties !== null &&
|
|
2274
|
+
("project_id" in properties || "group_id" in properties));
|
|
2275
|
+
}
|
|
2276
|
+
const allToolNames = new Set(allTools.map(tool => tool.name));
|
|
2257
2277
|
for (const tool of allTools) {
|
|
2258
|
-
tool.description = getToolDescription(tool.name, tool.description, readOnlyTools.has(tool.name), destructiveTools.has(tool.name));
|
|
2278
|
+
tool.description = getToolDescription(tool.name, tool.description, readOnlyTools.has(tool.name), destructiveTools.has(tool.name), acceptsProjectOrGroupId(tool.inputSchema), allToolNames);
|
|
2259
2279
|
}
|
|
2260
2280
|
export function parseEnabledToolsets(raw) {
|
|
2261
2281
|
if (!raw || raw.trim() === "") {
|
|
@@ -2,6 +2,7 @@ const TOOL_GUIDANCE = {
|
|
|
2
2
|
merge_merge_request: "Use this only after checking the merge request approval, conflict, and pipeline state; use `approve_merge_request` to approve rather than merge. The operation changes repository state and may squash commits, schedule auto-merge, or delete the source branch, so it requires merge permission and returns GitLab's merge result or a mergeability error. Pass `sha` from `get_merge_request` (`sha` or `diff_refs.head_sha`); GitLab 19.2+ groups may reject merges without it.",
|
|
3
3
|
approve_merge_request: "Use this to record an approval on an existing merge request; it does not merge the request or change its source branch. The operation changes review state, may require re-authentication or approval permission, and returns the updated approval result or a permission/state error.",
|
|
4
4
|
unapprove_merge_request: "Use this to remove the current user's approval from an existing merge request; use `merge_merge_request` only when you intend to merge. The operation changes review state and requires approval permission, and GitLab returns the updated result or an error when the request or approval is unavailable.",
|
|
5
|
+
rebase_merge_request: "Use this when the source branch is behind its target branch; use `get_merge_request_conflicts` to inspect conflicts and `merge_merge_request` to merge. The operation rewrites the source branch history with a force push and requires permission to push to that branch. With `wait` true (default), it polls until the rebase ends and returns the merge request: GitLab reports a failed rebase in `merge_error`, but that field can also keep a message from an earlier attempt, so compare `sha` with its value before the rebase. If the rebase still runs after `timeout_seconds`, it returns a timeout error while GitLab continues the rebase. With `wait` false, it returns GitLab's enqueue response (`rebase_in_progress` true) at once. Set `skip_ci` to skip the CI pipeline for the rebased branch.",
|
|
5
6
|
get_merge_request_approval_state: "Use this to inspect approval rules and approvers before deciding whether a merge request can be merged; use `approve_merge_request` to change approval state. It is read-only and returns the approval-state response, while missing requests, unsupported GitLab versions, and permission failures are reported as errors.",
|
|
6
7
|
get_merge_request_conflicts: "Use this to inspect merge conflicts before attempting `merge_merge_request`; it reports conflicts and does not resolve them. It is read-only, requires access to the project and merge request, and returns GitLab's conflict data or an error when the request cannot be evaluated.",
|
|
7
8
|
list_merge_request_pipelines: "Use this to inspect pipelines associated with one merge request; use `list_pipelines` for project-wide pipeline filtering. It is read-only and paginated, requires project access, and returns pipeline records or GitLab errors for invalid identifiers, missing resources, or rate limits.",
|
|
@@ -34,8 +35,8 @@ const TOOL_GUIDANCE = {
|
|
|
34
35
|
update_issue_description_patch: "Use this for a targeted search/replace or unified-diff change to an issue description; use `dry_run` before applying an uncertain patch and `create_note` when an audit summary is wanted. It changes the issue description when not dry-running, requires issue-edit permission, and returns the patch result or a mismatch/validation/permission error.",
|
|
35
36
|
delete_issue: "Use this only after confirming the issue and intended permanent removal; use `update_issue` to close or edit an issue without deleting it. The operation permanently removes issue data, requires delete permission, and returns the deletion result or a missing-resource, permission, or policy error.",
|
|
36
37
|
delete_issue_link: "Use this to remove an existing relationship between two issues; use `list_issue_links` or `get_issue_link` to verify the link first. The operation changes issue relationships, requires issue-edit permission, and returns the result or an error when the link is missing or access is denied.",
|
|
37
|
-
download_job_artifacts: "Use this to retrieve a pipeline job's artifact archive; remote HTTP mode returns a download URL while local mode saves the archive to a local path. It is read-only but
|
|
38
|
-
download_attachment: "Use this to retrieve a previously uploaded project attachment; remote mode returns inline base64 for images or a download URL, while local mode
|
|
38
|
+
download_job_artifacts: "Use this to retrieve a pipeline job's artifact archive; remote HTTP mode returns a download URL while local mode saves the archive to a local path. It is read-only on GitLab but creates a local file in stdio mode (rejected in readonly mode), requires job/project access, and returns the download result or an artifact/permission error.",
|
|
39
|
+
download_attachment: "Use this to retrieve a previously uploaded project attachment; remote mode returns inline base64 for images or a download URL, while local mode saves the file as a new file under the download directory (GITLAB_DOWNLOAD_DIR, default .gitlab-mcp-downloads). It is read-only with respect to GitLab but creates a local file in stdio mode (readonly mode returns images inline and rejects everything else), never replaces an existing file, requires project access, and returns the file content or an attachment/permission error.",
|
|
39
40
|
gitlab_api_request: "Send one GitLab REST call under /api/v4. Readonly mode allows GET only, and modify mode rejects DELETE. Enable it only by listing api in GITLAB_TOOLSETS; all, discover_tools, and GITLAB_TOOLS do not. Prompt injection can drive this tool, so operators who rely on group, project, or tool restrictions must not enable it. GITLAB_ALLOWED_PROJECT_IDS is enforced only for /projects/:id paths; other endpoints are not constrained.",
|
|
40
41
|
execute_graphql: "Use this only when a supported GitLab REST tool does not cover the requested operation; prefer a typed tool when one exists. The query is sent directly to GitLab and can include mutations when permission allows, so callers must treat it as potentially state-changing and handle GraphQL errors in the returned response.",
|
|
41
42
|
discover_tools: "Use this when a needed opt-in category is not currently exposed; omit `category` to inspect available categories, then call it with a category to activate that group for the current session. It changes only the session's tool registry, returns the active-tool summary, and does not change GitLab data.",
|
|
@@ -62,46 +63,80 @@ const TOOL_GUIDANCE = {
|
|
|
62
63
|
orbit_get_status: "Use this to check whether Orbit indexing has completed before trusting `orbit_query` results; results reflect the last index cycle, not real-time state. It is read-only and free of credit charges, and returns the indexing status or a permission error.",
|
|
63
64
|
orbit_list_tools: "Use this to see which MCP tool definitions Orbit itself exposes; use `orbit_query` to run graph queries directly. It is read-only and free of credit charges, and returns the tool definition list or a permission error.",
|
|
64
65
|
};
|
|
65
|
-
const PARAMETER_GUIDANCE = "
|
|
66
|
+
const PARAMETER_GUIDANCE = "`project_id`/`group_id` take a numeric ID or URL-encoded path.";
|
|
66
67
|
function ensureSentence(text) {
|
|
67
68
|
const trimmed = text.trim();
|
|
68
69
|
return /[.!?]$/.test(trimmed) ? trimmed : `${trimmed}.`;
|
|
69
70
|
}
|
|
70
|
-
|
|
71
|
+
// Candidate get_* names for a list_* resource: list_pipelines -> get_pipeline,
|
|
72
|
+
// list_branches -> get_branch, list_policies -> get_policy, list_diffs -> get_diffs.
|
|
73
|
+
function matchingGetToolNames(resource) {
|
|
74
|
+
const candidates = [`get_${resource}`];
|
|
75
|
+
if (resource.endsWith("ies"))
|
|
76
|
+
candidates.push(`get_${resource.slice(0, -3)}y`);
|
|
77
|
+
if (resource.endsWith("es"))
|
|
78
|
+
candidates.push(`get_${resource.slice(0, -2)}`);
|
|
79
|
+
if (resource.endsWith("s"))
|
|
80
|
+
candidates.push(`get_${resource.slice(0, -1)}`);
|
|
81
|
+
return candidates;
|
|
82
|
+
}
|
|
83
|
+
// Candidate list_*/search_* names for a get_* resource: get_pipeline -> list_pipelines,
|
|
84
|
+
// get_branch -> list_branches, get_policy -> list_policies, get_diffs -> list_diffs.
|
|
85
|
+
function matchingDiscoveryToolNames(resource) {
|
|
86
|
+
const plurals = [resource, `${resource}s`, `${resource}es`];
|
|
87
|
+
if (resource.endsWith("y"))
|
|
88
|
+
plurals.push(`${resource.slice(0, -1)}ies`);
|
|
89
|
+
return plurals.flatMap(plural => [`list_${plural}`, `search_${plural}`]);
|
|
90
|
+
}
|
|
91
|
+
// Sibling hints are only added when the sibling tool exists, so a description
|
|
92
|
+
// never points at a tool the server does not have.
|
|
93
|
+
function getLifecycleGuidance(name, toolNames) {
|
|
71
94
|
const verb = name.split("_")[0] ?? "use";
|
|
95
|
+
const resource = name.slice(verb.length + 1);
|
|
72
96
|
if (verb === "list") {
|
|
73
|
-
return
|
|
97
|
+
return matchingGetToolNames(resource).some(candidate => toolNames.has(candidate))
|
|
98
|
+
? "For one known resource, use the matching get tool."
|
|
99
|
+
: "";
|
|
74
100
|
}
|
|
75
101
|
if (verb === "get") {
|
|
76
|
-
return
|
|
102
|
+
return matchingDiscoveryToolNames(resource).some(candidate => toolNames.has(candidate))
|
|
103
|
+
? "To find resources, use the matching list or search tool."
|
|
104
|
+
: "";
|
|
77
105
|
}
|
|
78
106
|
if (verb === "create") {
|
|
79
|
-
return
|
|
107
|
+
return toolNames.has(`update_${resource}`) || toolNames.has(`edit_${resource}`)
|
|
108
|
+
? "If the resource already exists, use the update tool."
|
|
109
|
+
: "";
|
|
80
110
|
}
|
|
81
111
|
if (verb === "update" || verb === "edit") {
|
|
82
|
-
|
|
112
|
+
if (!toolNames.has(`create_${resource}`)) {
|
|
113
|
+
return "";
|
|
114
|
+
}
|
|
115
|
+
return toolNames.has(`create_${resource}_note`)
|
|
116
|
+
? "Use the create tool for new resources and a note tool for comments."
|
|
117
|
+
: "Use the create tool for new resources.";
|
|
83
118
|
}
|
|
84
119
|
if (verb === "delete" || verb === "remove") {
|
|
85
|
-
return "
|
|
120
|
+
return "Verify the target first with a get or list tool.";
|
|
86
121
|
}
|
|
87
122
|
if (verb === "search") {
|
|
88
|
-
return "
|
|
123
|
+
return "If the identifier is known, use a typed get or list tool.";
|
|
89
124
|
}
|
|
90
125
|
if (verb === "validate") {
|
|
91
|
-
return "
|
|
126
|
+
return "Checks without applying; create or update only after it passes.";
|
|
92
127
|
}
|
|
93
|
-
return "
|
|
128
|
+
return "";
|
|
94
129
|
}
|
|
95
130
|
function getBehaviorGuidance(readOnly, destructive) {
|
|
96
131
|
if (readOnly) {
|
|
97
|
-
return "
|
|
132
|
+
return "Read-only; missing resources, denied access, and rate limits return errors.";
|
|
98
133
|
}
|
|
99
134
|
if (destructive) {
|
|
100
|
-
return "
|
|
135
|
+
return "Changes or removes GitLab data and may be irreversible; needs permission.";
|
|
101
136
|
}
|
|
102
|
-
return "
|
|
137
|
+
return "Changes GitLab data; needs permission and returns validation or conflict errors.";
|
|
103
138
|
}
|
|
104
|
-
export function getToolDescription(name, baseDescription, readOnly, destructive) {
|
|
139
|
+
export function getToolDescription(name, baseDescription, readOnly, destructive, acceptsProjectOrGroupId, toolNames) {
|
|
105
140
|
const explicitGuidance = TOOL_GUIDANCE[name];
|
|
106
141
|
if (explicitGuidance) {
|
|
107
142
|
return `${ensureSentence(baseDescription)} ${explicitGuidance}`;
|
|
@@ -110,5 +145,12 @@ export function getToolDescription(name, baseDescription, readOnly, destructive)
|
|
|
110
145
|
if (normalizedDescription.length >= 180) {
|
|
111
146
|
return normalizedDescription;
|
|
112
147
|
}
|
|
113
|
-
return
|
|
148
|
+
return [
|
|
149
|
+
normalizedDescription,
|
|
150
|
+
getLifecycleGuidance(name, toolNames),
|
|
151
|
+
getBehaviorGuidance(readOnly, destructive),
|
|
152
|
+
acceptsProjectOrGroupId ? PARAMETER_GUIDANCE : "",
|
|
153
|
+
]
|
|
154
|
+
.filter(Boolean)
|
|
155
|
+
.join(" ");
|
|
114
156
|
}
|
|
@@ -112,8 +112,7 @@ function skipInsignificantGraphQL(source, index) {
|
|
|
112
112
|
function extractTopLevelMutationFields(normalized) {
|
|
113
113
|
const fields = [];
|
|
114
114
|
const mutationRegex = /(?:^|[;},]\s*)mutation\b[^({]*(?:\([^)]*\))?\s*\{/g;
|
|
115
|
-
|
|
116
|
-
while ((match = mutationRegex.exec(normalized)) !== null) {
|
|
115
|
+
while (mutationRegex.exec(normalized) !== null) {
|
|
117
116
|
let i = mutationRegex.lastIndex;
|
|
118
117
|
let braceDepth = 1;
|
|
119
118
|
let parenDepth = 0;
|
package/build/utils/helpers.js
CHANGED
|
@@ -82,8 +82,11 @@ export function resolveSafeExistingPath(inputPath, label = "path", baseDir) {
|
|
|
82
82
|
* it if needed. Rejects symlink components and verifies the final real path
|
|
83
83
|
* remains inside the base.
|
|
84
84
|
*/
|
|
85
|
-
export function resolveSafeOutputDir(inputDir, label = "local_path", baseDir) {
|
|
85
|
+
export function resolveSafeOutputDir(inputDir, label = "local_path", baseDir, options = {}) {
|
|
86
86
|
const relative = assertSafeRelativePath(inputDir, label);
|
|
87
|
+
if (options.rejectDotNames && relative.split(path.sep).some(isDotName)) {
|
|
88
|
+
throw new Error(`Invalid ${label}: names starting with a dot are not allowed.`);
|
|
89
|
+
}
|
|
87
90
|
const baseReal = resolveTrustedBaseDir(baseDir);
|
|
88
91
|
assertNoSymlinkComponents(baseReal, relative, label);
|
|
89
92
|
const absolute = path.resolve(baseReal, relative);
|
|
@@ -136,6 +139,11 @@ const WRITE_OPEN_FLAGS = fs.constants.O_WRONLY |
|
|
|
136
139
|
fs.constants.O_CREAT |
|
|
137
140
|
fs.constants.O_TRUNC |
|
|
138
141
|
(fs.constants.O_NOFOLLOW ?? 0);
|
|
142
|
+
// O_EXCL also refuses a symlink in the final component.
|
|
143
|
+
const EXCLUSIVE_WRITE_OPEN_FLAGS = fs.constants.O_WRONLY | fs.constants.O_CREAT | fs.constants.O_EXCL;
|
|
144
|
+
function isDotName(part) {
|
|
145
|
+
return part.startsWith(".") && part !== ".";
|
|
146
|
+
}
|
|
139
147
|
/**
|
|
140
148
|
* Validate and read a file in one step so callers never reuse a path string
|
|
141
149
|
* after a symlink swap (final-component TOCTOU mitigation via O_NOFOLLOW).
|
|
@@ -171,7 +179,7 @@ export function readSafeExistingFile(inputPath, label = "path", baseDir) {
|
|
|
171
179
|
* Validate an output destination and open a write stream immediately so the
|
|
172
180
|
* path is not handed back for a separate createWriteStream call.
|
|
173
181
|
*/
|
|
174
|
-
export function openSafeOutputWriteStream(filename, inputDir, label = "local_path", baseDir) {
|
|
182
|
+
export function openSafeOutputWriteStream(filename, inputDir, label = "local_path", baseDir, options = {}) {
|
|
175
183
|
if (!filename ||
|
|
176
184
|
filename === "." ||
|
|
177
185
|
filename === ".." ||
|
|
@@ -180,10 +188,27 @@ export function openSafeOutputWriteStream(filename, inputDir, label = "local_pat
|
|
|
180
188
|
filename.includes(path.sep)) {
|
|
181
189
|
throw new Error(`Invalid ${label}: directory separators are not allowed in filename.`);
|
|
182
190
|
}
|
|
191
|
+
if (options.rejectDotNames && isDotName(filename)) {
|
|
192
|
+
throw new Error("Invalid filename: names starting with a dot are not allowed.");
|
|
193
|
+
}
|
|
183
194
|
const dirReal = inputDir
|
|
184
|
-
? resolveSafeOutputDir(inputDir, label, baseDir)
|
|
195
|
+
? resolveSafeOutputDir(inputDir, label, baseDir, options)
|
|
185
196
|
: resolveTrustedBaseDir(baseDir);
|
|
186
197
|
const dest = path.join(dirReal, filename);
|
|
198
|
+
if (options.exclusive) {
|
|
199
|
+
let fd;
|
|
200
|
+
try {
|
|
201
|
+
fd = fs.openSync(dest, EXCLUSIVE_WRITE_OPEN_FLAGS, 0o666);
|
|
202
|
+
}
|
|
203
|
+
catch (err) {
|
|
204
|
+
if (err.code === "EEXIST") {
|
|
205
|
+
throw new Error(`${dest} already exists. Choose another ${label} or remove the file first.`);
|
|
206
|
+
}
|
|
207
|
+
throw err;
|
|
208
|
+
}
|
|
209
|
+
const stream = fs.createWriteStream(null, { fd, autoClose: true });
|
|
210
|
+
return { stream, path: dest };
|
|
211
|
+
}
|
|
187
212
|
try {
|
|
188
213
|
const st = fs.lstatSync(dest);
|
|
189
214
|
if (st.isSymbolicLink()) {
|
|
@@ -203,6 +228,40 @@ export function openSafeOutputWriteStream(filename, inputDir, label = "local_pat
|
|
|
203
228
|
});
|
|
204
229
|
return { stream, path: dest };
|
|
205
230
|
}
|
|
231
|
+
export const DEFAULT_DOWNLOAD_DIR = ".gitlab-mcp-downloads";
|
|
232
|
+
/**
|
|
233
|
+
* Resolve (and create on first use) the directory that downloads are saved under.
|
|
234
|
+
* The default sits in the working directory, which may be a cloned repository, so it
|
|
235
|
+
* must be a real directory rather than a symlink planted there. A directory the
|
|
236
|
+
* server creates gets a `.gitignore` so its contents are never committed by accident.
|
|
237
|
+
*/
|
|
238
|
+
export function resolveDownloadRoot(configured) {
|
|
239
|
+
const root = path.resolve(configured || DEFAULT_DOWNLOAD_DIR);
|
|
240
|
+
let st;
|
|
241
|
+
try {
|
|
242
|
+
st = fs.lstatSync(root);
|
|
243
|
+
}
|
|
244
|
+
catch (err) {
|
|
245
|
+
if (err.code !== "ENOENT") {
|
|
246
|
+
throw err;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
if (st?.isSymbolicLink() && !configured) {
|
|
250
|
+
throw new Error(`Invalid download directory: ${root} is a symbolic link. Remove it or set GITLAB_DOWNLOAD_DIR.`);
|
|
251
|
+
}
|
|
252
|
+
if (!st) {
|
|
253
|
+
fs.mkdirSync(root, { recursive: true });
|
|
254
|
+
try {
|
|
255
|
+
fs.writeFileSync(path.join(root, ".gitignore"), "*\n", { flag: "wx" });
|
|
256
|
+
}
|
|
257
|
+
catch (err) {
|
|
258
|
+
if (err.code !== "EEXIST") {
|
|
259
|
+
throw err;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
return fs.realpathSync(root);
|
|
264
|
+
}
|
|
206
265
|
/**
|
|
207
266
|
* Estimate the number of merge commits that will be added based on the merge method.
|
|
208
267
|
*/
|
|
@@ -245,7 +304,7 @@ export function filterDiffsByPatterns(diffs, excludedFilePatterns) {
|
|
|
245
304
|
try {
|
|
246
305
|
return new RegExp(pattern);
|
|
247
306
|
}
|
|
248
|
-
catch
|
|
307
|
+
catch {
|
|
249
308
|
console.warn(`Invalid regex pattern ignored: ${pattern}`);
|
|
250
309
|
return null;
|
|
251
310
|
}
|
|
@@ -193,7 +193,7 @@ function withoutCredentialHeaders(options) {
|
|
|
193
193
|
* Runs on every redirect hop, so an upstream cannot steer the request to loopback,
|
|
194
194
|
* link-local instance metadata, or a private-range host.
|
|
195
195
|
*/
|
|
196
|
-
async function assertRedirectTargetAllowed(target, trusted,
|
|
196
|
+
async function assertRedirectTargetAllowed(target, trusted, _options) {
|
|
197
197
|
if (trusted) {
|
|
198
198
|
return;
|
|
199
199
|
}
|
package/build/utils/url.js
CHANGED
|
@@ -40,6 +40,7 @@ const DOT_SEGMENT_PATTERN = /(^|[\\/])\.\.?([\\/]|$)/;
|
|
|
40
40
|
/** A decoded value that starts with a path separator (absolute-path payload). */
|
|
41
41
|
const LEADING_SEPARATOR_PATTERN = /^[\\/]/;
|
|
42
42
|
/** NUL, newline and the other control characters: never valid in a path segment. */
|
|
43
|
+
// eslint-disable-next-line no-control-regex
|
|
43
44
|
const CONTROL_CHARACTER_PATTERN = /[\u0000-\u001f\u007f]/;
|
|
44
45
|
/**
|
|
45
46
|
* How many times a value is percent-decoded before the checks run. A payload can be
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zereight/mcp-gitlab",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.1",
|
|
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": [
|
|
@@ -62,11 +62,11 @@
|
|
|
62
62
|
"test:oauth": "tsx test/oauth-tests.ts && node --import tsx/esm --test --experimental-test-isolation=none test/oauth-device-flow-tests.ts",
|
|
63
63
|
"test:list-merge-requests": "npm run build && tsx test/test-list-merge-requests.ts",
|
|
64
64
|
"test:approvals": "npm run build && tsx test/test-merge-request-approvals.ts",
|
|
65
|
-
"lint": "eslint .
|
|
65
|
+
"lint": "eslint .",
|
|
66
66
|
"check:runtime-deps": "node scripts/check-runtime-deps.mjs",
|
|
67
67
|
"check:skill-sync": "tsx scripts/check-skill-sync.ts",
|
|
68
68
|
"docs:tools": "tsx scripts/generate-tool-docs.ts && tsx scripts/generate-tool-coverage.ts",
|
|
69
|
-
"lint:fix": "eslint . --
|
|
69
|
+
"lint:fix": "eslint . --fix",
|
|
70
70
|
"release": "bash scripts/release.sh",
|
|
71
71
|
"release:mcp-registry": "bash scripts/publish_mcp_registry.sh",
|
|
72
72
|
"format": "prettier --write \"**/*.{js,ts,json,md}\"",
|
|
@@ -90,6 +90,7 @@
|
|
|
90
90
|
"zod": "^4.6.5"
|
|
91
91
|
},
|
|
92
92
|
"devDependencies": {
|
|
93
|
+
"@eslint/js": "^9.27.0",
|
|
93
94
|
"@types/express": "^5.0.2",
|
|
94
95
|
"@types/jmespath": "^0.15.2",
|
|
95
96
|
"@types/node": "^22.13.10",
|