github.getUserRepoStats
Retrieve comprehensive GitHub repository statistics for a user within a specified time frame, including PR activity, comments, reviews, and code changes in a single API call.
Instructions
Get comprehensive repository statistics for a user within a time frame. Aggregates all activity metrics in a single call: PRs authored (with state breakdown: merged/open/closed), comments (total with review/issue breakdown), PR reviews (total with state breakdown: approved/changesRequested/commented, plus unique PRs reviewed), and code changes (files changed, additions, deletions, net change). This is the most efficient tool for getting a complete overview of user activity in a repository. Combines data from multiple sources internally.
Example use cases:
Get complete activity overview for performance reviews
Generate comprehensive developer metrics reports
Compare user activity across different repositories
Track overall contribution metrics in a single call
Returns: Object with stats containing username, repo, timeRange, prs (count, merged, open, closed), comments (total, review, issue), reviews (total, totalPRsReviewed, approved, changesRequested, commented), codeChanges (filesChanged, additions, deletions, netChange)
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| username | Yes | GitHub username (case-insensitive, @ prefix optional). Examples: "octocat", "@octocat" | |
| repo | Yes | Repository in owner/repo format. Required - statistics will be calculated only for this repository. Example: "owner/repo" | |
| from | Yes | Start timestamp in ISO 8601 format. Example: "2024-01-01T00:00:00Z" | |
| to | Yes | End timestamp in ISO 8601 format. Example: "2024-12-31T23:59:59Z" |
Implementation Reference
- src/mcp/tools.ts:1037-1123 (handler)Core handler implementation in GitHubTools class. Aggregates stats by calling other tools (getAuthoredPRs, getUserComments, getPRReviews) and computes PR states, comment types, review states, and code changes.async getUserRepoStats( username: string, repos: string[], from?: string, to?: string ): Promise<{ stats: UserRepoStats }> { const { normalizedUsername, normalizedRepos, from: validatedFrom, to: validatedTo } = this.validateCommonParameters(username, repos, from, to); try { // Log progress to stderr (server logs) console.error(`[getUserRepoStats] Starting for user: ${normalizedUsername}, repos: ${normalizedRepos.join(', ')}`); // 1. Get authored PRs for all repos console.error(`[getUserRepoStats] Step 1/3: Fetching authored PRs...`); const { prs } = await this.getAuthoredPRs(normalizedUsername, normalizedRepos, validatedFrom, validatedTo); console.error(`[getUserRepoStats] Found ${prs.length} authored PRs`); // 2. Get all comments for all repos console.error(`[getUserRepoStats] Step 2/3: Fetching comments (this may take a while for large repos)...`); const { comments } = await this.getUserComments(normalizedUsername, normalizedRepos, validatedFrom, validatedTo); console.error(`[getUserRepoStats] Found ${comments.length} comments`); // 3. Get PR reviews (already filtered by repos) console.error(`[getUserRepoStats] Step 3/3: Fetching PR reviews...`); const { reviews } = await this.getPRReviews(normalizedUsername, normalizedRepos, validatedFrom, validatedTo); console.error(`[getUserRepoStats] Found ${reviews.length} reviews`); // 4. Aggregate PR statistics const prStats = { count: prs.length, merged: prs.filter(pr => pr.state === 'MERGED').length, open: prs.filter(pr => pr.state === 'OPEN').length, closed: prs.filter(pr => pr.state === 'CLOSED').length, }; // 5. Aggregate comment statistics const commentStats = { total: comments.length, review: comments.filter(c => c.commentType === 'review').length, issue: comments.filter(c => c.commentType === 'issue').length, }; // 6. Aggregate review statistics // Count unique PRs reviewed (a user can review the same PR multiple times) const uniquePRsReviewed = new Set(reviews.map(r => r.prId)).size; const reviewStats = { total: reviews.length, totalPRsReviewed: uniquePRsReviewed, approved: reviews.filter(r => r.state === 'APPROVED').length, changesRequested: reviews.filter(r => r.state === 'CHANGES_REQUESTED').length, commented: reviews.filter(r => r.state === 'COMMENTED').length, }; // 7. Aggregate code change statistics const codeStats = { filesChanged: prs.reduce((sum, pr) => sum + pr.filesChanged, 0), additions: prs.reduce((sum, pr) => sum + pr.additions, 0), deletions: prs.reduce((sum, pr) => sum + pr.deletions, 0), netChange: prs.reduce((sum, pr) => sum + pr.additions - pr.deletions, 0), }; // For stats, use first repo as primary (or combine if needed) // Note: stats are aggregated across all provided repos const stats: UserRepoStats = { username: normalizedUsername, repo: normalizedRepos.length === 1 ? normalizedRepos[0] : normalizedRepos.join(', '), timeRange: { from: validatedFrom, to: validatedTo, }, prs: prStats, comments: commentStats, reviews: reviewStats, codeChanges: codeStats, }; console.error(`[getUserRepoStats] Completed successfully`); return { stats }; } catch (error: any) { console.error(`[getUserRepoStats] Error: ${error.message}`); if (error.stack) { console.error(`[getUserRepoStats] Stack: ${error.stack}`); } throw error; } }
- src/mcp/server.ts:146-161 (registration)MCP server switch case dispatcher that handles the tool call by delegating to tools.getUserRepoStats and formats the response.case 'github.getUserRepoStats': { const result = await tools.getUserRepoStats( args.username as string, args.repos as string[], args.from as string | undefined, args.to as string | undefined ); return { content: [ { type: 'text', text: JSON.stringify(result, null, 2), }, ], }; }
- src/mcp/tools.ts:1325-1361 (schema)Tool schema definition including name, description, inputSchema with parameters (username, repo, from, to), used by listTools handler.name: 'github.getUserRepoStats', description: `Get comprehensive repository statistics for a user within a time frame. Aggregates all activity metrics in a single call: PRs authored (with state breakdown: merged/open/closed), comments (total with review/issue breakdown), PR reviews (total with state breakdown: approved/changesRequested/commented, plus unique PRs reviewed), and code changes (files changed, additions, deletions, net change). This is the most efficient tool for getting a complete overview of user activity in a repository. Combines data from multiple sources internally. Example use cases: - Get complete activity overview for performance reviews - Generate comprehensive developer metrics reports - Compare user activity across different repositories - Track overall contribution metrics in a single call Returns: Object with stats containing username, repo, timeRange, prs (count, merged, open, closed), comments (total, review, issue), reviews (total, totalPRsReviewed, approved, changesRequested, commented), codeChanges (filesChanged, additions, deletions, netChange)`, inputSchema: { type: 'object', properties: { username: { type: 'string', description: 'GitHub username (case-insensitive, @ prefix optional). Examples: "octocat", "@octocat"', examples: ['octocat', '@octocat'], }, repo: { type: 'string', description: 'Repository in owner/repo format. Required - statistics will be calculated only for this repository. Example: "owner/repo"', examples: ['owner/repo', 'radireddy/AiApps'], }, from: { type: 'string', description: 'Start timestamp in ISO 8601 format. Example: "2024-01-01T00:00:00Z"', examples: ['2024-01-01T00:00:00Z'], }, to: { type: 'string', description: 'End timestamp in ISO 8601 format. Example: "2024-12-31T23:59:59Z"', examples: ['2024-12-31T23:59:59Z'], }, }, required: ['username', 'repo', 'from', 'to'], }, },
- src/mcp/server.ts:43-47 (registration)Registers the listTools endpoint which returns all tool definitions including github.getUserRepoStats schema via getToolDefinitions().server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: getToolDefinitions(), }; });
- src/mcp/tools.ts:165-181 (helper)Shared validation helper used by getUserRepoStats for input parameters (username, repos, time range).private validateCommonParameters( username: string, repos: string[], from?: string, to?: string ): { normalizedUsername: string; normalizedRepos: string[]; from: string; to: string } { const normalizedUsername = this.validateUsernameParameter(username); const normalizedRepos = this.validateReposParameter(repos); const timeRange = this.validateTimeRangeParameters(from, to); return { normalizedUsername, normalizedRepos, from: timeRange.from, to: timeRange.to }; }