feat: add get_issue endpoint to retrieve single issue details

Adds functionality to fetch details of a specific GitHub issue by number.
This includes:
- New GetIssueSchema for input validation
- Implementation of getIssue function using GitHub API
- Addition of get_issue tool to available tools list
- Handler for get_issue in CallToolRequestSchema

This allows users to retrieve complete issue information including:
- Issue metadata (title, body, state)
- Associated data (labels, assignees, milestone)
- Timestamps (created, updated, closed)
This commit is contained in:
Aschent89 2024-12-06 14:03:12 -05:00
commit 6d7a8f2267
2 changed files with 45 additions and 0 deletions

View file

@ -20,6 +20,7 @@ import {
CreateRepositorySchema, CreateRepositorySchema,
ForkRepositorySchema, ForkRepositorySchema,
GetFileContentsSchema, GetFileContentsSchema,
GetIssueSchema,
GitHubCommitSchema, GitHubCommitSchema,
GitHubContentSchema, GitHubContentSchema,
GitHubCreateUpdateFileResponseSchema, GitHubCreateUpdateFileResponseSchema,
@ -691,6 +692,29 @@ async function searchUsers(
return SearchUsersResponseSchema.parse(await response.json()); return SearchUsersResponseSchema.parse(await response.json());
} }
async function getIssue(
owner: string,
repo: string,
issueNumber: number
): Promise<GitHubIssue> {
const response = await fetch(
`https://api.github.com/repos/${owner}/${repo}/issues/${issueNumber}`,
{
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 GitHubIssueSchema.parse(await response.json());
}
server.setRequestHandler(ListToolsRequestSchema, async () => { server.setRequestHandler(ListToolsRequestSchema, async () => {
return { return {
tools: [ tools: [
@ -778,6 +802,11 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
description: "Search for users on GitHub", description: "Search for users on GitHub",
inputSchema: zodToJsonSchema(SearchUsersSchema), inputSchema: zodToJsonSchema(SearchUsersSchema),
}, },
{
name: "get_issue",
description: "Get details of a specific issue in a GitHub repository.",
inputSchema: zodToJsonSchema(GetIssueSchema)
}
], ],
}; };
}); });
@ -972,6 +1001,16 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
return { content: [{ type: "text", text: JSON.stringify(results, null, 2) }] }; return { content: [{ type: "text", text: JSON.stringify(results, null, 2) }] };
} }
case "get_issue": {
const args = z.object({
owner: z.string(),
repo: z.string(),
issue_number: z.number()
}).parse(request.params.arguments);
const issue = await getIssue(args.owner, args.repo, args.issue_number);
return { toolResult: issue };
}
default: default:
throw new Error(`Unknown tool: ${request.params.name}`); throw new Error(`Unknown tool: ${request.params.name}`);
} }

View file

@ -677,6 +677,12 @@ export const IssueCommentSchema = z.object({
body: z.string() body: z.string()
}); });
export const GetIssueSchema = z.object({
owner: z.string().describe("Repository owner (username or organization)"),
repo: z.string().describe("Repository name"),
issue_number: z.number().describe("Issue number")
});
// Export types // Export types
export type GitHubAuthor = z.infer<typeof GitHubAuthorSchema>; export type GitHubAuthor = z.infer<typeof GitHubAuthorSchema>;
export type GitHubFork = z.infer<typeof GitHubForkSchema>; export type GitHubFork = z.infer<typeof GitHubForkSchema>;