Skip to main content
Glama
radireddy

GitHub MCP Server

by radireddy
README.md
# GitHub MCP Server

A production-ready MCP (Model Context Protocol) server that exposes employee-centric GitHub activity APIs for AI agents and agent orchestration systems. This server abstracts GitHub REST & GraphQL APIs and provides semantic endpoints for analyzing developer contributions, code reviews, and impact over time ranges.

## 🎯 For AI Agents & Agent Orchestration

**Quick Start for Agents**: See [AGENT_GUIDE.md](./AGENT_GUIDE.md) for comprehensive agent-focused documentation, use cases, and examples.

**Recommended Tool for Quick Overview**: Use `github.getUserRepoStats` to get comprehensive metrics in a single call (PRs, comments, reviews, code changes).

**Tool Discovery**: All tools include detailed descriptions, examples, and use cases in their schemas for easy agent discovery.

## Features

- **Pull Request Analysis**: Fetch PRs authored by employees with detailed metadata
- **Review Tracking**: Get PR reviews with states (APPROVED, CHANGES_REQUESTED, COMMENTED)
- **Comment Analysis**: Extract inline and general review comments with file/line context
- **User Comments**: Fetch all comments (review and issue) by a user for a repository within a time range
- **Repository Statistics**: Get comprehensive stats (PRs, comments, reviews, code changes) for a user in a repository
- **Impact Assessment**: Analyze whether review comments led to code changes
- **Code Statistics**: Get detailed diff metadata and code stats for PRs

## Architecture

```
/src
  /mcp
    server.ts        # MCP server registration
    tools.ts         # Tool definitions and handlers
  /github
    client.ts        # GraphQL client with auth
    queries.ts       # GraphQL query definitions
    mapper.ts        # Normalize GitHub → MCP DTOs
  /utils
    pagination.ts    # Cursor-based pagination
    time.ts          # ISO 8601 timestamp handling
    rateLimit.ts     # Rate limit management
```

## Prerequisites

- Node.js 20+
- GitHub Personal Access Token with appropriate permissions:
  - `repo` (REQUIRED for private repos)
  - `read:org` (REQUIRED for organization repositories)
  - `read:user` (for user data)

### For Private Organization Repositories

If you're querying private organization repositories (e.g., `radireddy/AiApps`), ensure:

1. **Token has both scopes**: `repo` AND `read:org`
2. **Account membership**: Your account must be a member of the organization
3. **Organization settings**: Organization must allow third-party access (if using OAuth)
4. **Repository access**: You must have at least read access to the repository

To verify your token has access, run:
```bash
npm run check-token radireddy/AiApps
```

## Installation

```bash
npm install
npm run build
```

## Configuration

### Option 1: Using .env file (Recommended)

1. Copy the example file:
   ```bash
   cp .env.example .env
   ```

2. Edit `.env` and add your GitHub token:
   ```bash
   GITHUB_TOKEN=ghp_your_token_here
   ```

The `.env` file is automatically loaded and is excluded from git (already in `.gitignore`).

### Option 2: Environment Variable

```bash
export GITHUB_TOKEN=ghp_your_token_here
```

**Note:** The `.env` file approach is recommended as it keeps your token local and secure.

## Usage

### MCP Configuration

Add to your MCP client configuration (`mcp.json`):

```json
{
  "mcpServers": {
    "github": {
      "command": "node",
      "args": ["dist/mcp/server.js"],
      "env": {
        "GITHUB_TOKEN": "${GITHUB_TOKEN}"
      }
    }
  }
}
```

### Running the Server

```bash
npm start
```

The server communicates via stdio, so it should be launched by your MCP client.

## MCP Tools

### 1. `github.getAuthoredPRs`

Fetch all PRs authored by a user in a time range.

**Input:**
```json
{
  "username": "octocat",
  "repos": ["owner/repo1", "owner/repo2"],
  "from": "2024-01-01T00:00:00Z",
  "to": "2024-12-31T23:59:59Z"
}
```

**Note:** `from` and `to` are optional. If omitted, defaults to last 3 months. `repos` is required (at least one repository).

**Output:**
```json
{
  "prs": [
    {
      "id": "PR_kwDO...",
      "repo": "owner/repo",
      "title": "Fix bug in authentication",
      "createdAt": "2024-06-15T10:30:00Z",
      "mergedAt": "2024-06-16T14:20:00Z",
      "state": "MERGED",
      "filesChanged": 5,
      "additions": 120,
      "deletions": 45
    }
  ]
}
```

### 2. `github.getPRReviews`

Fetch PR reviews submitted by the employee. Filters by repository.

**Input:**
```json
{
  "username": "octocat",
  "repos": ["owner/repo"],
  "from": "2024-01-01T00:00:00Z",
  "to": "2024-12-31T23:59:59Z"
}
```

