Skip to main content
Glama

GitHub Enterprise MCP Server

server.ts40 kB
import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { CallToolRequestSchema, ListToolsRequestSchema, McpError, ErrorCode, } from '@modelcontextprotocol/sdk/types.js'; import { validateEnvVariables } from './utils/error-handling.js'; import { safeJsonParse } from './utils/error-handling.js'; // Import all tools import { searchRepositories, createRepository, updateRepository, deleteRepository, createBranch, listCommits, listWorkflows, listWorkflowRuns, triggerWorkflow, } from './tools/repository.js'; import { createOrUpdateFile, pushFiles, getFileContents, forkRepository, getPullRequestFiles, } from './tools/files.js'; import { listIssues, getIssue, createIssue, updateIssue, addIssueComment, searchIssues as searchIssuesAndPRs, } from './tools/issues.js'; import { listPullRequests, getPullRequest, createPullRequest, createPullRequestReview, mergePullRequest, getPullRequestStatus, updatePullRequestBranch, getPullRequestComments, getPullRequestReviews, } from './tools/pull-requests.js'; import { searchCode, searchIssues, searchUsers, getLicenseInfo, getEnterpriseStats, } from './tools/search.js'; /** * GitHub Enterprise MCP Server */ export class GitHubEnterpriseServer { private server: Server; constructor() { // Validate required environment variables validateEnvVariables(['GITHUB_PERSONAL_ACCESS_TOKEN']); // Create MCP server this.server = new Server( { name: 'github-enterprise', version: '1.0.0', }, { capabilities: { tools: {}, }, } ); // Set up request handlers this.setupRequestHandlers(); // Set up error handler this.server.onerror = (error) => { console.error('[GitHub Enterprise MCP Server Error]', error); }; } /** * Set up request handlers for the MCP server */ private setupRequestHandlers(): void { // List available tools this.server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: [ // Repository tools { name: 'search-repositories', description: 'Search for GitHub repositories', inputSchema: { type: 'object', properties: { query: { type: 'string', description: 'Search query (see GitHub search syntax)', }, page: { type: 'number', description: 'Page number for pagination (default: 1)', }, perPage: { type: 'number', description: 'Number of results per page (default: 30, max: 100)', }, }, required: ['query'], additionalProperties: false, }, }, { name: 'create-repository', description: 'Create a new GitHub repository in your account', inputSchema: { type: 'object', properties: { name: { type: 'string', description: 'Repository name', }, description: { type: 'string', description: 'Repository description', }, private: { type: 'boolean', description: 'Whether the repository should be private', }, autoInit: { type: 'boolean', description: 'Initialize with README.md', }, }, required: ['name'], additionalProperties: false, }, }, { name: 'update-repository', description: 'Update an existing GitHub repository', inputSchema: { type: 'object', properties: { owner: { type: 'string', description: 'Repository owner', }, repo: { type: 'string', description: 'Repository name', }, description: { type: 'string', description: 'New description', }, private: { type: 'boolean', description: 'Change privacy setting', }, default_branch: { type: 'string', description: 'Change default branch', }, has_issues: { type: 'boolean', description: 'Enable/disable issues', }, has_projects: { type: 'boolean', description: 'Enable/disable projects', }, has_wiki: { type: 'boolean', description: 'Enable/disable wiki', }, archived: { type: 'boolean', description: 'Archive/unarchive repository', }, }, required: ['owner', 'repo'], additionalProperties: false, }, }, { name: 'delete-repository', description: 'Delete a GitHub repository', inputSchema: { type: 'object', properties: { owner: { type: 'string', description: 'Repository owner', }, repo: { type: 'string', description: 'Repository name', }, confirm: { type: 'boolean', description: 'Confirmation for deletion (must be true)', }, }, required: ['owner', 'repo', 'confirm'], additionalProperties: false, }, }, { name: 'create-branch', description: 'Create a new branch in a GitHub repository', inputSchema: { type: 'object', properties: { owner: { type: 'string', description: 'Repository owner', }, repo: { type: 'string', description: 'Repository name', }, branch: { type: 'string', description: 'Name for the new branch', }, from_branch: { type: 'string', description: 'Source branch to create from (defaults to the repository\'s default branch)', }, }, required: ['owner', 'repo', 'branch'], additionalProperties: false, }, }, { name: 'list-commits', description: 'Get list of commits of a branch in a GitHub repository', inputSchema: { type: 'object', properties: { owner: { type: 'string', }, repo: { type: 'string', }, sha: { type: 'string', }, page: { type: 'number', }, perPage: { type: 'number', }, }, required: ['owner', 'repo'], additionalProperties: false, }, }, { name: 'list-workflows', description: 'List workflows in a GitHub repository', inputSchema: { type: 'object', properties: { owner: { type: 'string', description: 'Repository owner', }, repo: { type: 'string', description: 'Repository name', }, page: { type: 'integer', description: 'Page number', }, perPage: { type: 'integer', description: 'Items per page', }, }, required: ['owner', 'repo'], additionalProperties: false, }, }, { name: 'list-workflow-runs', description: 'List workflow runs in a GitHub repository', inputSchema: { type: 'object', properties: { owner: { type: 'string', description: 'Repository owner', }, repo: { type: 'string', description: 'Repository name', }, workflow_id: { type: ['string', 'number'], description: 'Workflow ID or file name', }, branch: { type: 'string', description: 'Filter by branch name', }, status: { type: 'string', enum: [ 'completed', 'action_required', 'cancelled', 'failure', 'neutral', 'skipped', 'stale', 'success', 'timed_out', 'in_progress', 'queued', 'requested', 'waiting', ], description: 'Filter by run status', }, page: { type: 'integer', description: 'Page number', }, perPage: { type: 'integer', description: 'Items per page', }, }, required: ['owner', 'repo'], additionalProperties: false, }, }, { name: 'trigger-workflow', description: 'Trigger a workflow run in a GitHub repository', inputSchema: { type: 'object', properties: { owner: { type: 'string', description: 'Repository owner', }, repo: { type: 'string', description: 'Repository name', }, workflow_id: { type: ['string', 'number'], description: 'Workflow ID or file name', }, ref: { type: 'string', description: 'Git reference (branch, tag, SHA)', }, inputs: { type: 'object', description: 'Workflow inputs', }, }, required: ['owner', 'repo', 'workflow_id', 'ref'], additionalProperties: false, }, }, // File operations tools { name: 'create-or-update-file', description: 'Create or update a single file in a GitHub repository', inputSchema: { type: 'object', properties: { owner: { type: 'string', description: 'Repository owner (username or organization)', }, repo: { type: 'string', description: 'Repository name', }, path: { type: 'string', description: 'Path where to create/update the file', }, content: { type: 'string', description: 'Content of the file', }, message: { type: 'string', description: 'Commit message', }, branch: { type: 'string', description: 'Branch to create/update the file in', }, sha: { type: 'string', description: 'SHA of the file being replaced (required when updating existing files)', }, }, required: ['owner', 'repo', 'path', 'content', 'message', 'branch'], additionalProperties: false, }, }, { name: 'push-files', description: 'Push multiple files to a GitHub repository in a single commit', inputSchema: { type: 'object', properties: { owner: { type: 'string', description: 'Repository owner (username or organization)', }, repo: { type: 'string', description: 'Repository name', }, branch: { type: 'string', description: 'Branch to push to (e.g., \'main\' or \'master\')', }, files: { type: 'array', items: { type: 'object', properties: { path: { type: 'string', }, content: { type: 'string', }, }, required: ['path', 'content'], additionalProperties: false, }, description: 'Array of files to push', }, message: { type: 'string', description: 'Commit message', }, }, required: ['owner', 'repo', 'branch', 'files', 'message'], additionalProperties: false, }, }, { name: 'get-file-contents', description: 'Get the contents of a file or directory from a GitHub repository', inputSchema: { type: 'object', properties: { owner: { type: 'string', description: 'Repository owner (username or organization)', }, repo: { type: 'string', description: 'Repository name', }, path: { type: 'string', description: 'Path to the file or directory', }, branch: { type: 'string', description: 'Branch to get contents from', }, }, required: ['owner', 'repo', 'path'], additionalProperties: false, }, }, { name: 'fork-repository', description: 'Fork a GitHub repository to your account or specified organization', inputSchema: { type: 'object', properties: { owner: { type: 'string', description: 'Repository owner (username or organization)', }, repo: { type: 'string', description: 'Repository name', }, organization: { type: 'string', description: 'Optional: organization to fork to (defaults to your personal account)', }, }, required: ['owner', 'repo'], additionalProperties: false, }, }, // Issue tools { name: 'list-issues', description: 'List and filter repository issues', inputSchema: { type: 'object', properties: { owner: { type: 'string', }, repo: { type: 'string', }, state: { type: 'string', enum: ['open', 'closed', 'all'], }, labels: { type: 'array', items: { type: 'string', }, }, sort: { type: 'string', enum: ['created', 'updated', 'comments'], }, direction: { type: 'string', enum: ['asc', 'desc'], }, since: { type: 'string', }, page: { type: 'number', }, per_page: { type: 'number', }, }, required: ['owner', 'repo'], additionalProperties: false, }, }, { name: 'get-issue', description: 'Get details of a specific issue in a GitHub repository.', inputSchema: { type: 'object', properties: { owner: { type: 'string', }, repo: { type: 'string', }, issue_number: { type: 'number', }, }, required: ['owner', 'repo', 'issue_number'], additionalProperties: false, }, }, { name: 'create-issue', description: 'Create a new issue in a GitHub repository', inputSchema: { type: 'object', properties: { owner: { type: 'string', }, repo: { type: 'string', }, title: { type: 'string', }, body: { type: 'string', }, assignees: { type: 'array', items: { type: 'string', }, }, milestone: { type: 'number', }, labels: { type: 'array', items: { type: 'string', }, }, }, required: ['owner', 'repo', 'title'], additionalProperties: false, }, }, { name: 'update-issue', description: 'Update an existing issue in a GitHub repository', inputSchema: { type: 'object', properties: { owner: { type: 'string', }, repo: { type: 'string', }, issue_number: { type: 'number', }, title: { type: 'string', }, body: { type: 'string', }, assignees: { type: 'array', items: { type: 'string', }, }, milestone: { type: 'number', }, labels: { type: 'array', items: { type: 'string', }, }, state: { type: 'string', enum: ['open', 'closed'], }, }, required: ['owner', 'repo', 'issue_number'], additionalProperties: false, }, }, { name: 'add-issue-comment', description: 'Add a comment to an existing issue', inputSchema: { type: 'object', properties: { owner: { type: 'string', }, repo: { type: 'string', }, issue_number: { type: 'number', }, body: { type: 'string', }, }, required: ['owner', 'repo', 'issue_number', 'body'], additionalProperties: false, }, }, // Pull request tools { name: 'list-pull-requests', description: 'List and filter repository pull requests', 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: 'State of the pull requests to return', }, head: { type: 'string', description: 'Filter by head user or head organization and branch name', }, base: { type: 'string', description: 'Filter by base branch name', }, sort: { type: 'string', enum: ['created', 'updated', 'popularity', 'long-running'], description: 'What to sort results by', }, direction: { type: 'string', enum: ['asc', 'desc'], description: 'The direction of the sort', }, per_page: { type: 'number', description: 'Results per page (max 100)', }, page: { type: 'number', description: 'Page number of the results', }, }, required: ['owner', 'repo'], additionalProperties: false, }, }, { name: 'get-pull-request', description: 'Get details of a specific pull request', inputSchema: { type: 'object', properties: { owner: { type: 'string', description: 'Repository owner (username or organization)', }, repo: { type: 'string', description: 'Repository name', }, pull_number: { type: 'number', description: 'Pull request number', }, }, required: ['owner', 'repo', 'pull_number'], additionalProperties: false, }, }, { name: 'create-pull-request', description: 'Create a new pull request 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: 'Pull request title', }, body: { type: 'string', description: 'Pull request body/description', }, head: { type: 'string', description: 'The name of the branch where your changes are implemented', }, base: { type: 'string', description: 'The name of the branch you want the changes pulled into', }, draft: { type: 'boolean', description: 'Whether to create the pull request as a draft', }, maintainer_can_modify: { type: 'boolean', description: 'Whether maintainers can modify the pull request', }, }, required: ['owner', 'repo', 'title', 'head', 'base'], additionalProperties: false, }, }, { name: 'create-pull-request-review', description: 'Create a review on a pull request', inputSchema: { type: 'object', properties: { owner: { type: 'string', description: 'Repository owner (username or organization)', }, repo: { type: 'string', description: 'Repository name', }, pull_number: { type: 'number', description: 'Pull request number', }, commit_id: { type: 'string', description: 'The SHA of the commit that needs a review', }, body: { type: 'string', description: 'The body text of the review', }, event: { type: 'string', enum: ['APPROVE', 'REQUEST_CHANGES', 'COMMENT'], description: 'The review action to perform', }, comments: { type: 'array', items: { type: 'object', properties: { path: { type: 'string', description: 'The relative path to the file being commented on', }, position: { type: 'number', description: 'The position in the diff where you want to add a review comment', }, body: { type: 'string', description: 'Text of the review comment', }, }, required: ['path', 'position', 'body'], additionalProperties: false, }, description: 'Comments to post as part of the review', }, }, required: ['owner', 'repo', 'pull_number', 'body', 'event'], additionalProperties: false, }, }, { name: 'merge-pull-request', description: 'Merge a pull request', inputSchema: { type: 'object', properties: { owner: { type: 'string', description: 'Repository owner (username or organization)', }, repo: { type: 'string', description: 'Repository name', }, pull_number: { type: 'number', description: 'Pull request number', }, commit_title: { type: 'string', description: 'Title for the automatic commit message', }, commit_message: { type: 'string', description: 'Extra detail to append to automatic commit message', }, merge_method: { type: 'string', enum: ['merge', 'squash', 'rebase'], description: 'Merge method to use', }, }, required: ['owner', 'repo', 'pull_number'], additionalProperties: false, }, }, { name: 'get-pull-request-files', description: 'Get the list of files changed in a pull request', inputSchema: { type: 'object', properties: { owner: { type: 'string', description: 'Repository owner (username or organization)', }, repo: { type: 'string', description: 'Repository name', }, pull_number: { type: 'number', description: 'Pull request number', }, }, required: ['owner', 'repo', 'pull_number'], additionalProperties: false, }, }, { name: 'get-pull-request-status', description: 'Get the combined status of all status checks for a pull request', inputSchema: { type: 'object', properties: { owner: { type: 'string', description: 'Repository owner (username or organization)', }, repo: { type: 'string', description: 'Repository name', }, pull_number: { type: 'number', description: 'Pull request number', }, }, required: ['owner', 'repo', 'pull_number'], additionalProperties: false, }, }, { name: 'update-pull-request-branch', description: 'Update a pull request branch with the latest changes from the base branch', inputSchema: { type: 'object', properties: { owner: { type: 'string', description: 'Repository owner (username or organization)', }, repo: { type: 'string', description: 'Repository name', }, pull_number: { type: 'number', description: 'Pull request number', }, expected_head_sha: { type: 'string', description: 'The expected SHA of the pull request\'s HEAD ref', }, }, required: ['owner', 'repo', 'pull_number'], additionalProperties: false, }, }, { name: 'get-pull-request-comments', description: 'Get the review comments on a pull request', inputSchema: { type: 'object', properties: { owner: { type: 'string', description: 'Repository owner (username or organization)', }, repo: { type: 'string', description: 'Repository name', }, pull_number: { type: 'number', description: 'Pull request number', }, }, required: ['owner', 'repo', 'pull_number'], additionalProperties: false, }, }, { name: 'get-pull-request-reviews', description: 'Get the reviews on a pull request', inputSchema: { type: 'object', properties: { owner: { type: 'string', description: 'Repository owner (username or organization)', }, repo: { type: 'string', description: 'Repository name', }, pull_number: { type: 'number', description: 'Pull request number', }, }, required: ['owner', 'repo', 'pull_number'], additionalProperties: false, }, }, // Search tools { name: 'search-code', description: 'Search for code across GitHub repositories', inputSchema: { type: 'object', properties: { q: { type: 'string', }, order: { type: 'string', enum: ['asc', 'desc'], }, page: { type: 'number', minimum: 1, }, per_page: { type: 'number', minimum: 1, maximum: 100, }, }, required: ['q'], additionalProperties: false, }, }, { name: 'search-issues', description: 'Search for issues and pull requests across GitHub repositories', inputSchema: { type: 'object', properties: { q: { type: 'string', }, order: { type: 'string', enum: ['asc', 'desc'], }, page: { type: 'number', minimum: 1, }, per_page: { type: 'number', minimum: 1, maximum: 100, }, sort: { type: 'string', enum: [ 'comments', 'reactions', 'reactions-+1', 'reactions--1', 'reactions-smile', 'reactions-thinking_face', 'reactions-heart', 'reactions-tada', 'interactions', 'created', 'updated', ], }, }, required: ['q'], additionalProperties: false, }, }, { name: 'search-users', description: 'Search for users on GitHub', inputSchema: { type: 'object', properties: { q: { type: 'string', }, order: { type: 'string', enum: ['asc', 'desc'], }, page: { type: 'number', minimum: 1, }, per_page: { type: 'number', minimum: 1, maximum: 100, }, sort: { type: 'string', enum: ['followers', 'repositories', 'joined'], }, }, required: ['q'], additionalProperties: false, }, }, { name: 'get-license-info', description: 'Get information about commonly used licenses on GitHub', inputSchema: { type: 'object', properties: {}, additionalProperties: false, }, }, { name: 'get-enterprise-stats', description: 'Get GitHub Enterprise statistics (only available for GitHub Enterprise)', inputSchema: { type: 'object', properties: {}, additionalProperties: false, }, }, ], })); // Handle tool calls this.server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; let parsedArgs; try { // Parse arguments if they are provided as a string if (typeof args === 'string') { parsedArgs = safeJsonParse(args); } else { parsedArgs = args; } // Call the appropriate tool let result; switch (name) { // Repository tools case 'search-repositories': result = await searchRepositories(parsedArgs); break; case 'create-repository': result = await createRepository(parsedArgs); break; case 'update-repository': result = await updateRepository(parsedArgs); break; case 'delete-repository': result = await deleteRepository(parsedArgs); break; case 'create-branch': result = await createBranch(parsedArgs); break; case 'list-commits': result = await listCommits(parsedArgs); break; case 'list-workflows': result = await listWorkflows(parsedArgs); break; case 'list-workflow-runs': result = await listWorkflowRuns(parsedArgs); break; case 'trigger-workflow': result = await triggerWorkflow(parsedArgs); break; // File operations tools case 'create-or-update-file': result = await createOrUpdateFile(parsedArgs); break; case 'push-files': result = await pushFiles(parsedArgs); break; case 'get-file-contents': result = await getFileContents(parsedArgs); break; case 'fork-repository': result = await forkRepository(parsedArgs); break; case 'get-pull-request-files': result = await getPullRequestFiles(parsedArgs); break; // Issue tools case 'list-issues': result = await listIssues(parsedArgs); break; case 'get-issue': result = await getIssue(parsedArgs); break; case 'create-issue': result = await createIssue(parsedArgs); break; case 'update-issue': result = await updateIssue(parsedArgs); break; case 'add-issue-comment': result = await addIssueComment(parsedArgs); break; // Pull request tools case 'list-pull-requests': result = await listPullRequests(parsedArgs); break; case 'get-pull-request': result = await getPullRequest(parsedArgs); break; case 'create-pull-request': result = await createPullRequest(parsedArgs); break; case 'create-pull-request-review': result = await createPullRequestReview(parsedArgs); break; case 'merge-pull-request': result = await mergePullRequest(parsedArgs); break; case 'get-pull-request-status': result = await getPullRequestStatus(parsedArgs); break; case 'update-pull-request-branch': result = await updatePullRequestBranch(parsedArgs); break; case 'get-pull-request-comments': result = await getPullRequestComments(parsedArgs); break; case 'get-pull-request-reviews': result = await getPullRequestReviews(parsedArgs); break; // Search tools case 'search-code': result = await searchCode(parsedArgs); break; case 'search-issues': result = await searchIssues(parsedArgs); break; case 'search-users': result = await searchUsers(parsedArgs); break; case 'get-license-info': result = await getLicenseInfo(); break; case 'get-enterprise-stats': result = await getEnterpriseStats(); break; default: throw new McpError( ErrorCode.MethodNotFound, `Unknown tool: ${name}` ); } return { content: [ { type: 'text', text: JSON.stringify(result, null, 2), }, ], }; } catch (error: any) { // Handle errors if (error instanceof McpError) { throw error; } // Convert other errors to MCP errors throw new McpError( ErrorCode.InternalError, `Error executing tool ${name}: ${error.message}` ); } }); } /** * Start the MCP server */ async run(): Promise<void> { try { const transport = new StdioServerTransport(); await this.server.connect(transport); console.error('GitHub Enterprise MCP server running on stdio'); // Handle process termination process.on('SIGINT', async () => { await this.server.close(); process.exit(0); }); } catch (error: any) { console.error('Failed to start GitHub Enterprise MCP server:', error); process.exit(1); } } }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/piyushgIITian/github-enterprice-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server