Attempt to make this work

This commit is contained in:
Mark Wylde
2025-05-31 00:56:07 +01:00
parent ea134ca929
commit 5171232878
8 changed files with 300 additions and 137 deletions

View File

@@ -17,7 +17,7 @@ console.log(`[GITEA-MCP] REPO_OWNER: ${REPO_OWNER}`);
console.log(`[GITEA-MCP] REPO_NAME: ${REPO_NAME}`);
console.log(`[GITEA-MCP] BRANCH_NAME: ${BRANCH_NAME}`);
console.log(`[GITEA-MCP] GITEA_API_URL: ${GITEA_API_URL}`);
console.log(`[GITEA-MCP] GITHUB_TOKEN: ${GITHUB_TOKEN ? '***' : 'undefined'}`);
console.log(`[GITEA-MCP] GITHUB_TOKEN: ${GITHUB_TOKEN ? "***" : "undefined"}`);
if (!REPO_OWNER || !REPO_NAME || !GITHUB_TOKEN) {
console.error(
@@ -39,10 +39,10 @@ async function giteaRequest(
): Promise<any> {
const url = `${GITEA_API_URL}${endpoint}`;
console.log(`[GITEA-MCP] Making ${method} request to: ${url}`);
const headers: Record<string, string> = {
"Authorization": `token ${GITHUB_TOKEN}`,
"Accept": "application/json",
Authorization: `token ${GITHUB_TOKEN}`,
Accept: "application/json",
};
if (body) {
@@ -60,7 +60,9 @@ async function giteaRequest(
console.log(`[GITEA-MCP] Response: ${responseText.substring(0, 500)}...`);
if (!response.ok) {
throw new Error(`Gitea API request failed: ${response.status} ${responseText}`);
throw new Error(
`Gitea API request failed: ${response.status} ${responseText}`,
);
}
return responseText ? JSON.parse(responseText) : null;
@@ -75,8 +77,10 @@ server.tool(
},
async ({ issue_number }) => {
try {
const issue = await giteaRequest(`/api/v1/repos/${REPO_OWNER}/${REPO_NAME}/issues/${issue_number}`);
const issue = await giteaRequest(
`/api/v1/repos/${REPO_OWNER}/${REPO_NAME}/issues/${issue_number}`,
);
return {
content: [
{
@@ -86,7 +90,8 @@ server.tool(
],
};
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
const errorMessage =
error instanceof Error ? error.message : String(error);
console.error(`[GITEA-MCP] Error getting issue: ${errorMessage}`);
return {
content: [
@@ -108,23 +113,31 @@ server.tool(
"Get all comments for a specific issue",
{
issue_number: z.number().describe("The issue number to fetch comments for"),
since: z.string().optional().describe("Only show comments updated after this time (ISO 8601 format)"),
before: z.string().optional().describe("Only show comments updated before this time (ISO 8601 format)"),
since: z
.string()
.optional()
.describe("Only show comments updated after this time (ISO 8601 format)"),
before: z
.string()
.optional()
.describe(
"Only show comments updated before this time (ISO 8601 format)",
),
},
async ({ issue_number, since, before }) => {
try {
let endpoint = `/api/v1/repos/${REPO_OWNER}/${REPO_NAME}/issues/${issue_number}/comments`;
const params = new URLSearchParams();
if (since) params.append("since", since);
if (before) params.append("before", before);
if (params.toString()) {
endpoint += `?${params.toString()}`;
}
const comments = await giteaRequest(endpoint);
return {
content: [
{
@@ -134,8 +147,11 @@ server.tool(
],
};
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
console.error(`[GITEA-MCP] Error getting issue comments: ${errorMessage}`);
const errorMessage =
error instanceof Error ? error.message : String(error);
console.error(
`[GITEA-MCP] Error getting issue comments: ${errorMessage}`,
);
return {
content: [
{
@@ -165,7 +181,7 @@ server.tool(
"POST",
{ body },
);
return {
content: [
{
@@ -175,7 +191,8 @@ server.tool(
],
};
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
const errorMessage =
error instanceof Error ? error.message : String(error);
console.error(`[GITEA-MCP] Error adding issue comment: ${errorMessage}`);
return {
content: [
@@ -206,7 +223,7 @@ server.tool(
"PATCH",
{ body },
);
return {
content: [
{
@@ -216,8 +233,11 @@ server.tool(
],
};
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
console.error(`[GITEA-MCP] Error updating issue comment: ${errorMessage}`);
const errorMessage =
error instanceof Error ? error.message : String(error);
console.error(
`[GITEA-MCP] Error updating issue comment: ${errorMessage}`,
);
return {
content: [
{
@@ -245,7 +265,7 @@ server.tool(
`/api/v1/repos/${REPO_OWNER}/${REPO_NAME}/issues/comments/${comment_id}`,
"DELETE",
);
return {
content: [
{
@@ -255,8 +275,11 @@ server.tool(
],
};
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
console.error(`[GITEA-MCP] Error deleting issue comment: ${errorMessage}`);
const errorMessage =
error instanceof Error ? error.message : String(error);
console.error(
`[GITEA-MCP] Error deleting issue comment: ${errorMessage}`,
);
return {
content: [
{
@@ -280,8 +303,10 @@ server.tool(
},
async ({ comment_id }) => {
try {
const comment = await giteaRequest(`/api/v1/repos/${REPO_OWNER}/${REPO_NAME}/issues/comments/${comment_id}`);
const comment = await giteaRequest(
`/api/v1/repos/${REPO_OWNER}/${REPO_NAME}/issues/comments/${comment_id}`,
);
return {
content: [
{
@@ -291,7 +316,8 @@ server.tool(
],
};
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
const errorMessage =
error instanceof Error ? error.message : String(error);
console.error(`[GITEA-MCP] Error getting comment: ${errorMessage}`);
return {
content: [
@@ -312,20 +338,44 @@ server.tool(
"list_issues",
"List issues in the repository",
{
state: z.enum(["open", "closed", "all"]).optional().describe("Issue state filter"),
labels: z.string().optional().describe("Comma-separated list of label names"),
state: z
.enum(["open", "closed", "all"])
.optional()
.describe("Issue state filter"),
labels: z
.string()
.optional()
.describe("Comma-separated list of label names"),
milestone: z.string().optional().describe("Milestone title to filter by"),
assignee: z.string().optional().describe("Username to filter issues assigned to"),
creator: z.string().optional().describe("Username to filter issues created by"),
mentioned: z.string().optional().describe("Username to filter issues that mention"),
assignee: z
.string()
.optional()
.describe("Username to filter issues assigned to"),
creator: z
.string()
.optional()
.describe("Username to filter issues created by"),
mentioned: z
.string()
.optional()
.describe("Username to filter issues that mention"),
page: z.number().optional().describe("Page number for pagination"),
limit: z.number().optional().describe("Number of items per page"),
},
async ({ state, labels, milestone, assignee, creator, mentioned, page, limit }) => {
async ({
state,
labels,
milestone,
assignee,
creator,
mentioned,
page,
limit,
}) => {
try {
let endpoint = `/api/v1/repos/${REPO_OWNER}/${REPO_NAME}/issues`;
const params = new URLSearchParams();
if (state) params.append("state", state);
if (labels) params.append("labels", labels);
if (milestone) params.append("milestone", milestone);
@@ -334,13 +384,13 @@ server.tool(
if (mentioned) params.append("mentioned", mentioned);
if (page) params.append("page", page.toString());
if (limit) params.append("limit", limit.toString());
if (params.toString()) {
endpoint += `?${params.toString()}`;
}
const issues = await giteaRequest(endpoint);
return {
content: [
{
@@ -350,7 +400,8 @@ server.tool(
],
};
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
const errorMessage =
error instanceof Error ? error.message : String(error);
console.error(`[GITEA-MCP] Error listing issues: ${errorMessage}`);
return {
content: [
@@ -374,14 +425,23 @@ server.tool(
title: z.string().describe("Issue title"),
body: z.string().optional().describe("Issue body content"),
assignee: z.string().optional().describe("Username to assign the issue to"),
assignees: z.array(z.string()).optional().describe("Array of usernames to assign the issue to"),
milestone: z.number().optional().describe("Milestone ID to associate with the issue"),
labels: z.array(z.string()).optional().describe("Array of label names to apply to the issue"),
assignees: z
.array(z.string())
.optional()
.describe("Array of usernames to assign the issue to"),
milestone: z
.number()
.optional()
.describe("Milestone ID to associate with the issue"),
labels: z
.array(z.string())
.optional()
.describe("Array of label names to apply to the issue"),
},
async ({ title, body, assignee, assignees, milestone, labels }) => {
try {
const issueData: any = { title };
if (body) issueData.body = body;
if (assignee) issueData.assignee = assignee;
if (assignees) issueData.assignees = assignees;
@@ -393,7 +453,7 @@ server.tool(
"POST",
issueData,
);
return {
content: [
{
@@ -403,7 +463,8 @@ server.tool(
],
};
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
const errorMessage =
error instanceof Error ? error.message : String(error);
console.error(`[GITEA-MCP] Error creating issue: ${errorMessage}`);
return {
content: [
@@ -428,15 +489,33 @@ server.tool(
title: z.string().optional().describe("New issue title"),
body: z.string().optional().describe("New issue body content"),
assignee: z.string().optional().describe("Username to assign the issue to"),
assignees: z.array(z.string()).optional().describe("Array of usernames to assign the issue to"),
milestone: z.number().optional().describe("Milestone ID to associate with the issue"),
labels: z.array(z.string()).optional().describe("Array of label names to apply to the issue"),
assignees: z
.array(z.string())
.optional()
.describe("Array of usernames to assign the issue to"),
milestone: z
.number()
.optional()
.describe("Milestone ID to associate with the issue"),
labels: z
.array(z.string())
.optional()
.describe("Array of label names to apply to the issue"),
state: z.enum(["open", "closed"]).optional().describe("Issue state"),
},
async ({ issue_number, title, body, assignee, assignees, milestone, labels, state }) => {
async ({
issue_number,
title,
body,
assignee,
assignees,
milestone,
labels,
state,
}) => {
try {
const updateData: any = {};
if (title) updateData.title = title;
if (body !== undefined) updateData.body = body;
if (assignee) updateData.assignee = assignee;
@@ -450,7 +529,7 @@ server.tool(
"PATCH",
updateData,
);
return {
content: [
{
@@ -460,7 +539,8 @@ server.tool(
],
};
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
const errorMessage =
error instanceof Error ? error.message : String(error);
console.error(`[GITEA-MCP] Error updating issue: ${errorMessage}`);
return {
content: [
@@ -477,45 +557,43 @@ server.tool(
);
// Get repository information
server.tool(
"get_repository",
"Get repository information",
{},
async () => {
try {
const repo = await giteaRequest(`/api/v1/repos/${REPO_OWNER}/${REPO_NAME}`);
return {
content: [
{
type: "text",
text: JSON.stringify(repo, null, 2),
},
],
};
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
console.error(`[GITEA-MCP] Error getting repository: ${errorMessage}`);
return {
content: [
{
type: "text",
text: `Error getting repository: ${errorMessage}`,
},
],
error: errorMessage,
isError: true,
};
}
},
);
server.tool("get_repository", "Get repository information", {}, async () => {
try {
const repo = await giteaRequest(`/api/v1/repos/${REPO_OWNER}/${REPO_NAME}`);
return {
content: [
{
type: "text",
text: JSON.stringify(repo, null, 2),
},
],
};
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
console.error(`[GITEA-MCP] Error getting repository: ${errorMessage}`);
return {
content: [
{
type: "text",
text: `Error getting repository: ${errorMessage}`,
},
],
error: errorMessage,
isError: true,
};
}
});
// Get pull requests
server.tool(
"list_pull_requests",
"List pull requests in the repository",
{
state: z.enum(["open", "closed", "all"]).optional().describe("Pull request state filter"),
state: z
.enum(["open", "closed", "all"])
.optional()
.describe("Pull request state filter"),
head: z.string().optional().describe("Head branch name"),
base: z.string().optional().describe("Base branch name"),
page: z.number().optional().describe("Page number for pagination"),
@@ -525,19 +603,19 @@ server.tool(
try {
let endpoint = `/api/v1/repos/${REPO_OWNER}/${REPO_NAME}/pulls`;
const params = new URLSearchParams();
if (state) params.append("state", state);
if (head) params.append("head", head);
if (base) params.append("base", base);
if (page) params.append("page", page.toString());
if (limit) params.append("limit", limit.toString());
if (params.toString()) {
endpoint += `?${params.toString()}`;
}
const pulls = await giteaRequest(endpoint);
return {
content: [
{
@@ -547,7 +625,8 @@ server.tool(
],
};
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
const errorMessage =
error instanceof Error ? error.message : String(error);
console.error(`[GITEA-MCP] Error listing pull requests: ${errorMessage}`);
return {
content: [
@@ -572,8 +651,10 @@ server.tool(
},
async ({ pull_number }) => {
try {
const pull = await giteaRequest(`/api/v1/repos/${REPO_OWNER}/${REPO_NAME}/pulls/${pull_number}`);
const pull = await giteaRequest(
`/api/v1/repos/${REPO_OWNER}/${REPO_NAME}/pulls/${pull_number}`,
);
return {
content: [
{
@@ -583,7 +664,8 @@ server.tool(
],
};
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
const errorMessage =
error instanceof Error ? error.message : String(error);
console.error(`[GITEA-MCP] Error getting pull request: ${errorMessage}`);
return {
content: [
@@ -608,15 +690,36 @@ server.tool(
body: z.string().optional().describe("Pull request body/description"),
head: z.string().describe("Head branch name"),
base: z.string().describe("Base branch name"),
assignee: z.string().optional().describe("Username to assign the pull request to"),
assignees: z.array(z.string()).optional().describe("Array of usernames to assign the pull request to"),
milestone: z.number().optional().describe("Milestone ID to associate with the pull request"),
labels: z.array(z.string()).optional().describe("Array of label names to apply to the pull request"),
assignee: z
.string()
.optional()
.describe("Username to assign the pull request to"),
assignees: z
.array(z.string())
.optional()
.describe("Array of usernames to assign the pull request to"),
milestone: z
.number()
.optional()
.describe("Milestone ID to associate with the pull request"),
labels: z
.array(z.string())
.optional()
.describe("Array of label names to apply to the pull request"),
},
async ({ title, body, head, base, assignee, assignees, milestone, labels }) => {
async ({
title,
body,
head,
base,
assignee,
assignees,
milestone,
labels,
}) => {
try {
const pullData: any = { title, head, base };
if (body) pullData.body = body;
if (assignee) pullData.assignee = assignee;
if (assignees) pullData.assignees = assignees;
@@ -628,7 +731,7 @@ server.tool(
"POST",
pullData,
);
return {
content: [
{
@@ -638,7 +741,8 @@ server.tool(
],
};
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
const errorMessage =
error instanceof Error ? error.message : String(error);
console.error(`[GITEA-MCP] Error creating pull request: ${errorMessage}`);
return {
content: [
@@ -670,4 +774,4 @@ console.log(`[GITEA-MCP] Calling runServer()...`);
runServer().catch((error) => {
console.error(`[GITEA-MCP] Server startup failed:`, error);
process.exit(1);
});
});

View File

@@ -10,10 +10,16 @@ export async function prepareMcpConfig(
console.log(`[MCP-INSTALL] Owner: ${owner}`);
console.log(`[MCP-INSTALL] Repo: ${repo}`);
console.log(`[MCP-INSTALL] Branch: ${branch}`);
console.log(`[MCP-INSTALL] GitHub token: ${githubToken ? '***' : 'undefined'}`);
console.log(`[MCP-INSTALL] GITHUB_ACTION_PATH: ${process.env.GITHUB_ACTION_PATH}`);
console.log(`[MCP-INSTALL] GITHUB_WORKSPACE: ${process.env.GITHUB_WORKSPACE}`);
console.log(
`[MCP-INSTALL] GitHub token: ${githubToken ? "***" : "undefined"}`,
);
console.log(
`[MCP-INSTALL] GITHUB_ACTION_PATH: ${process.env.GITHUB_ACTION_PATH}`,
);
console.log(
`[MCP-INSTALL] GITHUB_WORKSPACE: ${process.env.GITHUB_WORKSPACE}`,
);
try {
const mcpConfig = {
mcpServers: {
@@ -29,7 +35,8 @@ export async function prepareMcpConfig(
REPO_NAME: repo,
BRANCH_NAME: branch,
REPO_DIR: process.env.GITHUB_WORKSPACE || process.cwd(),
GITEA_API_URL: process.env.GITEA_API_URL || "https://api.github.com",
GITEA_API_URL:
process.env.GITEA_API_URL || "https://api.github.com",
},
},
local_git_ops: {
@@ -55,7 +62,7 @@ export async function prepareMcpConfig(
console.log("[MCP-INSTALL] Generated MCP configuration:");
console.log(configString);
console.log("[MCP-INSTALL] MCP config generation completed successfully");
return configString;
} catch (error) {
console.error("[MCP-INSTALL] MCP config generation failed:", error);

View File

@@ -21,7 +21,9 @@ console.log(`[LOCAL-GIT-MCP] REPO_NAME: ${REPO_NAME}`);
console.log(`[LOCAL-GIT-MCP] BRANCH_NAME: ${BRANCH_NAME}`);
console.log(`[LOCAL-GIT-MCP] REPO_DIR: ${REPO_DIR}`);
console.log(`[LOCAL-GIT-MCP] GITEA_API_URL: ${GITEA_API_URL}`);
console.log(`[LOCAL-GIT-MCP] GITHUB_TOKEN: ${GITHUB_TOKEN ? '***' : 'undefined'}`);
console.log(
`[LOCAL-GIT-MCP] GITHUB_TOKEN: ${GITHUB_TOKEN ? "***" : "undefined"}`,
);
if (!REPO_OWNER || !REPO_NAME || !BRANCH_NAME) {
console.error(
@@ -63,7 +65,9 @@ function ensureGitUserConfigured(): void {
runGitCommand("git config user.email");
console.log(`[LOCAL-GIT-MCP] Git user.email already configured`);
} catch (error) {
console.log(`[LOCAL-GIT-MCP] Git user.email not configured, setting default`);
console.log(
`[LOCAL-GIT-MCP] Git user.email not configured, setting default`,
);
runGitCommand('git config user.email "claude@anthropic.com"');
}
@@ -72,7 +76,9 @@ function ensureGitUserConfigured(): void {
runGitCommand("git config user.name");
console.log(`[LOCAL-GIT-MCP] Git user.name already configured`);
} catch (error) {
console.log(`[LOCAL-GIT-MCP] Git user.name not configured, setting default`);
console.log(
`[LOCAL-GIT-MCP] Git user.name not configured, setting default`,
);
runGitCommand('git config user.name "Claude"');
}
}
@@ -134,7 +140,9 @@ server.tool(
message: z.string().describe("Commit message"),
},
async ({ files, message }) => {
console.log(`[LOCAL-GIT-MCP] commit_files called with files: ${JSON.stringify(files)}, message: ${message}`);
console.log(
`[LOCAL-GIT-MCP] commit_files called with files: ${JSON.stringify(files)}, message: ${message}`,
);
try {
// Ensure git user is configured before committing
ensureGitUserConfigured();
@@ -151,7 +159,9 @@ server.tool(
console.log(`[LOCAL-GIT-MCP] Committing with message: ${message}`);
runGitCommand(`git commit -m "${message}"`);
console.log(`[LOCAL-GIT-MCP] Successfully committed ${files.length} files`);
console.log(
`[LOCAL-GIT-MCP] Successfully committed ${files.length} files`,
);
return {
content: [
{
@@ -353,7 +363,9 @@ server.tool("git_status", "Get the current git status", {}, async () => {
const currentBranch = runGitCommand("git rev-parse --abbrev-ref HEAD");
console.log(`[LOCAL-GIT-MCP] Current branch: ${currentBranch}`);
console.log(`[LOCAL-GIT-MCP] Git status: ${status || "Working tree clean"}`);
console.log(
`[LOCAL-GIT-MCP] Git status: ${status || "Working tree clean"}`,
);
return {
content: [