**Note:** `from` and `to` are optional. If omitted, defaults to last 3 months. `repos` is required (at least one repository).

**Output:**
```json
{
  "reviews": [
    {
      "id": "PRR_kwDO...",
      "state": "APPROVED",
      "prId": "PR_kwDO...",
      "prNumber": 123,
      "prTitle": "Add feature X",
      "prRepo": "owner/repo",
      "submittedAt": "2024-06-20T09:15:00Z"
    }
  ]
}
```

### 3. `github.getReviewComments`

Fetch inline and general review comments. Returns structured JSON with PR-level grouping, totals, and date range. Filters by repository.

**Input:**
```json
{
  "username": "octocat",
  "repos": ["owner/repo"],
  "from": "2024-01-01T00:00:00Z",
  "to": "2024-12-31T23:59:59Z"
}
```

**Note:** `from` and `to` are optional. If omitted, defaults to last 3 months. `repos` is required (at least one repository).

**Note:** The `repos` parameter is required (at least one repository). Only comments on PRs in the specified repositories will be included. `from` and `to` are optional (defaults to last 3 months if omitted).

**Output:**
```json
{
  "userId": "octocat",
  "dateRange": {
    "from": "2024-01-01T00:00:00Z",
    "to": "2024-12-31T23:59:59Z"
  },
  "totalPRsReviewed": 5,
  "totalComments": 12,
  "prs": [
    {
      "prId": "PR_kwDO...",
      "prNumber": 123,
      "prTitle": "Add feature X",
      "prRepo": "owner/repo",
      "prUrl": "https://github.com/owner/repo/pull/123",
      "prCreatedAt": "2024-06-15T10:30:00Z",
      "comments": [
        "Consider using a constant here",
        "This looks good!"
      ],
      "totalComments": 2
    },
    {
      "prId": "PR_kwDO...",
      "prNumber": 124,
      "prTitle": "Fix bug Y",
      "prRepo": "owner/repo",
      "prUrl": "https://github.com/owner/repo/pull/124",
      "prCreatedAt": "2024-06-20T14:20:00Z",
      "comments": [
        "Maybe we should add error handling here"
      ],
      "totalComments": 1
    }
  ]
}
```

**Note:** All comment bodies are properly JSON-escaped to handle newlines (`\n`), quotes, and other special characters. The response is 100% valid JSON format.

### 4. `github.getCommentImpact`

Analyze whether review comments resulted in code changes. Filters by repository.

**Input:**
```json
{
  "username": "octocat",
  "repos": ["owner/repo"],
  "from": "2024-01-01T00:00:00Z",
  "to": "2024-12-31T23:59:59Z"
}
```

**Note:** `from` and `to` are optional. If omitted, defaults to last 3 months. `repos` is required (at least one repository).

**Output:**
```json
{
  "impacts": [
    {
      "commentId": "PRRC_kwDO...",
      "prId": "PR_kwDO...",
      "hadImpact": true,
      "confidence": 0.7,
      "evidence": [
        "Commit abc1234 modified files after comment (3 files)"
      ]
    }
  ],
  "stats": {
    "totalComments": 25,
    "totalPRsReviewed": 10,
    "totalImpacts": 8
  }
}
```

**Note:** 
- Only comments with actual impact (commits found after comment) are included in the `impacts` array
- The `stats` object is only included if data is available (i.e., if comments were analyzed)
- Statistics are calculated from existing data without additional API calls

### 5. `github.getUserComments`

Fetch all comments (review comments and issue comments) added by a user for a given repository within a time duration. This tool combines PR review comments and PR issue comments, filters by `comment.createdAt` and author, normalizes the results, and deduplicates them.

**Input:**
```json
{
  "username": "octocat",
  "repos": ["owner/repo"],
  "from": "2024-01-01T00:00:00Z",
  "to": "2024-12-31T23:59:59Z"
}
```

**Note:** `from` and `to` are optional. If omitted, defaults to last 3 months. `repos` is required (at least one repository).

**Output:**
```json
{
  "comments": [
    {
      "id": "PRRC_kwDO...",
      "body": "Consider using a constant here",
      "createdAt": "2024-06-20T09:15:00Z",
      "author": "octocat",
      "prId": "PR_kwDO...",
      "prNumber": 123,
      "prTitle": "Add feature X",
      "prRepo": "owner/repo",
      "commentType": "review",
      "filePath": "src/utils/helper.ts",
      "lineNumber": 42,
      "reviewId": "PRR_kwDO..."
    },
    {
      "id": "IC_kwDO...",
      "body": "Great work! This looks good to me.",
      "createdAt": "2024-06-21T14:30:00Z",
      "author": "octocat",
      "prId": "PR_kwDO...",
      "prNumber": 123,
      "prTitle": "Add feature X",
      "prRepo": "owner/repo",
      "commentType": "issue",
      "filePath": null,
      "lineNumber": null,
      "reviewId": null
    }
  ]
}
```

