mirror of
https://github.com/modelcontextprotocol/servers.git
synced 2026-04-18 08:13:24 +02:00
feat: add issue management functionalities for github
- Implemented `listIssues`, `updateIssue`, and `addIssueComment` functions to manage GitHub issues. - Introduced corresponding schemas: `ListIssuesOptionsSchema`, `UpdateIssueOptionsSchema`, and `IssueCommentSchema`. - Updated server request handlers to support new functionalities. - Enhanced README with documentation for new features.
This commit is contained in:
@@ -41,7 +41,10 @@ import {
|
||||
CreateIssueSchema,
|
||||
CreatePullRequestSchema,
|
||||
ForkRepositorySchema,
|
||||
CreateBranchSchema
|
||||
CreateBranchSchema,
|
||||
ListIssuesOptionsSchema,
|
||||
UpdateIssueOptionsSchema,
|
||||
IssueCommentSchema
|
||||
} from './schemas.js';
|
||||
import { z } from 'zod';
|
||||
import { zodToJsonSchema } from 'zod-to-json-schema';
|
||||
@@ -467,6 +470,98 @@ async function createRepository(
|
||||
return GitHubRepositorySchema.parse(await response.json());
|
||||
}
|
||||
|
||||
async function listIssues(
|
||||
owner: string,
|
||||
repo: string,
|
||||
options: z.infer<typeof ListIssuesOptionsSchema>
|
||||
): Promise<GitHubIssue[]> {
|
||||
const url = new URL(`https://api.github.com/repos/${owner}/${repo}/issues`);
|
||||
|
||||
// Add query parameters
|
||||
if (options.state) url.searchParams.append('state', options.state);
|
||||
if (options.labels) url.searchParams.append('labels', options.labels.join(','));
|
||||
if (options.sort) url.searchParams.append('sort', options.sort);
|
||||
if (options.direction) url.searchParams.append('direction', options.direction);
|
||||
if (options.since) url.searchParams.append('since', options.since);
|
||||
if (options.page) url.searchParams.append('page', options.page.toString());
|
||||
if (options.per_page) url.searchParams.append('per_page', options.per_page.toString());
|
||||
|
||||
const response = await fetch(url.toString(), {
|
||||
headers: {
|
||||
"Authorization": `token ${GITHUB_PERSONAL_ACCESS_TOKEN}`,
|
||||
"Accept": "application/vnd.github.v3+json",
|
||||
"User-Agent": "github-mcp-server"
|
||||
}
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`GitHub API error: ${response.statusText}`);
|
||||
}
|
||||
|
||||
return z.array(GitHubIssueSchema).parse(await response.json());
|
||||
}
|
||||
|
||||
async function updateIssue(
|
||||
owner: string,
|
||||
repo: string,
|
||||
issueNumber: number,
|
||||
options: z.infer<typeof UpdateIssueOptionsSchema>
|
||||
): Promise<GitHubIssue> {
|
||||
const response = await fetch(
|
||||
`https://api.github.com/repos/${owner}/${repo}/issues/${issueNumber}`,
|
||||
{
|
||||
method: "PATCH",
|
||||
headers: {
|
||||
"Authorization": `token ${GITHUB_PERSONAL_ACCESS_TOKEN}`,
|
||||
"Accept": "application/vnd.github.v3+json",
|
||||
"User-Agent": "github-mcp-server",
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
body: JSON.stringify({
|
||||
title: options.title,
|
||||
body: options.body,
|
||||
state: options.state,
|
||||
labels: options.labels,
|
||||
assignees: options.assignees,
|
||||
milestone: options.milestone
|
||||
})
|
||||
}
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`GitHub API error: ${response.statusText}`);
|
||||
}
|
||||
|
||||
return GitHubIssueSchema.parse(await response.json());
|
||||
}
|
||||
|
||||
async function addIssueComment(
|
||||
owner: string,
|
||||
repo: string,
|
||||
issueNumber: number,
|
||||
body: string
|
||||
): Promise<z.infer<typeof IssueCommentSchema>> {
|
||||
const response = await fetch(
|
||||
`https://api.github.com/repos/${owner}/${repo}/issues/${issueNumber}/comments`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Authorization": `token ${GITHUB_PERSONAL_ACCESS_TOKEN}`,
|
||||
"Accept": "application/vnd.github.v3+json",
|
||||
"User-Agent": "github-mcp-server",
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
body: JSON.stringify({ body })
|
||||
}
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`GitHub API error: ${response.statusText}`);
|
||||
}
|
||||
|
||||
return IssueCommentSchema.parse(await response.json());
|
||||
}
|
||||
|
||||
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
||||
return {
|
||||
tools: [
|
||||
@@ -514,6 +609,21 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
||||
name: "create_branch",
|
||||
description: "Create a new branch in a GitHub repository",
|
||||
inputSchema: zodToJsonSchema(CreateBranchSchema)
|
||||
},
|
||||
{
|
||||
name: "list_issues",
|
||||
description: "List issues in a GitHub repository with filtering options",
|
||||
inputSchema: zodToJsonSchema(ListIssuesOptionsSchema)
|
||||
},
|
||||
{
|
||||
name: "update_issue",
|
||||
description: "Update an existing issue in a GitHub repository",
|
||||
inputSchema: zodToJsonSchema(UpdateIssueOptionsSchema)
|
||||
},
|
||||
{
|
||||
name: "add_issue_comment",
|
||||
description: "Add a comment to an existing issue",
|
||||
inputSchema: zodToJsonSchema(IssueCommentSchema)
|
||||
}
|
||||
]
|
||||
};
|
||||
@@ -623,6 +733,27 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
||||
return { toolResult: pullRequest };
|
||||
}
|
||||
|
||||
case "list_issues": {
|
||||
const args = ListIssuesOptionsSchema.parse(request.params.arguments);
|
||||
const { owner, repo, ...options } = args;
|
||||
const issues = await listIssues(owner, repo, options);
|
||||
return { toolResult: issues };
|
||||
}
|
||||
|
||||
case "update_issue": {
|
||||
const args = UpdateIssueOptionsSchema.parse(request.params.arguments);
|
||||
const { owner, repo, issue_number, ...options } = args;
|
||||
const issue = await updateIssue(owner, repo, issue_number, options);
|
||||
return { toolResult: issue };
|
||||
}
|
||||
|
||||
case "add_issue_comment": {
|
||||
const args = IssueCommentSchema.parse(request.params.arguments);
|
||||
const { owner, repo, issue_number, body } = args;
|
||||
const comment = await addIssueComment(owner, repo, issue_number, body);
|
||||
return { toolResult: comment };
|
||||
}
|
||||
|
||||
default:
|
||||
throw new Error(`Unknown tool: ${request.params.name}`);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user