chore: bump version to 1.0.27 and update deploy script for public access

This commit is contained in:
simple
2025-04-05 20:59:15 +09:00
parent c69f8416ac
commit 6858e1cf4a
2 changed files with 207 additions and 74 deletions

277
index.ts
View File

@ -10,7 +10,7 @@ import fetch from "node-fetch";
import { z } from "zod"; import { z } from "zod";
import { zodToJsonSchema } from "zod-to-json-schema"; import { zodToJsonSchema } from "zod-to-json-schema";
import { fileURLToPath } from "url"; import { fileURLToPath } from "url";
import { dirname, resolve } from "path"; import { dirname } from "path";
import fs from "fs"; import fs from "fs";
import path from "path"; import path from "path";
import { import {
@ -100,11 +100,11 @@ import {
*/ */
const __filename = fileURLToPath(import.meta.url); const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename); const __dirname = dirname(__filename);
const packageJsonPath = path.resolve(__dirname, '../package.json'); const packageJsonPath = path.resolve(__dirname, "../package.json");
let SERVER_VERSION = "unknown"; let SERVER_VERSION = "unknown";
try { try {
if (fs.existsSync(packageJsonPath)) { if (fs.existsSync(packageJsonPath)) {
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')); const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
SERVER_VERSION = packageJson.version || SERVER_VERSION; SERVER_VERSION = packageJson.version || SERVER_VERSION;
} }
} catch (error) { } catch (error) {
@ -124,7 +124,7 @@ const server = new Server(
); );
const GITLAB_PERSONAL_ACCESS_TOKEN = process.env.GITLAB_PERSONAL_ACCESS_TOKEN; const GITLAB_PERSONAL_ACCESS_TOKEN = process.env.GITLAB_PERSONAL_ACCESS_TOKEN;
const GITLAB_READ_ONLY_MODE = process.env.GITLAB_READ_ONLY_MODE === 'true'; const GITLAB_READ_ONLY_MODE = process.env.GITLAB_READ_ONLY_MODE === "true";
// Define all available tools // Define all available tools
const allTools = [ const allTools = [
@ -151,8 +151,7 @@ const allTools = [
}, },
{ {
name: "push_files", name: "push_files",
description: description: "Push multiple files to a GitLab project in a single commit",
"Push multiple files to a GitLab project in a single commit",
inputSchema: zodToJsonSchema(PushFilesSchema), inputSchema: zodToJsonSchema(PushFilesSchema),
}, },
{ {
@ -167,8 +166,7 @@ const allTools = [
}, },
{ {
name: "fork_repository", name: "fork_repository",
description: description: "Fork a GitLab project to your account or specified namespace",
"Fork a GitLab project to your account or specified namespace",
inputSchema: zodToJsonSchema(ForkRepositorySchema), inputSchema: zodToJsonSchema(ForkRepositorySchema),
}, },
{ {
@ -321,7 +319,7 @@ const readOnlyTools = [
"list_projects", "list_projects",
"list_labels", "list_labels",
"get_label", "get_label",
"list_group_projects" "list_group_projects",
]; ];
/** /**
@ -336,10 +334,13 @@ function normalizeGitLabApiUrl(url?: string): string {
} }
// Remove trailing slash if present // Remove trailing slash if present
let normalizedUrl = url.endsWith('/') ? url.slice(0, -1) : url; let normalizedUrl = url.endsWith("/") ? url.slice(0, -1) : url;
// Check if URL already has /api/v4 // Check if URL already has /api/v4
if (!normalizedUrl.endsWith('/api/v4') && !normalizedUrl.endsWith('/api/v4/')) { if (
!normalizedUrl.endsWith("/api/v4") &&
!normalizedUrl.endsWith("/api/v4/")
) {
// Append /api/v4 if not already present // Append /api/v4 if not already present
normalizedUrl = `${normalizedUrl}/api/v4`; normalizedUrl = `${normalizedUrl}/api/v4`;
} }
@ -582,9 +583,9 @@ async function listIssues(
// Add all query parameters // Add all query parameters
Object.entries(options).forEach(([key, value]) => { Object.entries(options).forEach(([key, value]) => {
if (value !== undefined) { if (value !== undefined) {
if (key === 'label_name' && Array.isArray(value)) { if (key === "label_name" && Array.isArray(value)) {
// Handle array of labels // Handle array of labels
url.searchParams.append(key, value.join(',')); url.searchParams.append(key, value.join(","));
} else { } else {
url.searchParams.append(key, value.toString()); url.searchParams.append(key, value.toString());
} }
@ -613,7 +614,9 @@ async function getIssue(
issueIid: number issueIid: number
): Promise<GitLabIssue> { ): Promise<GitLabIssue> {
const url = new URL( const url = new URL(
`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/issues/${issueIid}` `${GITLAB_API_URL}/projects/${encodeURIComponent(
projectId
)}/issues/${issueIid}`
); );
const response = await fetch(url.toString(), { const response = await fetch(url.toString(), {
@ -640,13 +643,15 @@ async function updateIssue(
options: Omit<z.infer<typeof UpdateIssueSchema>, "project_id" | "issue_iid"> options: Omit<z.infer<typeof UpdateIssueSchema>, "project_id" | "issue_iid">
): Promise<GitLabIssue> { ): Promise<GitLabIssue> {
const url = new URL( const url = new URL(
`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/issues/${issueIid}` `${GITLAB_API_URL}/projects/${encodeURIComponent(
projectId
)}/issues/${issueIid}`
); );
// Convert labels array to comma-separated string if present // Convert labels array to comma-separated string if present
const body: Record<string, any> = { ...options }; const body: Record<string, any> = { ...options };
if (body.labels && Array.isArray(body.labels)) { if (body.labels && Array.isArray(body.labels)) {
body.labels = body.labels.join(','); body.labels = body.labels.join(",");
} }
const response = await fetch(url.toString(), { const response = await fetch(url.toString(), {
@ -668,12 +673,11 @@ async function updateIssue(
* @param {number} issueIid - The internal ID of the project issue * @param {number} issueIid - The internal ID of the project issue
* @returns {Promise<void>} * @returns {Promise<void>}
*/ */
async function deleteIssue( async function deleteIssue(projectId: string, issueIid: number): Promise<void> {
projectId: string,
issueIid: number
): Promise<void> {
const url = new URL( const url = new URL(
`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/issues/${issueIid}` `${GITLAB_API_URL}/projects/${encodeURIComponent(
projectId
)}/issues/${issueIid}`
); );
const response = await fetch(url.toString(), { const response = await fetch(url.toString(), {
@ -697,7 +701,9 @@ async function listIssueLinks(
issueIid: number issueIid: number
): Promise<GitLabIssueWithLinkDetails[]> { ): Promise<GitLabIssueWithLinkDetails[]> {
const url = new URL( const url = new URL(
`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/issues/${issueIid}/links` `${GITLAB_API_URL}/projects/${encodeURIComponent(
projectId
)}/issues/${issueIid}/links`
); );
const response = await fetch(url.toString(), { const response = await fetch(url.toString(), {
@ -724,7 +730,9 @@ async function getIssueLink(
issueLinkId: number issueLinkId: number
): Promise<GitLabIssueLink> { ): Promise<GitLabIssueLink> {
const url = new URL( const url = new URL(
`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/issues/${issueIid}/links/${issueLinkId}` `${GITLAB_API_URL}/projects/${encodeURIComponent(
projectId
)}/issues/${issueIid}/links/${issueLinkId}`
); );
const response = await fetch(url.toString(), { const response = await fetch(url.toString(), {
@ -752,10 +760,12 @@ async function createIssueLink(
issueIid: number, issueIid: number,
targetProjectId: string, targetProjectId: string,
targetIssueIid: number, targetIssueIid: number,
linkType: 'relates_to' | 'blocks' | 'is_blocked_by' = 'relates_to' linkType: "relates_to" | "blocks" | "is_blocked_by" = "relates_to"
): Promise<GitLabIssueLink> { ): Promise<GitLabIssueLink> {
const url = new URL( const url = new URL(
`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/issues/${issueIid}/links` `${GITLAB_API_URL}/projects/${encodeURIComponent(
projectId
)}/issues/${issueIid}/links`
); );
const response = await fetch(url.toString(), { const response = await fetch(url.toString(), {
@ -764,7 +774,7 @@ async function createIssueLink(
body: JSON.stringify({ body: JSON.stringify({
target_project_id: targetProjectId, target_project_id: targetProjectId,
target_issue_iid: targetIssueIid, target_issue_iid: targetIssueIid,
link_type: linkType link_type: linkType,
}), }),
}); });
@ -788,7 +798,9 @@ async function deleteIssueLink(
issueLinkId: number issueLinkId: number
): Promise<void> { ): Promise<void> {
const url = new URL( const url = new URL(
`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/issues/${issueIid}/links/${issueLinkId}` `${GITLAB_API_URL}/projects/${encodeURIComponent(
projectId
)}/issues/${issueIid}/links/${issueLinkId}`
); );
const response = await fetch(url.toString(), { const response = await fetch(url.toString(), {
@ -812,9 +824,7 @@ async function createMergeRequest(
options: z.infer<typeof CreateMergeRequestOptionsSchema> options: z.infer<typeof CreateMergeRequestOptionsSchema>
): Promise<GitLabMergeRequest> { ): Promise<GitLabMergeRequest> {
const url = new URL( const url = new URL(
`${GITLAB_API_URL}/projects/${encodeURIComponent( `${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/merge_requests`
projectId
)}/merge_requests`
); );
const response = await fetch(url.toString(), { const response = await fetch(url.toString(), {
@ -1417,7 +1427,9 @@ async function verifyNamespaceExistence(
namespacePath: string, namespacePath: string,
parentId?: number parentId?: number
): Promise<GitLabNamespaceExistsResponse> { ): Promise<GitLabNamespaceExistsResponse> {
const url = new URL(`${GITLAB_API_URL}/namespaces/${encodeURIComponent(namespacePath)}/exists`); const url = new URL(
`${GITLAB_API_URL}/namespaces/${encodeURIComponent(namespacePath)}/exists`
);
if (parentId) { if (parentId) {
url.searchParams.append("parent_id", parentId.toString()); url.searchParams.append("parent_id", parentId.toString());
@ -1451,7 +1463,9 @@ async function getProject(
with_custom_attributes?: boolean; with_custom_attributes?: boolean;
} = {} } = {}
): Promise<GitLabProject> { ): Promise<GitLabProject> {
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}`); const url = new URL(
`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}`
);
if (options.license) { if (options.license) {
url.searchParams.append("license", "true"); url.searchParams.append("license", "true");
@ -1481,7 +1495,9 @@ async function getProject(
* @param {Object} options - Options for listing projects * @param {Object} options - Options for listing projects
* @returns {Promise<GitLabProject[]>} List of projects * @returns {Promise<GitLabProject[]>} List of projects
*/ */
async function listProjects(options: z.infer<typeof ListProjectsSchema> = {}): Promise<GitLabProject[]> { async function listProjects(
options: z.infer<typeof ListProjectsSchema> = {}
): Promise<GitLabProject[]> {
// Construct the query parameters // Construct the query parameters
const params = new URLSearchParams(); const params = new URLSearchParams();
for (const [key, value] of Object.entries(options)) { for (const [key, value] of Object.entries(options)) {
@ -1523,7 +1539,9 @@ async function listLabels(
options: Omit<z.infer<typeof ListLabelsSchema>, "project_id"> = {} options: Omit<z.infer<typeof ListLabelsSchema>, "project_id"> = {}
): Promise<GitLabLabel[]> { ): Promise<GitLabLabel[]> {
// Construct the URL with project path // Construct the URL with project path
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/labels`); const url = new URL(
`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/labels`
);
// Add query parameters // Add query parameters
Object.entries(options).forEach(([key, value]) => { Object.entries(options).forEach(([key, value]) => {
@ -1562,11 +1580,18 @@ async function getLabel(
labelId: number | string, labelId: number | string,
includeAncestorGroups?: boolean includeAncestorGroups?: boolean
): Promise<GitLabLabel> { ): Promise<GitLabLabel> {
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/labels/${encodeURIComponent(String(labelId))}`); const url = new URL(
`${GITLAB_API_URL}/projects/${encodeURIComponent(
projectId
)}/labels/${encodeURIComponent(String(labelId))}`
);
// Add query parameters // Add query parameters
if (includeAncestorGroups !== undefined) { if (includeAncestorGroups !== undefined) {
url.searchParams.append("include_ancestor_groups", includeAncestorGroups ? "true" : "false"); url.searchParams.append(
"include_ancestor_groups",
includeAncestorGroups ? "true" : "false"
);
} }
// Make the API request // Make the API request
@ -1626,7 +1651,9 @@ async function updateLabel(
): Promise<GitLabLabel> { ): Promise<GitLabLabel> {
// Make the API request // Make the API request
const response = await fetch( const response = await fetch(
`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/labels/${encodeURIComponent(String(labelId))}`, `${GITLAB_API_URL}/projects/${encodeURIComponent(
projectId
)}/labels/${encodeURIComponent(String(labelId))}`,
{ {
method: "PUT", method: "PUT",
headers: DEFAULT_HEADERS, headers: DEFAULT_HEADERS,
@ -1654,7 +1681,9 @@ async function deleteLabel(
): Promise<void> { ): Promise<void> {
// Make the API request // Make the API request
const response = await fetch( const response = await fetch(
`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/labels/${encodeURIComponent(String(labelId))}`, `${GITLAB_API_URL}/projects/${encodeURIComponent(
projectId
)}/labels/${encodeURIComponent(String(labelId))}`,
{ {
method: "DELETE", method: "DELETE",
headers: DEFAULT_HEADERS, headers: DEFAULT_HEADERS,
@ -1679,22 +1708,52 @@ async function listGroupProjects(
); );
// Add optional parameters to URL // Add optional parameters to URL
if (options.include_subgroups) url.searchParams.append('include_subgroups', 'true'); if (options.include_subgroups)
if (options.search) url.searchParams.append('search', options.search); url.searchParams.append("include_subgroups", "true");
if (options.order_by) url.searchParams.append('order_by', options.order_by); if (options.search) url.searchParams.append("search", options.search);
if (options.sort) url.searchParams.append('sort', options.sort); if (options.order_by) url.searchParams.append("order_by", options.order_by);
if (options.page) url.searchParams.append('page', options.page.toString()); if (options.sort) url.searchParams.append("sort", options.sort);
if (options.per_page) url.searchParams.append('per_page', options.per_page.toString()); if (options.page) url.searchParams.append("page", options.page.toString());
if (options.archived !== undefined) url.searchParams.append('archived', options.archived.toString()); if (options.per_page)
if (options.visibility) url.searchParams.append('visibility', options.visibility); url.searchParams.append("per_page", options.per_page.toString());
if (options.with_issues_enabled !== undefined) url.searchParams.append('with_issues_enabled', options.with_issues_enabled.toString()); if (options.archived !== undefined)
if (options.with_merge_requests_enabled !== undefined) url.searchParams.append('with_merge_requests_enabled', options.with_merge_requests_enabled.toString()); url.searchParams.append("archived", options.archived.toString());
if (options.min_access_level !== undefined) url.searchParams.append('min_access_level', options.min_access_level.toString()); if (options.visibility)
if (options.with_programming_language) url.searchParams.append('with_programming_language', options.with_programming_language); url.searchParams.append("visibility", options.visibility);
if (options.starred !== undefined) url.searchParams.append('starred', options.starred.toString()); if (options.with_issues_enabled !== undefined)
if (options.statistics !== undefined) url.searchParams.append('statistics', options.statistics.toString()); url.searchParams.append(
if (options.with_custom_attributes !== undefined) url.searchParams.append('with_custom_attributes', options.with_custom_attributes.toString()); "with_issues_enabled",
if (options.with_security_reports !== undefined) url.searchParams.append('with_security_reports', options.with_security_reports.toString()); options.with_issues_enabled.toString()
);
if (options.with_merge_requests_enabled !== undefined)
url.searchParams.append(
"with_merge_requests_enabled",
options.with_merge_requests_enabled.toString()
);
if (options.min_access_level !== undefined)
url.searchParams.append(
"min_access_level",
options.min_access_level.toString()
);
if (options.with_programming_language)
url.searchParams.append(
"with_programming_language",
options.with_programming_language
);
if (options.starred !== undefined)
url.searchParams.append("starred", options.starred.toString());
if (options.statistics !== undefined)
url.searchParams.append("statistics", options.statistics.toString());
if (options.with_custom_attributes !== undefined)
url.searchParams.append(
"with_custom_attributes",
options.with_custom_attributes.toString()
);
if (options.with_security_reports !== undefined)
url.searchParams.append(
"with_security_reports",
options.with_security_reports.toString()
);
const response = await fetch(url.toString(), { const response = await fetch(url.toString(), {
method: "GET", method: "GET",
@ -1709,7 +1768,7 @@ async function listGroupProjects(
server.setRequestHandler(ListToolsRequestSchema, async () => { server.setRequestHandler(ListToolsRequestSchema, async () => {
// If read-only mode is enabled, filter out write operations // If read-only mode is enabled, filter out write operations
const tools = GITLAB_READ_ONLY_MODE const tools = GITLAB_READ_ONLY_MODE
? allTools.filter(tool => readOnlyTools.includes(tool.name)) ? allTools.filter((tool) => readOnlyTools.includes(tool.name))
: allTools; : allTools;
return { return {
@ -1727,9 +1786,14 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
case "fork_repository": { case "fork_repository": {
const forkArgs = ForkRepositorySchema.parse(request.params.arguments); const forkArgs = ForkRepositorySchema.parse(request.params.arguments);
try { try {
const forkedProject = await forkProject(forkArgs.project_id, forkArgs.namespace); const forkedProject = await forkProject(
forkArgs.project_id,
forkArgs.namespace
);
return { return {
content: [{ type: "text", text: JSON.stringify(forkedProject, null, 2) }], content: [
{ type: "text", text: JSON.stringify(forkedProject, null, 2) },
],
}; };
} catch (forkError) { } catch (forkError) {
console.error("Error forking repository:", forkError); console.error("Error forking repository:", forkError);
@ -1738,7 +1802,12 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
forkErrorMessage = `${forkErrorMessage}: ${forkError.message}`; forkErrorMessage = `${forkErrorMessage}: ${forkError.message}`;
} }
return { return {
content: [{ type: "text", text: JSON.stringify({ error: forkErrorMessage }, null, 2) }], content: [
{
type: "text",
text: JSON.stringify({ error: forkErrorMessage }, null, 2),
},
],
}; };
} }
} }
@ -1845,7 +1914,9 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
} }
case "update_merge_request_note": { case "update_merge_request_note": {
const args = UpdateMergeRequestNoteSchema.parse(request.params.arguments); const args = UpdateMergeRequestNoteSchema.parse(
request.params.arguments
);
const note = await updateMergeRequestNote( const note = await updateMergeRequestNote(
args.project_id, args.project_id,
args.merge_request_iid, args.merge_request_iid,
@ -1900,7 +1971,9 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
} }
case "list_merge_request_discussions": { case "list_merge_request_discussions": {
const args = ListMergeRequestDiscussionsSchema.parse(request.params.arguments); const args = ListMergeRequestDiscussionsSchema.parse(
request.params.arguments
);
const discussions = await listMergeRequestDiscussions( const discussions = await listMergeRequestDiscussions(
args.project_id, args.project_id,
args.merge_request_iid args.merge_request_iid
@ -1938,13 +2011,19 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
const namespaces = z.array(GitLabNamespaceSchema).parse(data); const namespaces = z.array(GitLabNamespaceSchema).parse(data);
return { return {
content: [{ type: "text", text: JSON.stringify(namespaces, null, 2) }], content: [
{ type: "text", text: JSON.stringify(namespaces, null, 2) },
],
}; };
} }
case "get_namespace": { case "get_namespace": {
const args = GetNamespaceSchema.parse(request.params.arguments); const args = GetNamespaceSchema.parse(request.params.arguments);
const url = new URL(`${GITLAB_API_URL}/namespaces/${encodeURIComponent(args.namespace_id)}`); const url = new URL(
`${GITLAB_API_URL}/namespaces/${encodeURIComponent(
args.namespace_id
)}`
);
const response = await fetch(url.toString(), { const response = await fetch(url.toString(), {
headers: DEFAULT_HEADERS, headers: DEFAULT_HEADERS,
@ -1961,7 +2040,9 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
case "verify_namespace": { case "verify_namespace": {
const args = VerifyNamespaceSchema.parse(request.params.arguments); const args = VerifyNamespaceSchema.parse(request.params.arguments);
const url = new URL(`${GITLAB_API_URL}/namespaces/${encodeURIComponent(args.path)}/exists`); const url = new URL(
`${GITLAB_API_URL}/namespaces/${encodeURIComponent(args.path)}/exists`
);
const response = await fetch(url.toString(), { const response = await fetch(url.toString(), {
headers: DEFAULT_HEADERS, headers: DEFAULT_HEADERS,
@ -1972,13 +2053,17 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
const namespaceExists = GitLabNamespaceExistsResponseSchema.parse(data); const namespaceExists = GitLabNamespaceExistsResponseSchema.parse(data);
return { return {
content: [{ type: "text", text: JSON.stringify(namespaceExists, null, 2) }], content: [
{ type: "text", text: JSON.stringify(namespaceExists, null, 2) },
],
}; };
} }
case "get_project": { case "get_project": {
const args = GetProjectSchema.parse(request.params.arguments); const args = GetProjectSchema.parse(request.params.arguments);
const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(args.project_id)}`); const url = new URL(
`${GITLAB_API_URL}/projects/${encodeURIComponent(args.project_id)}`
);
const response = await fetch(url.toString(), { const response = await fetch(url.toString(), {
headers: DEFAULT_HEADERS, headers: DEFAULT_HEADERS,
@ -2047,7 +2132,16 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
const args = DeleteIssueSchema.parse(request.params.arguments); const args = DeleteIssueSchema.parse(request.params.arguments);
await deleteIssue(args.project_id, args.issue_iid); await deleteIssue(args.project_id, args.issue_iid);
return { return {
content: [{ type: "text", text: JSON.stringify({ status: "success", message: "Issue deleted successfully" }, null, 2) }], content: [
{
type: "text",
text: JSON.stringify(
{ status: "success", message: "Issue deleted successfully" },
null,
2
),
},
],
}; };
} }
@ -2061,7 +2155,11 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
case "get_issue_link": { case "get_issue_link": {
const args = GetIssueLinkSchema.parse(request.params.arguments); const args = GetIssueLinkSchema.parse(request.params.arguments);
const link = await getIssueLink(args.project_id, args.issue_iid, args.issue_link_id); const link = await getIssueLink(
args.project_id,
args.issue_iid,
args.issue_link_id
);
return { return {
content: [{ type: "text", text: JSON.stringify(link, null, 2) }], content: [{ type: "text", text: JSON.stringify(link, null, 2) }],
}; };
@ -2069,7 +2167,13 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
case "create_issue_link": { case "create_issue_link": {
const args = CreateIssueLinkSchema.parse(request.params.arguments); const args = CreateIssueLinkSchema.parse(request.params.arguments);
const link = await createIssueLink(args.project_id, args.issue_iid, args.target_project_id, args.target_issue_iid, args.link_type); const link = await createIssueLink(
args.project_id,
args.issue_iid,
args.target_project_id,
args.target_issue_iid,
args.link_type
);
return { return {
content: [{ type: "text", text: JSON.stringify(link, null, 2) }], content: [{ type: "text", text: JSON.stringify(link, null, 2) }],
}; };
@ -2077,9 +2181,25 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
case "delete_issue_link": { case "delete_issue_link": {
const args = DeleteIssueLinkSchema.parse(request.params.arguments); const args = DeleteIssueLinkSchema.parse(request.params.arguments);
await deleteIssueLink(args.project_id, args.issue_iid, args.issue_link_id); await deleteIssueLink(
args.project_id,
args.issue_iid,
args.issue_link_id
);
return { return {
content: [{ type: "text", text: JSON.stringify({ status: "success", message: "Issue link deleted successfully" }, null, 2) }], content: [
{
type: "text",
text: JSON.stringify(
{
status: "success",
message: "Issue link deleted successfully",
},
null,
2
),
},
],
}; };
} }
@ -2093,7 +2213,11 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
case "get_label": { case "get_label": {
const args = GetLabelSchema.parse(request.params.arguments); const args = GetLabelSchema.parse(request.params.arguments);
const label = await getLabel(args.project_id, args.label_id, args.include_ancestor_groups); const label = await getLabel(
args.project_id,
args.label_id,
args.include_ancestor_groups
);
return { return {
content: [{ type: "text", text: JSON.stringify(label, null, 2) }], content: [{ type: "text", text: JSON.stringify(label, null, 2) }],
}; };
@ -2120,7 +2244,16 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
const args = DeleteLabelSchema.parse(request.params.arguments); const args = DeleteLabelSchema.parse(request.params.arguments);
await deleteLabel(args.project_id, args.label_id); await deleteLabel(args.project_id, args.label_id);
return { return {
content: [{ type: "text", text: JSON.stringify({ status: "success", message: "Label deleted successfully" }, null, 2) }], content: [
{
type: "text",
text: JSON.stringify(
{ status: "success", message: "Label deleted successfully" },
null,
2
),
},
],
}; };
} }

View File

@ -1,6 +1,6 @@
{ {
"name": "@zereight/mcp-gitlab", "name": "@zereight/mcp-gitlab",
"version": "1.0.25", "version": "1.0.27",
"description": "MCP server for using the GitLab API", "description": "MCP server for using the GitLab API",
"license": "MIT", "license": "MIT",
"author": "zereight", "author": "zereight",
@ -19,7 +19,7 @@
"build": "tsc && node -e \"require('fs').chmodSync('build/index.js', '755')\"", "build": "tsc && node -e \"require('fs').chmodSync('build/index.js', '755')\"",
"prepare": "npm run build", "prepare": "npm run build",
"watch": "tsc --watch", "watch": "tsc --watch",
"deploy": "npm run build && npm publish" "deploy": "npm publish --access public"
}, },
"dependencies": { "dependencies": {
"@modelcontextprotocol/sdk": "1.8.0", "@modelcontextprotocol/sdk": "1.8.0",