**Note:** This tool uses GitHub GraphQL APIs directly and filters by `comment.createdAt` client-side for accurate time-based filtering. It combines both review comments (inline comments from PR reviews) and issue comments (general comments on PRs), normalizes them into a unified format, and deduplicates by comment ID.

### 6. `github.getUserRepoStats`

Get comprehensive repository statistics for a user within a time frame. Aggregates all activity metrics including PRs, comments, reviews, and code changes.

**Input:**
```json
{
  "username": "octocat",
  "repos": ["owner/repo"],
  "from": "2024-01-01T00:00:00Z",
  "to": "2024-12-31T23:59:59Z"
}
```

**Note:** `from` and `to` are optional. If omitted, defaults to last 3 months. `repos` is required (at least one repository).

**Output:**
```json
{
  "stats": {
    "username": "octocat",
    "repo": "owner/repo",
    "timeRange": {
      "from": "2024-01-01T00:00:00Z",
      "to": "2024-12-31T23:59:59Z"
    },
    "prs": {
      "count": 15,
      "merged": 12,
      "open": 2,
      "closed": 1
    },
    "comments": {
      "total": 45,
      "review": 30,
      "issue": 15
    },
    "reviews": {
      "total": 20,
      "totalPRsReviewed": 15,
      "approved": 12,
      "changesRequested": 5,
      "commented": 3
    },
    "codeChanges": {
      "filesChanged": 120,
      "additions": 3500,
      "deletions": 800,
      "netChange": 2700
    }
  }
}
```

**Note:** This tool combines data from multiple sources (`getAuthoredPRs`, `getUserComments`, `getPRReviews`) to provide a complete overview of user activity in a repository. All statistics are filtered by the specified time range and repository.

**Important:** When comparing with `github.getReviewComments`:
- `getUserRepoStats.comments.total` includes both review comments AND issue comments, while `getReviewComments.totalComments` includes only review comments
- `getUserRepoStats.comments.review` should match `getReviewComments.totalComments` when both are filtered by the same repository
- `getUserRepoStats.reviews.totalPRsReviewed` counts unique PRs reviewed, while `getUserRepoStats.reviews.total` counts total review submissions (a user can review the same PR multiple times)

## Agent Orchestration

This MCP server is designed for use by AI agents and agent orchestration systems. All tools include:
- **Detailed descriptions** with use cases and examples
- **Parameter examples** in tool schemas
- **Consistent response formats** for easy parsing
- **Automatic filtering** of auto-generated content
- **Error handling** with clear error messages

### Quick Reference for Agents

| Tool | Best For | Returns |
|------|----------|---------|
| `github.getUserRepoStats` | **Quick overview** - Single call for all metrics | Complete stats (PRs, comments, reviews, code changes) |
| `github.getAuthoredPRs` | PR analysis | Array of PRs with metadata |
| `github.getPRReviews` | Review participation | Array of reviews with states |
| `github.getReviewComments` | Comment analysis | Grouped comments by PR |
| `github.getCommentImpact` | Review effectiveness | Impact assessments with confidence scores |
| `github.getUserComments` | All comments | Combined review + issue comments |

**See [AGENT_GUIDE.md](./AGENT_GUIDE.md) for comprehensive agent documentation, workflows, and best practices.**

**See [agent-examples.json](./agent-examples.json) for real-world agent usage examples and workflows.**

## Example Agent Call

Here's an example of how an AI agent might use this MCP server:

```typescript
// Agent workflow for collecting data for employee performance analysis

// 1. Get all PRs authored by employee in Q1 2024
const prs = await mcp.callTool('github.getAuthoredPRs', {
  username: 'johndoe',
  repos: ['company/main-repo'],
  from: '2024-01-01T00:00:00Z',
  to: '2024-03-31T23:59:59Z'
});

// 2. Get PR reviews to assess code review participation
const reviews = await mcp.callTool('github.getPRReviews', {
  username: 'johndoe',
  repos: ['company/main-repo'],
  from: '2024-01-01T00:00:00Z',
  to: '2024-03-31T23:59:59Z'
});

// 3. Analyze review comment impact
const impacts = await mcp.callTool('github.getCommentImpact', {
  username: 'johndoe',
  repos: ['company/main-repo'],
  from: '2024-01-01T00:00:00Z',
  to: '2024-03-31T23:59:59Z'
});

// 4. Get all comments by employee for a specific repository
const comments = await mcp.callTool('github.getUserComments', {
  username: 'johndoe',
  repos: ['company/important-repo'],
  from: '2024-01-01T00:00:00Z',
  to: '2024-03-31T23:59:59Z'
});

// 6. Get comprehensive repository statistics
const repoStats = await mcp.callTool('github.getUserRepoStats', {
  username: 'johndoe',
  repos: ['company/important-repo'],
  from: '2024-01-01T00:00:00Z',
  to: '2024-03-31T23:59:59Z'
});
// Returns aggregated stats: PRs, comments, reviews, code changes
```

