GitHub MCP Server

by ualUsham
Verified
import { Octokit } from "octokit"; // Initialize Octokit (will use environment variables for authentication) const octokit = new Octokit({ auth: process.env.GITHUB_TOKEN, }); // Tools for GitHub API export const tools = { "search-repos": { name: "search-repos", description: "Search for GitHub repositories", inputSchema: { type: "object", properties: { query: { type: "string", description: "Search query", }, sort: { type: "string", enum: ["stars", "forks", "help-wanted-issues", "updated"], description: "Sort order", }, limit: { type: "number", description: "Maximum number of results to return", } }, required: ["query"], }, }, "get-repo-info": { name: "get-repo-info", description: "Get information about a specific GitHub repository", inputSchema: { type: "object", properties: { owner: { type: "string", description: "Repository owner (username or organization)", }, repo: { type: "string", description: "Repository name", } }, required: ["owner", "repo"], }, }, "list-issues": { name: "list-issues", description: "List issues in a GitHub repository", inputSchema: { type: "object", properties: { owner: { type: "string", description: "Repository owner (username or organization)", }, repo: { type: "string", description: "Repository name", }, state: { type: "string", enum: ["open", "closed", "all"], description: "Issue state", }, limit: { type: "number", description: "Maximum number of issues to return", } }, required: ["owner", "repo"], }, }, "create-issue": { name: "create-issue", description: "Create a new issue in a GitHub repository", inputSchema: { type: "object", properties: { owner: { type: "string", description: "Repository owner (username or organization)", }, repo: { type: "string", description: "Repository name", }, title: { type: "string", description: "Issue title", }, body: { type: "string", description: "Issue body", }, labels: { type: "array", items: { type: "string" }, description: "Labels to apply to the issue", } }, required: ["owner", "repo", "title", "body"], }, }, }; // Type definitions for tool parameters type SearchReposArgs = { query: string; sort?: "stars" | "forks" | "help-wanted-issues" | "updated"; limit?: number; }; type GetRepoInfoArgs = { owner: string; repo: string; }; type ListIssuesArgs = { owner: string; repo: string; state?: "open" | "closed" | "all"; limit?: number; }; type CreateIssueArgs = { owner: string; repo: string; title: string; body: string; labels?: string[]; }; // Tool handler implementations const searchRepos = async (args: SearchReposArgs) => { const { query, sort = "stars", limit = 5 } = args; try { const response = await octokit.rest.search.repos({ q: query, sort, per_page: limit, }); return { content: [ { type: "text", text: JSON.stringify( response.data.items.map(repo => ({ name: repo.full_name, description: repo.description, stars: repo.stargazers_count, url: repo.html_url, language: repo.language, forks: repo.forks_count, })), null, 2 ), }, ], }; } catch (error) { const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred'; return { content: [ { type: "text", text: `Error searching repositories: ${errorMessage}`, }, ], }; } }; const getRepoInfo = async (args: GetRepoInfoArgs) => { const { owner, repo } = args; try { const response = await octokit.rest.repos.get({ owner, repo, }); return { content: [ { type: "text", text: JSON.stringify( { name: response.data.full_name, description: response.data.description, stars: response.data.stargazers_count, forks: response.data.forks_count, issues: response.data.open_issues_count, language: response.data.language, created_at: response.data.created_at, updated_at: response.data.updated_at, url: response.data.html_url, default_branch: response.data.default_branch, license: response.data.license?.name || "No license", topics: response.data.topics, }, null, 2 ), }, ], }; } catch (error) { const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred'; return { content: [ { type: "text", text: `Error getting repository information: ${errorMessage}`, }, ], }; } }; const listIssues = async (args: ListIssuesArgs) => { const { owner, repo, state = "open", limit = 10 } = args; try { const response = await octokit.rest.issues.listForRepo({ owner, repo, state, per_page: limit, }); return { content: [ { type: "text", text: JSON.stringify( response.data.map(issue => ({ number: issue.number, title: issue.title, state: issue.state, created_at: issue.created_at, updated_at: issue.updated_at, user: issue.user?.login, labels: issue.labels.map(label => typeof label === 'string' ? label : label.name ), url: issue.html_url, comments: issue.comments, })), null, 2 ), }, ], }; } catch (error) { const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred'; return { content: [ { type: "text", text: `Error listing issues: ${errorMessage}`, }, ], }; } }; const createIssue = async (args: CreateIssueArgs) => { const { owner, repo, title, body, labels = [] } = args; try { const response = await octokit.rest.issues.create({ owner, repo, title, body, labels, }); return { content: [ { type: "text", text: JSON.stringify( { number: response.data.number, title: response.data.title, url: response.data.html_url, created_at: response.data.created_at, message: "Issue created successfully", }, null, 2 ), }, ], }; } catch (error) { const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred'; return { content: [ { type: "text", text: `Error creating issue: ${errorMessage}`, }, ], }; } }; // Export tool handlers export const toolHandlers = { "search-repos": searchRepos, "get-repo-info": getRepoInfo, "list-issues": listIssues, "create-issue": createIssue, };