|
|
@@ -112,6 +112,63 @@ const GetCommitsSchema = z.object({
|
|
|
page: z.number().optional().describe('Page number (default: 1)'),
|
|
|
});
|
|
|
|
|
|
+const ListIssuesSchema = z.object({
|
|
|
+ owner: z.string().describe('Repository owner username'),
|
|
|
+ repo: z.string().describe('Repository name'),
|
|
|
+ state: z.enum(['open', 'closed', 'all']).optional().describe('Filter by state (default: open)'),
|
|
|
+ labels: z.string().optional().describe('Comma-separated list of label names'),
|
|
|
+ page: z.number().optional().describe('Page number (default: 1)'),
|
|
|
+ per_page: z.number().optional().describe('Results per page (default: 30)'),
|
|
|
+});
|
|
|
+
|
|
|
+const GetIssueSchema = z.object({
|
|
|
+ owner: z.string().describe('Repository owner username'),
|
|
|
+ repo: z.string().describe('Repository name'),
|
|
|
+ number: z.number().describe('Issue number'),
|
|
|
+});
|
|
|
+
|
|
|
+const CreateIssueSchema = z.object({
|
|
|
+ owner: z.string().describe('Repository owner username'),
|
|
|
+ repo: z.string().describe('Repository name'),
|
|
|
+ title: z.string().describe('Issue title'),
|
|
|
+ body: z.string().optional().describe('Issue description'),
|
|
|
+ assignee: z.string().optional().describe('Username to assign the issue to'),
|
|
|
+ milestone: z.number().optional().describe('Milestone ID'),
|
|
|
+ labels: z.array(z.number()).optional().describe('Array of label IDs'),
|
|
|
+});
|
|
|
+
|
|
|
+const UpdateIssueSchema = z.object({
|
|
|
+ owner: z.string().describe('Repository owner username'),
|
|
|
+ repo: z.string().describe('Repository name'),
|
|
|
+ number: z.number().describe('Issue number'),
|
|
|
+ title: z.string().optional().describe('Issue title'),
|
|
|
+ body: z.string().optional().describe('Issue description'),
|
|
|
+ assignee: z.string().optional().describe('Username to assign the issue to'),
|
|
|
+ milestone: z.number().optional().describe('Milestone ID'),
|
|
|
+ state: z.enum(['open', 'closed']).optional().describe('Issue state'),
|
|
|
+ labels: z.array(z.number()).optional().describe('Array of label IDs'),
|
|
|
+});
|
|
|
+
|
|
|
+const ListIssueCommentsSchema = z.object({
|
|
|
+ owner: z.string().describe('Repository owner username'),
|
|
|
+ repo: z.string().describe('Repository name'),
|
|
|
+ number: z.number().describe('Issue number'),
|
|
|
+});
|
|
|
+
|
|
|
+const CreateIssueCommentSchema = z.object({
|
|
|
+ owner: z.string().describe('Repository owner username'),
|
|
|
+ repo: z.string().describe('Repository name'),
|
|
|
+ number: z.number().describe('Issue number'),
|
|
|
+ body: z.string().describe('Comment text'),
|
|
|
+});
|
|
|
+
|
|
|
+const UpdateIssueCommentSchema = z.object({
|
|
|
+ owner: z.string().describe('Repository owner username'),
|
|
|
+ repo: z.string().describe('Repository name'),
|
|
|
+ commentId: z.number().describe('Comment ID'),
|
|
|
+ body: z.string().describe('Updated comment text'),
|
|
|
+});
|
|
|
+
|
|
|
// Register tools
|
|
|
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
return {
|
|
|
@@ -365,6 +422,228 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
required: ['owner', 'repo'],
|
|
|
},
|
|
|
},
|
|
|
+ {
|
|
|
+ name: 'list_issues',
|
|
|
+ description: 'List issues in a repository',
|
|
|
+ inputSchema: {
|
|
|
+ type: 'object',
|
|
|
+ properties: {
|
|
|
+ owner: {
|
|
|
+ type: 'string',
|
|
|
+ description: 'Repository owner username',
|
|
|
+ },
|
|
|
+ repo: {
|
|
|
+ type: 'string',
|
|
|
+ description: 'Repository name',
|
|
|
+ },
|
|
|
+ state: {
|
|
|
+ type: 'string',
|
|
|
+ enum: ['open', 'closed', 'all'],
|
|
|
+ description: 'Filter by state (default: open)',
|
|
|
+ },
|
|
|
+ labels: {
|
|
|
+ type: 'string',
|
|
|
+ description: 'Comma-separated list of label names',
|
|
|
+ },
|
|
|
+ page: {
|
|
|
+ type: 'number',
|
|
|
+ description: 'Page number (default: 1)',
|
|
|
+ },
|
|
|
+ per_page: {
|
|
|
+ type: 'number',
|
|
|
+ description: 'Results per page (default: 30)',
|
|
|
+ },
|
|
|
+ },
|
|
|
+ required: ['owner', 'repo'],
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: 'get_issue',
|
|
|
+ description: 'Get a specific issue by number',
|
|
|
+ inputSchema: {
|
|
|
+ type: 'object',
|
|
|
+ properties: {
|
|
|
+ owner: {
|
|
|
+ type: 'string',
|
|
|
+ description: 'Repository owner username',
|
|
|
+ },
|
|
|
+ repo: {
|
|
|
+ type: 'string',
|
|
|
+ description: 'Repository name',
|
|
|
+ },
|
|
|
+ number: {
|
|
|
+ type: 'number',
|
|
|
+ description: 'Issue number',
|
|
|
+ },
|
|
|
+ },
|
|
|
+ required: ['owner', 'repo', 'number'],
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: 'create_issue',
|
|
|
+ description: 'Create a new issue in a repository',
|
|
|
+ inputSchema: {
|
|
|
+ type: 'object',
|
|
|
+ properties: {
|
|
|
+ owner: {
|
|
|
+ type: 'string',
|
|
|
+ description: 'Repository owner username',
|
|
|
+ },
|
|
|
+ repo: {
|
|
|
+ type: 'string',
|
|
|
+ description: 'Repository name',
|
|
|
+ },
|
|
|
+ title: {
|
|
|
+ type: 'string',
|
|
|
+ description: 'Issue title',
|
|
|
+ },
|
|
|
+ body: {
|
|
|
+ type: 'string',
|
|
|
+ description: 'Issue description',
|
|
|
+ },
|
|
|
+ assignee: {
|
|
|
+ type: 'string',
|
|
|
+ description: 'Username to assign the issue to',
|
|
|
+ },
|
|
|
+ milestone: {
|
|
|
+ type: 'number',
|
|
|
+ description: 'Milestone ID',
|
|
|
+ },
|
|
|
+ labels: {
|
|
|
+ type: 'array',
|
|
|
+ items: {
|
|
|
+ type: 'number',
|
|
|
+ },
|
|
|
+ description: 'Array of label IDs',
|
|
|
+ },
|
|
|
+ },
|
|
|
+ required: ['owner', 'repo', 'title'],
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: 'update_issue',
|
|
|
+ description: 'Update an existing issue (including closing or reopening)',
|
|
|
+ inputSchema: {
|
|
|
+ type: 'object',
|
|
|
+ properties: {
|
|
|
+ owner: {
|
|
|
+ type: 'string',
|
|
|
+ description: 'Repository owner username',
|
|
|
+ },
|
|
|
+ repo: {
|
|
|
+ type: 'string',
|
|
|
+ description: 'Repository name',
|
|
|
+ },
|
|
|
+ number: {
|
|
|
+ type: 'number',
|
|
|
+ description: 'Issue number',
|
|
|
+ },
|
|
|
+ title: {
|
|
|
+ type: 'string',
|
|
|
+ description: 'Issue title',
|
|
|
+ },
|
|
|
+ body: {
|
|
|
+ type: 'string',
|
|
|
+ description: 'Issue description',
|
|
|
+ },
|
|
|
+ assignee: {
|
|
|
+ type: 'string',
|
|
|
+ description: 'Username to assign the issue to',
|
|
|
+ },
|
|
|
+ milestone: {
|
|
|
+ type: 'number',
|
|
|
+ description: 'Milestone ID',
|
|
|
+ },
|
|
|
+ state: {
|
|
|
+ type: 'string',
|
|
|
+ enum: ['open', 'closed'],
|
|
|
+ description: 'Issue state',
|
|
|
+ },
|
|
|
+ labels: {
|
|
|
+ type: 'array',
|
|
|
+ items: {
|
|
|
+ type: 'number',
|
|
|
+ },
|
|
|
+ description: 'Array of label IDs',
|
|
|
+ },
|
|
|
+ },
|
|
|
+ required: ['owner', 'repo', 'number'],
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: 'list_issue_comments',
|
|
|
+ description: 'List all comments on an issue',
|
|
|
+ inputSchema: {
|
|
|
+ type: 'object',
|
|
|
+ properties: {
|
|
|
+ owner: {
|
|
|
+ type: 'string',
|
|
|
+ description: 'Repository owner username',
|
|
|
+ },
|
|
|
+ repo: {
|
|
|
+ type: 'string',
|
|
|
+ description: 'Repository name',
|
|
|
+ },
|
|
|
+ number: {
|
|
|
+ type: 'number',
|
|
|
+ description: 'Issue number',
|
|
|
+ },
|
|
|
+ },
|
|
|
+ required: ['owner', 'repo', 'number'],
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: 'create_issue_comment',
|
|
|
+ description: 'Add a comment to an issue',
|
|
|
+ inputSchema: {
|
|
|
+ type: 'object',
|
|
|
+ properties: {
|
|
|
+ owner: {
|
|
|
+ type: 'string',
|
|
|
+ description: 'Repository owner username',
|
|
|
+ },
|
|
|
+ repo: {
|
|
|
+ type: 'string',
|
|
|
+ description: 'Repository name',
|
|
|
+ },
|
|
|
+ number: {
|
|
|
+ type: 'number',
|
|
|
+ description: 'Issue number',
|
|
|
+ },
|
|
|
+ body: {
|
|
|
+ type: 'string',
|
|
|
+ description: 'Comment text',
|
|
|
+ },
|
|
|
+ },
|
|
|
+ required: ['owner', 'repo', 'number', 'body'],
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: 'update_issue_comment',
|
|
|
+ description: 'Edit an existing comment on an issue',
|
|
|
+ inputSchema: {
|
|
|
+ type: 'object',
|
|
|
+ properties: {
|
|
|
+ owner: {
|
|
|
+ type: 'string',
|
|
|
+ description: 'Repository owner username',
|
|
|
+ },
|
|
|
+ repo: {
|
|
|
+ type: 'string',
|
|
|
+ description: 'Repository name',
|
|
|
+ },
|
|
|
+ commentId: {
|
|
|
+ type: 'number',
|
|
|
+ description: 'Comment ID',
|
|
|
+ },
|
|
|
+ body: {
|
|
|
+ type: 'string',
|
|
|
+ description: 'Updated comment text',
|
|
|
+ },
|
|
|
+ },
|
|
|
+ required: ['owner', 'repo', 'commentId', 'body'],
|
|
|
+ },
|
|
|
+ },
|
|
|
],
|
|
|
};
|
|
|
});
|
|
|
@@ -546,6 +825,110 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
};
|
|
|
}
|
|
|
|
|
|
+ case 'list_issues': {
|
|
|
+ const { owner, repo, state, labels, page, per_page } = ListIssuesSchema.parse(args);
|
|
|
+ const issues = await gogsClient.listIssues(owner, repo, { state, labels, page, per_page });
|
|
|
+ return {
|
|
|
+ content: [
|
|
|
+ {
|
|
|
+ type: 'text',
|
|
|
+ text: JSON.stringify(issues, null, 2),
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ case 'get_issue': {
|
|
|
+ const { owner, repo, number } = GetIssueSchema.parse(args);
|
|
|
+ const issue = await gogsClient.getIssue(owner, repo, number);
|
|
|
+ return {
|
|
|
+ content: [
|
|
|
+ {
|
|
|
+ type: 'text',
|
|
|
+ text: JSON.stringify(issue, null, 2),
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ case 'create_issue': {
|
|
|
+ const { owner, repo, title, body, assignee, milestone, labels } = CreateIssueSchema.parse(args);
|
|
|
+ const issue = await gogsClient.createIssue(owner, repo, {
|
|
|
+ title,
|
|
|
+ body,
|
|
|
+ assignee,
|
|
|
+ milestone,
|
|
|
+ labels,
|
|
|
+ });
|
|
|
+ return {
|
|
|
+ content: [
|
|
|
+ {
|
|
|
+ type: 'text',
|
|
|
+ text: JSON.stringify(issue, null, 2),
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ case 'update_issue': {
|
|
|
+ const { owner, repo, number, title, body, assignee, milestone, state, labels } = UpdateIssueSchema.parse(args);
|
|
|
+ const issue = await gogsClient.updateIssue(owner, repo, number, {
|
|
|
+ title,
|
|
|
+ body,
|
|
|
+ assignee,
|
|
|
+ milestone,
|
|
|
+ state,
|
|
|
+ labels,
|
|
|
+ });
|
|
|
+ return {
|
|
|
+ content: [
|
|
|
+ {
|
|
|
+ type: 'text',
|
|
|
+ text: JSON.stringify(issue, null, 2),
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ case 'list_issue_comments': {
|
|
|
+ const { owner, repo, number } = ListIssueCommentsSchema.parse(args);
|
|
|
+ const comments = await gogsClient.listIssueComments(owner, repo, number);
|
|
|
+ return {
|
|
|
+ content: [
|
|
|
+ {
|
|
|
+ type: 'text',
|
|
|
+ text: JSON.stringify(comments, null, 2),
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ case 'create_issue_comment': {
|
|
|
+ const { owner, repo, number, body } = CreateIssueCommentSchema.parse(args);
|
|
|
+ const comment = await gogsClient.createIssueComment(owner, repo, number, body);
|
|
|
+ return {
|
|
|
+ content: [
|
|
|
+ {
|
|
|
+ type: 'text',
|
|
|
+ text: JSON.stringify(comment, null, 2),
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ case 'update_issue_comment': {
|
|
|
+ const { owner, repo, commentId, body } = UpdateIssueCommentSchema.parse(args);
|
|
|
+ const comment = await gogsClient.updateIssueComment(owner, repo, commentId, body);
|
|
|
+ return {
|
|
|
+ content: [
|
|
|
+ {
|
|
|
+ type: 'text',
|
|
|
+ text: JSON.stringify(comment, null, 2),
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
default:
|
|
|
throw new Error(`Unknown tool: ${name}`);
|
|
|
}
|