MCP (Model Context Protocol) server that exposes GitHub repository data as tools an AI assistant can call — repo info, issues, pull requests, commit statuses, PR diffs, and recent commits.
Works with any MCP-compatible client (Claude Desktop, Cline, Claude.ai, etc.) both locally (stdio) and as a deployed remote server (Streamable HTTP).
Live server: https://github-analyzer-mcp-keih.onrender.com
MCP endpoint: https://github-analyzer-mcp-keih.onrender.com/mcp
The Model Context Protocol is a standard way for AI applications to discover and call external tools. Instead of writing a custom integration for every AI app, you write one MCP server, and any compatible client can connect to it. This server exposes six read-only tools backed by GitHub's REST API via Octokit.
| Tool | Description |
|---|---|
get_repo_info |
Basic repo metadata — stars, forks, language, open issue count, description |
list_open_issues |
Open issues for a repo (title, author, labels, comment count) |
list_pull_requests |
Pull requests, filterable by state (open / closed / all) |
get_commit_status |
Combined CI/build status for a commit SHA, branch, or tag |
get_pull_request_diff |
Code diff for a specific PR (truncated if very large) |
list_recent_commits |
Recent commits on a branch |
- Node.js + @modelcontextprotocol/sdk — MCP server implementation
- Octokit — GitHub API client
- Zod — input schema validation for tools
- Express — HTTP layer for Streamable HTTP (remote) transport
- Jest — unit testing
- Docker — containerized local/deployable runtime
- GitHub Actions — CI (tests + Docker build verified on every push)
- Render — deployment
github-analyzer-mcp/
├── .github/
│ └── workflows/
│ └── ci.yml # GitHub Actions — runs tests + Docker build on every push
├── src/
│ ├── github/
│ │ └── client.js # Octokit setup + GitHub wrapper functions (MCP-agnostic)
│ │ └── client.test.js # Unit tests for client.js (mocked Octokit, no live API calls)
│ ├── tools/
│ │ └── index.js # createMcpServer() — registers all tools with schemas
│ │ └── index.test.js # Integration tests — real MCP Client/Server over an in-memory transport
│ └── server.js # Entry point — picks stdio or HTTP transport
├── Dockerfile # Container build (HTTP mode)
├── .dockerignore # Excludes node_modules, .env, tests from the image
├── .env # GITHUB_TOKEN (not committed)
├── .gitignore
└── package.json
github/client.js contains plain async functions with no MCP dependency — they can be tested or reused independently of the MCP layer. Each function accepts an optional Octokit client parameter (dependency injection), so tests can pass in a fake client instead of hitting the real GitHub API. tools/index.js wraps those functions with MCP tool schemas and descriptions. server.js wires everything to a transport.
git clone https://github.com/meetvora79/github-analyzer-mcp.git
cd github-analyzer-mcp
npm install- GitHub → Settings → Developer settings → Personal access tokens → Fine-grained tokens
- Generate new token, scope it to specific repos, and grant these permissions (read-only):
- Contents
- Issues
- Pull requests
- Commit statuses
- Metadata (usually auto-selected)
Create a .env file in the project root:
GITHUB_TOKEN=github_pat_xxxxxxxxxxxxxxxxxxxxxx
stdio mode (default — for local MCP clients like Cline or Claude Desktop, which spawn the server as a subprocess):
node src/server.jsHTTP mode (Streamable HTTP — for testing the remote-capable version locally):
# macOS/Linux
MCP_TRANSPORT=http node src/server.js
# Windows PowerShell
$env:MCP_TRANSPORT="http"; node src/server.jsServer listens on http://localhost:3000, with the MCP endpoint at http://localhost:3000/mcp.
npx @modelcontextprotocol/inspector node src/server.jsOpens a local web UI to list and manually call tools without needing a full AI client — useful for verifying a tool works before wiring up a client.
npm testRuns the full Jest suite:
src/github/client.test.js— unit tests for every GitHub-wrapper function (getRepoInfo,listOpenIssues,listPullRequests,getCommitStatus,getPullRequestDiff,listRecentCommits). Each function is tested against a fake Octokit client passed via dependency injection, so tests run instantly with no live GitHub API calls and no rate-limit risk.src/tools/index.test.js— integration tests that spin up a realMcpServerand a real MCPClientconnected over an in-memory transport, then call each registered tool exactly as a real MCP client would. Covers the success path, error handling (isError: trueon a thrown exception), and Zod input-validation rejections for missing/invalid arguments. Because this project uses ES Modules ("type": "module"), Jest runs with Node's experimental VM modules flag — see thetestscript inpackage.jsonif you're curious how that's wired up.
The server can run in a container, using the same HTTP transport as the Render deployment.
Build the image:
docker build -t github-analyzer-mcp .Run it, passing your token in at runtime (never baked into the image — .env is excluded via .dockerignore):
docker run -p 3000:3000 --env-file .env github-analyzer-mcpThe MCP endpoint is then available at http://localhost:3000/mcp.
Anyone who pulls this image gets a working server with no GitHub access until they supply their own token via
-e GITHUB_TOKEN=...or--env-file. Pulling the image never grants access to the maintainer's repos or token — each user brings their own.
Open Cline's MCP settings (MCP Servers icon → Configure → Configure MCP Servers) and add:
{
"mcpServers": {
"github-analyzer": {
"command": "node",
"args": ["/absolute/path/to/github-analyzer-mcp/src/server.js"],
"env": { "GITHUB_TOKEN": "github_pat_xxxxxxxxxxxxxxxxxxxxxx" },
"disabled": false,
"autoApprove": []
},
"github-analyzer-remote": {
"url": "https://github-analyzer-mcp-keih.onrender.com/mcp",
"type": "streamableHttp",
"disabled": false,
"autoApprove": []
}
}
}Edit claude_desktop_config.json (macOS: ~/Library/Application Support/Claude/, Windows: %APPDATA%\Claude\):
{
"mcpServers": {
"github-analyzer": {
"command": "node",
"args": ["/absolute/path/to/github-analyzer-mcp/src/server.js"],
"env": { "GITHUB_TOKEN": "github_pat_xxxxxxxxxxxxxxxxxxxxxx" }
}
}
}Fully restart the client after editing its config — MCP servers are only loaded on startup.
- Push this repo to GitHub.
- Render dashboard → New → Web Service → connect the repo.
- Settings:
- Build command:
npm install - Start command:
node src/server.js
- Build command:
- Environment variables:
GITHUB_TOKEN— your tokenMCP_TRANSPORT—http
- Deploy. Your MCP endpoint will be
https://<your-service>.onrender.com/mcp.
Free-tier Render instances spin down after inactivity — the first request after idle time may take 30–60 seconds while the instance wakes up.
Every push and pull request to main triggers a GitHub Actions workflow (.github/workflows/ci.yml) with two jobs, run in parallel:
test— installs dependencies and runs the full Jest suite (see Testing above).docker-build— runsdocker buildagainst theDockerfileto confirm the image still builds cleanly, catching a broken Dockerfile before it reaches a real deploy. Both must pass for the workflow to go green. See the badge at the top of this README, or the Actions tab for run history.
- stdio — client spawns the server as a local subprocess, communicates over stdin/stdout. No networking; can't be used remotely.
- Streamable HTTP — server runs as a persistent HTTP service; clients connect over a URL. This server runs in stateless mode (a fresh server + transport instance per request) since all tools are independent, read-only lookups with no need for session memory.
- The GitHub token lives server-side only — clients never see it directly.
- This deployment has no auth on the
/mcpendpoint; anyone with the URL can call it against your token's quota. Fine for a learning project, but add authentication before using this with a real/high-limit token. - Large payloads (e.g. PR diffs) are truncated to avoid flooding a model's context window.
Meet Vora
- Email: meetvora877@gmail.com
- LinkedIn: https://linkedin.com/in/meetvora79