|
|
@@ -12,6 +12,18 @@ import {
|
|
|
} from '@modelcontextprotocol/sdk/types.js';
|
|
|
import { z } from 'zod';
|
|
|
import { GogsClient } from './gogs-client.js';
|
|
|
+import {
|
|
|
+ formatGogsError,
|
|
|
+ validateUserExists,
|
|
|
+ validateRepoExists,
|
|
|
+ validateBranchExists,
|
|
|
+ validateIssueExists,
|
|
|
+ validateLabelExists,
|
|
|
+ validateLabelsExist,
|
|
|
+ validateMilestoneExists,
|
|
|
+ validateOrgExists,
|
|
|
+ validateTeamExists,
|
|
|
+} from './validation.js';
|
|
|
|
|
|
/**
|
|
|
* Helper function to create owner/repo schema fields that are optional when restricted
|
|
|
@@ -2617,6 +2629,12 @@ export function createMcpServer(gogsClient: GogsClient, restrictedOwner?: string
|
|
|
case 'get_commits': {
|
|
|
const parsed = GetCommitsSchema.parse(args);
|
|
|
const { owner, repo } = resolveRepoParams(parsed.owner, parsed.repo, restrictedOwner, restrictedRepo);
|
|
|
+
|
|
|
+ // Validate branch exists if sha is provided
|
|
|
+ if (parsed.sha) {
|
|
|
+ await validateBranchExists(gogsClient, owner, repo, parsed.sha);
|
|
|
+ }
|
|
|
+
|
|
|
const commits = await gogsClient.getCommits(owner, repo, { sha: parsed.sha, page: parsed.page });
|
|
|
return {
|
|
|
content: [
|
|
|
@@ -2673,6 +2691,22 @@ export function createMcpServer(gogsClient: GogsClient, restrictedOwner?: string
|
|
|
case 'create_issue': {
|
|
|
const parsed = CreateIssueSchema.parse(args);
|
|
|
const { owner, repo } = resolveRepoParams(parsed.owner, parsed.repo, restrictedOwner, restrictedRepo);
|
|
|
+
|
|
|
+ // Validate assignee exists if provided
|
|
|
+ if (parsed.assignee) {
|
|
|
+ await validateUserExists(gogsClient, parsed.assignee, 'assignee');
|
|
|
+ }
|
|
|
+
|
|
|
+ // Validate milestone exists if provided
|
|
|
+ if (parsed.milestone) {
|
|
|
+ await validateMilestoneExists(gogsClient, owner, repo, parsed.milestone);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Validate labels exist if provided
|
|
|
+ if (parsed.labels && parsed.labels.length > 0) {
|
|
|
+ await validateLabelsExist(gogsClient, owner, repo, parsed.labels);
|
|
|
+ }
|
|
|
+
|
|
|
const issue = await gogsClient.createIssue(owner, repo, {
|
|
|
title: parsed.title,
|
|
|
body: parsed.body,
|
|
|
@@ -2693,6 +2727,22 @@ export function createMcpServer(gogsClient: GogsClient, restrictedOwner?: string
|
|
|
case 'update_issue': {
|
|
|
const parsed = UpdateIssueSchema.parse(args);
|
|
|
const { owner, repo } = resolveRepoParams(parsed.owner, parsed.repo, restrictedOwner, restrictedRepo);
|
|
|
+
|
|
|
+ // Validate assignee exists if provided
|
|
|
+ if (parsed.assignee) {
|
|
|
+ await validateUserExists(gogsClient, parsed.assignee, 'assignee');
|
|
|
+ }
|
|
|
+
|
|
|
+ // Validate milestone exists if provided
|
|
|
+ if (parsed.milestone) {
|
|
|
+ await validateMilestoneExists(gogsClient, owner, repo, parsed.milestone);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Validate labels exist if provided
|
|
|
+ if (parsed.labels && parsed.labels.length > 0) {
|
|
|
+ await validateLabelsExist(gogsClient, owner, repo, parsed.labels);
|
|
|
+ }
|
|
|
+
|
|
|
const issue = await gogsClient.updateIssue(owner, repo, parsed.number, {
|
|
|
title: parsed.title,
|
|
|
body: parsed.body,
|
|
|
@@ -2840,6 +2890,10 @@ export function createMcpServer(gogsClient: GogsClient, restrictedOwner?: string
|
|
|
case 'add_issue_labels': {
|
|
|
const parsed = AddIssueLabelsSchema.parse(args);
|
|
|
const { owner, repo } = resolveRepoParams(parsed.owner, parsed.repo, restrictedOwner, restrictedRepo);
|
|
|
+
|
|
|
+ // Validate labels exist
|
|
|
+ await validateLabelsExist(gogsClient, owner, repo, parsed.labels);
|
|
|
+
|
|
|
const result = await gogsClient.addIssueLabels(owner, repo, parsed.number, parsed.labels);
|
|
|
return {
|
|
|
content: [
|
|
|
@@ -2868,6 +2922,10 @@ export function createMcpServer(gogsClient: GogsClient, restrictedOwner?: string
|
|
|
case 'replace_issue_labels': {
|
|
|
const parsed = ReplaceIssueLabelsSchema.parse(args);
|
|
|
const { owner, repo } = resolveRepoParams(parsed.owner, parsed.repo, restrictedOwner, restrictedRepo);
|
|
|
+
|
|
|
+ // Validate labels exist
|
|
|
+ await validateLabelsExist(gogsClient, owner, repo, parsed.labels);
|
|
|
+
|
|
|
const result = await gogsClient.replaceIssueLabels(owner, repo, parsed.number, parsed.labels);
|
|
|
return {
|
|
|
content: [
|
|
|
@@ -3049,6 +3107,13 @@ export function createMcpServer(gogsClient: GogsClient, restrictedOwner?: string
|
|
|
|
|
|
case 'add_organization_member': {
|
|
|
const { orgname, username, role } = AddOrganizationMemberSchema.parse(args);
|
|
|
+
|
|
|
+ // Validate organization exists
|
|
|
+ await validateOrgExists(gogsClient, orgname);
|
|
|
+
|
|
|
+ // Validate user exists before adding to organization
|
|
|
+ await validateUserExists(gogsClient, username, 'username');
|
|
|
+
|
|
|
await gogsClient.addOrganizationMember(orgname, username, role);
|
|
|
return {
|
|
|
content: [
|
|
|
@@ -3105,6 +3170,13 @@ export function createMcpServer(gogsClient: GogsClient, restrictedOwner?: string
|
|
|
|
|
|
case 'add_team_member': {
|
|
|
const { teamId, username } = AddTeamMemberSchema.parse(args);
|
|
|
+
|
|
|
+ // Validate team exists
|
|
|
+ await validateTeamExists(gogsClient, teamId);
|
|
|
+
|
|
|
+ // Validate user exists before adding to team
|
|
|
+ await validateUserExists(gogsClient, username, 'username');
|
|
|
+
|
|
|
await gogsClient.addTeamMember(teamId, username);
|
|
|
return {
|
|
|
content: [
|
|
|
@@ -3174,6 +3246,10 @@ export function createMcpServer(gogsClient: GogsClient, restrictedOwner?: string
|
|
|
case 'add_collaborator': {
|
|
|
const parsed = AddCollaboratorSchema.parse(args);
|
|
|
const { owner, repo } = resolveRepoParams(parsed.owner, parsed.repo, restrictedOwner, restrictedRepo);
|
|
|
+
|
|
|
+ // Validate user exists before adding as collaborator
|
|
|
+ await validateUserExists(gogsClient, parsed.username, 'username');
|
|
|
+
|
|
|
await gogsClient.addCollaborator(owner, repo, parsed.username, parsed.permission);
|
|
|
return {
|
|
|
content: [
|
|
|
@@ -3697,18 +3773,17 @@ export function createMcpServer(gogsClient: GogsClient, restrictedOwner?: string
|
|
|
throw new Error(`Unknown tool: ${name}`);
|
|
|
}
|
|
|
} catch (error) {
|
|
|
- if (error instanceof Error) {
|
|
|
- return {
|
|
|
- content: [
|
|
|
- {
|
|
|
- type: 'text',
|
|
|
- text: `Error: ${error.message}`,
|
|
|
- },
|
|
|
- ],
|
|
|
- isError: true,
|
|
|
- };
|
|
|
- }
|
|
|
- throw error;
|
|
|
+ // Use enhanced error formatting
|
|
|
+ const errorMessage = formatGogsError(error);
|
|
|
+ return {
|
|
|
+ content: [
|
|
|
+ {
|
|
|
+ type: 'text',
|
|
|
+ text: errorMessage,
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ isError: true,
|
|
|
+ };
|
|
|
}
|
|
|
});
|
|
|
|