GitHub Analytics MCP Server
by sweta2503
README.md
# GitHub Analytics MCP Server
A production-grade **Model Context Protocol (MCP) 2.x server** for GitHub analytics.
This project goes beyond a basic MCP tutorial and demonstrates how to build an MCP server with the engineering patterns you actually need for real-world use:
* Async HTTP
* Connection pooling
* Explicit timeouts
* TTL caching
* GitHub rate-limit awareness
* Retry with exponential backoff
* Structured logging
* Input validation
* Parallel API requests
* Clean MCP lifecycle management
* Real end-to-end MCP protocol testing
Built as part of the **Production AI Engineering** series on **Agentic Data Lab**.
š„ **YouTube:** [Agentic Data Lab](https://www.youtube.com/@agenticdatalab)
---
# What Does This MCP Server Do?
The server exposes GitHub repository analytics as MCP tools.
An MCP-compatible AI client can use it to:
* inspect repository metadata
* retrieve recent commits
* analyze contributors
* inspect open issues
* analyze commit activity
* compare two repositories
* inspect GitHub API rate limits
Example:
```text
User:
Compare pallets/flask and django/django.
Which repository looks more active?
```
The AI client can call:
```text
compare_repos
```
and retrieve live GitHub data through this MCP server.
---
# Architecture
```text
āāāāāāāāāāāāāāāāāāāāāāā
ā MCP Client / AI ā
ā Claude / MCP Client ā
āāāāāāāāāāāā¬āāāāāāāāāāā
ā
ā MCP stdio
ā¼
āāāāāāāāāāāāāāāāāāāāāāā
ā GitHub Analytics ā
ā MCP Server ā
āāāāāāāāāāāā¬āāāāāāāāāāā
ā
āāāāāāāāāāā“āāāāāāāāāā
ā ā
ā¼ ā¼
Input Validation TTL Cache
ā
āāāāāāāāāāā“āāāāāāāāāā
ā ā
CACHE HIT CACHE MISS
ā ā
ā ā¼
ā Async HTTP Client
ā ā
ā Retry + Backoff
ā ā
ā ā¼
ā GitHub REST API
ā ā
āāāāāāāāāāāāāāāāāāāāā
ā
ā¼
Structured MCP Result
```
---
# 7 Production Patterns Implemented
## 1. Async HTTP + Connection Pooling
The server uses:
```python
httpx.AsyncClient
```
instead of synchronous HTTP requests.
The HTTP client is created once during the MCP server lifecycle and reused across tool calls.
This provides:
* non-blocking I/O
* connection reuse
* better concurrency
* explicit timeout control
The server configures separate timeouts for:
```python
connect
read
write
pool
```
---
## 2. TTL Caching
AI clients may call the same MCP tool several times during one conversation.
Instead of hitting GitHub every time, the server caches responses in memory.
Example:
```text
First request
MCP Client
ā
ā¼
MCP Server
ā
ā¼
GitHub API
ā
ā¼
Cache
```
Second request:
```text
MCP Client
ā
ā¼
MCP Server
ā
ā¼
CACHE HIT
```
No additional GitHub request is required.
Different tools use different TTLs depending on how quickly their data changes.
| Tool | Cache TTL |
| ----------------------- | ---------: |
| `get_repo_overview` | 5 minutes |
| `list_recent_commits` | 2 minutes |
| `get_contributors` | 10 minutes |
| `list_open_issues` | 2 minutes |
| `get_commit_activity` | 30 minutes |
| `compare_repos` | 5 minutes |
| `get_rate_limit_status` | 30 seconds |
---
## 3. GitHub Rate-Limit Awareness
GitHub exposes rate-limit information through response headers.
The server tracks:
```text
X-RateLimit-Limit
X-RateLimit-Used
X-RateLimit-Remaining
X-RateLimit-Reset
Retry-After
```
The server can detect when GitHub is actually rate limiting requests and return a useful MCP tool error instead of exposing a raw exception.
---
## 4. Retry + Exponential Backoff
Transient network failures and upstream `5xx` responses are retried automatically.
Retry sequence:
```text
Attempt 1
ā
āāā failure
ā
ā¼
wait 1s
Attempt 2
ā
āāā failure
ā
ā¼
wait 2s
Attempt 3
ā
āāā final result
```
The backoff formula is:
```python
2 ** (attempt - 1)
```
The server does not blindly retry normal `4xx` client errors.
---
## 5. Structured Logging
MCP stdio uses `stdout` for protocol communication.
Operational logs are therefore written separately through Python logging.
Example:
```text
2026-08-27T14:14:03 | INFO | Starting GitHub Analytics MCP server
2026-08-27T14:14:04 | INFO | GET /repos/facebook/react ā 200
2026-08-27T14:14:04 | INFO | CACHE HIT /repos/facebook/react
```
This makes it easy to inspect:
* API requests
* HTTP status
* latency
* retry attempts
* cache hits
* validation failures
* rate-limit warnings
---
## 6. Input Validation
Repository owner and repository names are validated before any network request is made.
Valid names may contain:
```text
letters
numbers
.
-
_
```
For example:
```text
face../../book
```
is rejected locally before it can become part of a GitHub API request.
---
## 7. Parallel API Requests
The `compare_repos` MCP tool needs information from two independent repositories.
Instead of fetching them sequentially:
```python
repo_a = await get_repo_a()
repo_b = await get_repo_b()
```
the server runs both requests concurrently:
```python
repo_a, repo_b = await asyncio.gather(
get_repo_a(),
get_repo_b(),
)
```
Conceptually:
```text
Sequential
Repo A āāāāāāāāāāāāāāāāŗ Done
Repo B āāāāāāāāāāāāāāāāŗ Done
Parallel
Repo A āāāāāāāāāāāāāāāāŗ Done
Repo B āāāāāāāāāāāāāāāāāāāāŗ Done
```
This reduces elapsed wait time when requests are independent.
---
# Available MCP Tools
The server currently exposes **7 MCP tools**.
## `get_repo_overview`
Returns:
* stars
* forks
* open issues
* watchers
* language
* topics
* license
* last push date
* homepage
* repository size
Example:
```text
get_repo_overview(
owner="facebook",
repo="react"
)
```
---
## `list_recent_commits`
Returns recent repository commits.
Example:
```text
list_recent_commits(
owner="vuejs",
repo="core",
limit=5
)
```
---
## `get_contributors`
Returns top repository contributors.
Example:
```text
get_contributors(
owner="django",
repo="django",
limit=10
)
```
---
## `list_open_issues`
Returns open GitHub issues while excluding pull requests.
Example:
```text
list_open_issues(
owner="pallets",
repo="flask",
limit=10
)
```
---
## `get_commit_activity`
Returns repository commit activity including:
* total commits
* average commits per week
* peak activity
* recent weekly activity
---
## `compare_repos`
Compares two repositories side by side.
Example:
```text
compare_repos(
owner1="pallets",
repo1="flask",
owner2="django",
repo2="django"
)
```
Returned fields include:
```text
stars
forks
open issues
language
last push
```
---
## `get_rate_limit_status`
Returns GitHub API rate-limit information plus local MCP server counters.
Example:
```json
{
"limit": 60,
"used": 4,
"remaining": 56,
"resets_in_seconds": 3599,
"server_outbound_http_requests": 4,
"server_cache_hits": 1
}
```
Actual values depend on your current GitHub API usage.
---
# Project Structure
```text
mcp-github-analytics/
ā
āāā server.py
ā āāā Main MCP server and GitHub tools
ā
āāā demo_mcp.py
ā āāā Real end-to-end MCP client demo
ā
āāā requirements.txt
ā āāā Python dependencies
ā
āāā .env.example
ā āāā Environment variable template
ā
āāā .gitignore
```
---
# Setup
## 1. Clone the Repository
```bash
git clone https://github.com/sweta2503/mcp-github-analytics.git
```
Move into the project:
```bash
cd mcp-github-analytics
```
---
## 2. Create a Virtual Environment
```bash
python -m venv .venv
```
### macOS / Linux
```bash
source .venv/bin/activate
```
### Windows
```powershell
.venv\Scripts\activate
```
---
## 3. Install Dependencies
```bash
pip install -r requirements.txt
```
The project uses:
```text
mcp[cli]==2.1.1
httpx==0.28.1
python-dotenv==1.2.3
```
---
# GitHub Token Setup
A GitHub token is optional when working only with public repositories, but it is recommended.
Copy the example environment file:
```bash
cp .env.example .env
```
Add your GitHub token:
```env
GITHUB_TOKEN=your_github_token_here
```
Do not commit your real `.env` file or token.
---
# Run the Real MCP Demo
Run:
```bash
python demo_mcp.py
```
This is a real MCP end-to-end test.
`demo_mcp.py` does **not** simply import the functions from `server.py`.
Instead it:
```text
1. Starts server.py as an MCP subprocess
2. Connects using MCP stdio
3. Negotiates the MCP protocol
4. Discovers the MCP tools
5. Calls the tools through MCP
6. Receives structured MCP responses
```
You should see output similar to:
```text
MCP CONNECTED ā discover the real server tools
Negotiated protocol: ...
Tools discovered (7):
get_repo_overview
list_recent_commits
get_contributors
list_open_issues
get_commit_activity
compare_repos
get_rate_limit_status
```
---
# Test the Cache
The demo calls:
```text
get_repo_overview(facebook/react)
```
twice.
The first call hits GitHub.
The second should show:
```text
CACHE HIT
```
and return significantly faster.
---
# Test Parallel Repository Comparison
The demo also runs:
```text
compare_repos(
pallets/flask,
django/django
)
```
Both upstream GitHub requests are fired concurrently through:
```python
asyncio.gather(...)
```
---
# Capture Demo Output and Server Logs
You can capture the MCP client output and server logs separately:
```bash
python demo_mcp.py > demo_output.txt 2> server.log
```
This creates:
```text
demo_output.txt
```
for MCP client responses and:
```text
server.log
```
for server-side logs.
The server log contains useful information such as:
```text
GET /repos/facebook/react ā 200
CACHE HIT /repos/facebook/react
GET /repos/pallets/flask ā 200
GET /repos/django/django ā 200
```
---
# Run the Server Directly
You can start the MCP server itself with:
```bash
python server.py
```
The server runs over MCP stdio.
Normally an MCP-compatible client launches this process automatically.
---
# Connect the Server to Claude Desktop
You do not need to keep a machine-specific `claude_desktop_config.json` inside this repository.
Instead, add the server to your local Claude Desktop configuration.
Example:
```json
{
"mcpServers": {
"github-analytics": {
"command": "/ABSOLUTE/PATH/TO/mcp-github-analytics/.venv/bin/python",
"args": [
"/ABSOLUTE/PATH/TO/mcp-github-analytics/server.py"
],
"env": {
"GITHUB_TOKEN": "YOUR_GITHUB_TOKEN"
}
}
}
}
```
Replace:
```text
/ABSOLUTE/PATH/TO/mcp-github-analytics
```
with the actual project location on your computer.
Never commit your real GitHub token.
After restarting Claude Desktop, the GitHub analytics tools should become available to Claude.
Example prompt:
```text
Compare pallets/flask and django/django.
Which repository appears more active?
Use the GitHub MCP tools and explain which data you used.
```
---
# End-to-End Request Flow
```text
User
ā
ā¼
Claude / MCP Client
ā
ā MCP tool call
ā¼
GitHub Analytics MCP Server
ā
āāā Validate input
ā
āāā Check TTL cache
ā
āāā Cache hit āāāāāāāāāāāāāāāŗ Return result
ā
āāā Cache miss
ā
ā¼
Async HTTP
ā
Retry / Backoff
ā
ā¼
GitHub REST API
ā
ā¼
Response
ā
ā¼
TTL Cache
ā
ā¼
Structured MCP Response
ā
ā¼
AI / MCP Client
```
---
# Local vs Distributed Production MCP
This project intentionally uses an in-memory TTL cache because it is designed as a clear local/stdio MCP example.
For a multi-instance remote MCP deployment, you would typically replace process-local state with infrastructure such as:
```text
Redis
PostgreSQL
distributed rate limiting
centralized observability
authentication
tracing
```
The patterns demonstrated in this repository are the building blocks for that next stage.
---
# Watch the Full Build
I explain the architecture, code, caching, retry logic, validation, parallel requests and real MCP demo on my YouTube channel:
## š„ Agentic Data Lab
**https://www.youtube.com/@agenticdatalab**
On the channel I cover:
* Production AI Engineering
* MCP
* AI Agents
* LangGraph
* RAG
* AI evaluations
* Agent observability
* AI system design
* Data Engineering + AI
* Production benchmarks and experiments
If you're interested in building AI systems that go beyond tutorial demos, consider subscribing.
š **YouTube:** [Agentic Data Lab](https://www.youtube.com/@agenticdatalab)
---
# Contributing
Issues, improvements and pull requests are welcome.
If you extend the MCP server with another useful GitHub analytics tool, feel free to open a PR.
---
# Support the Project
If this repository helped you:
* ā Star the repository
* š“ Fork it and build your own MCP tools
* ā¶ļø Subscribe to [Agentic Data Lab](https://www.youtube.com/@agenticdatalab)
More production AI engineering projects are coming.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues