# Directory Structure ``` ├── package.json ├── README.md ├── src │ └── index.ts └── tsconfig.json ``` # Files -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- ```markdown # GitHub Integration The GitHub MCP server provides functionality to extract diffs from Pull Requests. ## Available Tools ### get_diff_pr Retrieves the diff content from a GitHub Pull Request. **Parameters**: - `owner`: Repository owner/organization name - `repo`: Repository name - `pr_number`: Pull Request number **Returns**: Object containing: - `content`: String containing the PR diff ## Authentication **Required**: Set the GitHub Personal Access Token as an environment variable: ```bash export GITHUB_TOKEN=<your-github-token> ``` The token needs at least `repo` scope permissions to access private repositories. For public repositories, a token with `public_repo` scope is sufficient. ## Error Handling The server implements standard error handling: - Missing/invalid token returns `ErrorCode.AuthenticationError` - Invalid repository details return `ErrorCode.InvalidParams` - Non-existent PR returns `ErrorCode.NotFound` - Failed diff fetches return formatted error messages - Graceful shutdown on SIGINT ## Technical Details - Built using the Highlight AI MCP SDK - Uses GitHub REST API v3 - Input validation via Zod - Runs as a stdio-based MCP server - Supports Node.js >=18.0.0 ## Limitations - Rate limits apply based on GitHub API restrictions - Large diffs may be truncated according to GitHub API limits - Token requires appropriate repository access permissions ``` -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- ```json { "compilerOptions": { "target": "ES2022", // "module": "Node16", // "moduleResolution": "Node16", "strict": true, "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true, "resolveJsonModule": true, "outDir": ".", "rootDir": ".", "moduleResolution": "Node", "module": "CommonJS" }, "include": [ "**/*.ts" ], "exclude": [ "node_modules" ] } ``` -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- ```json { "name": "github-mcp-server", "version": "0.0.1", "type": "module", "scripts": { "build": "tsc", "test": "jest", "start": "node dist/index.js" }, "dependencies": { "@highlight-ai/mcp-sdk": "^0.0.7", "@octokit/rest": "^21.1.0", "zod-to-json-schema": "^3.23.5" }, "devDependencies": { "@types/jest": "^29.5.11", "@types/node": "^20.10.5", "jest": "^29.7.0", "ts-jest": "^29.1.1", "typescript": "^5.3.3" } } ``` -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- ```typescript #!/usr/bin/env node import { Server } from '@highlight-ai/mcp-sdk/server/index.js' import { StdioServerTransport } from '@highlight-ai/mcp-sdk/server/stdio.js' import { ListToolsRequestSchema, GetAuthTokenRequestSchema, CallToolRequestSchema, ErrorCode, McpError, } from '@highlight-ai/mcp-sdk/types.js' import { z } from 'zod' import { Octokit } from '@octokit/rest' async function getPRDiff(owner: string, repo: string, pullNumber: number, token: string): Promise<string> { const octokit = new Octokit({ auth: token, }) const response = await octokit.pulls.get({ owner, repo, pull_number: pullNumber, mediaType: { format: 'diff', }, }) return response.data as unknown as string } class GithubServer { private server: Server private githubToken: string constructor() { const token = process.env.GITHUB_TOKEN if (!token) { throw new Error('GITHUB_TOKEN environment variable is required') } this.githubToken = token this.server = new Server( { name: 'github-server', version: '0.0.1', }, { capabilities: { resources: {}, tools: {}, }, }, ) this.setupHandlers() this.setupErrorHandling() } private setupErrorHandling(): void { this.server.onerror = (error) => { console.error('[MCP Error]', error) } process.on('SIGINT', async () => { await this.server.close() process.exit(0) }) } private setupHandlers(): void { this.setupToolHandlers() } private setupToolHandlers(): void { // List available tools this.server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: [ { name: 'get_pr_diff', description: 'Get the diff of a pull request', inputSchema: { type: 'object', properties: { owner: { type: 'string', description: 'The owner of the repository', }, repo: { type: 'string', description: 'The repository name', }, pullNumber: { type: 'number', description: 'The pull request number', }, }, required: ['owner', 'repo', 'pullNumber'], }, }, ], })) // Handle tool calls this.server.setRequestHandler(CallToolRequestSchema, async (request) => { if (request.params.name !== 'get_pr_diff') { throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${request.params.name}`) } const pullRequestParamsSchema = z.object({ owner: z.string(), repo: z.string(), pullNumber: z.number(), }) const parsedParams = pullRequestParamsSchema.safeParse(request.params.arguments) if (!parsedParams.success) { throw new Error('Invalid arguments') } const diff = await getPRDiff( parsedParams.data.owner, parsedParams.data.repo, parsedParams.data.pullNumber, this.githubToken ) return { content: [ { type: 'text', text: diff, }, ], } }) } async run(): Promise<void> { const transport = new StdioServerTransport() await this.server.connect(transport) console.log('Github MCP server running on stdio') } } const server = new GithubServer() server.run().catch(console.error) ```