## Design Decisions

### GraphQL over REST
- More efficient for nested data (reviews, comments, files)
- Single request for complex queries
- Better type safety

### Cursor-based Pagination
- Handles large datasets efficiently
- No duplicate results
- Predictable performance

### Normalized DTOs
- Consistent data structure for agents
- Hides GitHub API complexity
- Easy to extend

### Rate Limit Handling
- Automatic detection and waiting
- Request ID logging for debugging
- Graceful error messages

### Case-Insensitive Usernames
- User-friendly (handles @ prefix, case variations)
- Normalizes to lowercase for consistency

## Error Handling

The server handles:
- **Authentication errors**: Clear messages about GITHUB_TOKEN
- **Rate limits**: Automatic waiting and informative errors
- **Invalid timestamps**: Validation with helpful error messages
- **Missing data**: Graceful defaults (null, empty arrays)

## Extensibility

The architecture supports easy extension:

1. **New Tools**: Add to `tools.ts` and register in `server.ts`
2. **New Queries**: Add GraphQL queries to `queries.ts`
3. **New Mappers**: Extend `mapper.ts` with new DTOs
4. **Caching**: Add caching layer in `client.ts` (extension point)

## Development

```bash
# Build
npm run build

# Watch mode
npm run dev

# Run
npm start
```

## Agent Integration Examples

### Example 1: Performance Review Data Collection

```typescript
// Get comprehensive stats in one call (from/to optional, defaults to last 3 months)
const stats = await mcp.callTool('github.getUserRepoStats', {
  username: 'johndoe',
  repos: ['company/main-repo'],
  from: '2024-01-01T00:00:00Z',
  to: '2024-12-31T23:59:59Z'
});

// Returns: Complete metrics that can be used for performance reviews
```

### Example 2: Code Review Quality Assessment

```typescript
// Step 1: Get review activity
const reviews = await mcp.callTool('github.getPRReviews', {
  username: 'reviewer-name',
  repos: ['company/main-repo'],
  from: '2024-01-01T00:00:00Z',
  to: '2024-12-31T23:59:59Z'
});

// Step 2: Measure review impact
const impact = await mcp.callTool('github.getCommentImpact', {
  username: 'reviewer-name',
  repos: ['company/main-repo'],
  from: '2024-01-01T00:00:00Z',
  to: '2024-12-31T23:59:59Z'
});

// Calculate effectiveness: impact.stats.totalImpacts / impact.stats.totalComments
```

### Example 3: Multi-Repository Analysis

```typescript
// Option 1: Get stats for multiple repos separately
const repos = ['company/repo1', 'company/repo2'];
const results = await Promise.all(
  repos.map(repo => 
    mcp.callTool('github.getUserRepoStats', {
      username: 'developer-name',
      repos: [repo],
      from: '2024-01-01T00:00:00Z',
      to: '2024-12-31T23:59:59Z'
    })
  )
);

// Option 2: Get stats for multiple repos in one call (aggregated)
const aggregatedStats = await mcp.callTool('github.getUserRepoStats', {
  username: 'developer-name',
  repos: ['company/repo1', 'company/repo2'],
  from: '2024-01-01T00:00:00Z',
  to: '2024-12-31T23:59:59Z'
});
```

**For more examples and workflows, see [AGENT_GUIDE.md](./AGENT_GUIDE.md).**

## License

MIT

TDQS

A4.1/5.0

Scored across 6 tools

Disambiguation4/5

Most tools have distinct purposes focused on different aspects of GitHub activity (PRs authored, reviews, comments, stats), but there is some overlap between getCommentImpact and getReviewComments/getUserComments in analyzing comments. The descriptions help clarify differences, but an agent might occasionally confuse which tool to use for comment-related analysis.

Naming Consistency5/5

All tools follow a consistent verb_noun pattern with 'get' as the verb (e.g., getAuthoredPRs, getCommentImpact, getPRReviews). The naming is uniform and predictable, using camelCase throughout without any deviations or mixed conventions.

Tool Count4/5

With 6 tools, the count is reasonable for a GitHub analytics server, but it feels slightly thin for comprehensive coverage. The tools focus on user activity metrics, missing broader operations like repository management or issue handling, which might limit scope. However, each tool serves a clear purpose within this niche.

Completeness3/5

The toolset covers user-centric analytics well (e.g., PRs, reviews, comments, stats), but there are notable gaps for a GitHub server, such as no create, update, or delete operations, and missing tools for repositories, issues, or code search. This limits agents to read-only analysis without full lifecycle coverage.

Maintenance

ActivityInactive
ResponsivenessNo issues