This is a Model Context Protocol (MCP) server that allows a large language model (LLM) like Claude to fetch and format review comments from a GitHub pull request.
⚠️ Security Notice: Please read SECURITY.md for important security considerations, especially regarding agentic workflows and automated implementation of PR comments.
- Prerequisites: Python 3.10+,
uv - Quickstart:
uv add mcp-github-pr-review && mcp-github-pr-review - Full documentation lives in
docs/and is published via MkDocs. Key entry points:
This MCP server supports both GitHub.com and GitHub Enterprise Server (GHES).
GITHUB_TOKEN is required - the server will not start without a valid, non-empty token.
For GitHub.com (default):
GITHUB_TOKEN=ghp_your_token_hereFor GitHub Enterprise Server:
GH_HOST=github.enterprise.com
GITHUB_TOKEN=your_enterprise_tokenThe server automatically constructs API endpoints based on GH_HOST:
REST API: https://{GH_HOST}/api/v3
GraphQL API: https://{GH_HOST}/api/graphql
For non-standard enterprise configurations:
GITHUB_API_URL=https://custom.github.company.com/api
GITHUB_GRAPHQL_URL=https://custom.github.company.com/graphqlThe server accepts PR URLs in this format:
https://{host}/owner/repo/pull/123
Examples:
https://github.com/owner/repo/pull/123(GitHub.com)https://github.enterprise.com/owner/repo/pull/456(GHES)
This project uses Ruff for linting and formatting. All configurations are defined in pyproject.toml.
# Install development dependencies (if not already installed)
uv pip install -e ".[dev]"
# Run linting
ruff check .
# Run linting with auto-fix
ruff check . --fix
# Format code
ruff format .
# Run both linting and formatting
ruff check . --fix && ruff format .Run tests using pytest:
# Run all tests
pytest
# Run tests with verbose output
pytest -v
# Run specific test file
pytest tests/test_integration.py
# Run tests with coverage (install pytest-cov first)
pytest --cov=. --cov-report=htmlThis project uses pre-commit to run formatting, linting, and tests on staged files.
# Install the git hook scripts
uv run --extra dev pre-commit install
# Run all checks on every file
uv run --extra dev pre-commit run --all-filesTo start the MCP server, run the following command in your terminal:
# Using the installed script (after pip install -e .)
mcp-github-pr-review
# With UV
uv run mcp-github-pr-review
# Or use the helper script (uv-first)
./run-server.sh # starts via `uv run`
./run-server.sh --sync # sync deps first
./run-server.sh --log # also write logs/logs/mcp_server.log
./run-server.sh --register # register with Claude CLI as `pr-review`
./run-server.sh --codex # configure Codex CLI to use this server- Interactive config/show config only:
./run-server.sh --config # print instructions for all clients (no changes) - One-shot configure common clients (non-interactive):
./run-server.sh --register --codex --gemini # add --desktop to also configure Claude Desktop
Run these from the repo root so $(pwd) points to this project.
# Minimal (pass env vars if needed)
claude mcp add pr-review -s user -- \
uv run --project "$(pwd)" -- mcp-github-pr-review
# Example with env var (GitHub token)
claude mcp add pr-review -s user -e GITHUB_TOKEN="$GITHUB_TOKEN" -- \
uv run --project "$(pwd)" -- mcp-github-pr-reviewAppend to ~/.codex/config.toml:
[mcp_servers.pr-review]
command = "uv"
args = ["run", "mcp-github-pr-review"]
[mcp_servers.pr-review.env]
# Optional – provide your token here, or rely on your shell environment
# GITHUB_TOKEN = "your_github_token_here"
PATH = "/usr/local/bin:/usr/bin:/bin:/opt/homebrew/bin:$HOME/.local/bin:$HOME/.cargo/bin:$HOME/bin"Tip:
./run-server.sh --codexcan write this for you.
Edit ~/.gemini/settings.json and add:
{
"mcpServers": {
"pr-review": {
"command": "uv",
"args": ["run", "mcp-github-pr-review"]
}
}
}Tip:
./run-server.sh --geminican write this for you.
The server listens over stdio and becomes available to connected MCP clients.
The server exposes the following tools to the LLM:
Fetches all review comments from a given GitHub pull request URL. The tool returns Markdown by default (optimized for human/AI readability), with options to request JSON or both.
-
Parameters:
pr_url(str): The full URL of the pull request (e.g.,"https://github.com/owner/repo/pull/123"). If omitted, the server will attempt to auto-resolve from the current repo/branch.output(str, optional): Output format. One of"markdown"(default),"json", or"both".markdown: returns a single Markdown document rendered from the comments (default).json: returns a single JSON string with the raw comments list.both: returns two messages: first JSON, then Markdown.
per_page(int, optional): GitHub page size (1–100). Defaults from envHTTP_PER_PAGE.max_pages(int, optional): Safety cap on pages. Defaults from envPR_FETCH_MAX_PAGES.max_comments(int, optional): Safety cap on total comments. Defaults from envPR_FETCH_MAX_COMMENTS.max_retries(int, optional): Retry budget for transient errors. Defaults from envHTTP_MAX_RETRIES.
-
Returns:
- When
output="markdown"(default): a single text item containing Markdown. - When
output="json": a single text item containing a JSON string with the raw comments list. - When
output="both": two text items in order — first JSON, then Markdown.
- When
Example (Markdown default):
{
"name": "fetch_pr_review_comments",
"arguments": { "pr_url": "https://github.com/owner/repo/pull/123" }
}Example (JSON output):
{
"name": "fetch_pr_review_comments",
"arguments": { "pr_url": "https://github.com/owner/repo/pull/123", "output": "json" }
}Resolves the open PR URL for the current branch using git detection.
- Parameters:
select_strategy(str, optional): Strategy when auto-resolving a PR (default 'branch'). Options: 'branch', 'latest', 'first', 'error'.owner(str, optional): Override repo owner for PR resolution.repo(str, optional): Override repo name for PR resolution.branch(str, optional): Override branch name for PR resolution.
- Returns:
- The resolved PR URL as a string.
Use least privilege for GITHUB_TOKEN:
- Classic PATs:
- Public repositories:
public_repois sufficient. - Private repositories:
repois required.
- Public repositories:
- Fine-grained PATs:
- Repository access: Select the target repo(s).
- Permissions: Pull requests → Read access (enables reading review comments at
GET /repos/{owner}/{repo}/pulls/{pull_number}/comments).
Avoid granting write or admin scopes unless needed for other tools.
Do not run this application in production using a development server or with debug enabled. If exposing HTTP endpoints, use a production-grade WSGI/ASGI server (e.g., Gunicorn, Uvicorn) and ensure debug is disabled.
These variables can be set in .env (loaded via python-dotenv) or your environment:
GITHUB_TOKEN: GitHub PAT used for API calls. Fine-grained tokens useBearerscheme; classic PATs are automatically retried withtokenscheme on 401.PR_FETCH_MAX_PAGES(default50): Safety cap on pagination pages when fetching comments.PR_FETCH_MAX_COMMENTS(default2000): Safety cap on total collected comments before stopping early.HTTP_PER_PAGE(default100): GitHub APIper_pagevalue (1–100).HTTP_MAX_RETRIES(default3): Max retries for transient request errors and 5xx responses, with backoff + jitter.
For GitHub Enterprise instances, override the API endpoints in your .env:
GITHUB_API_URL=https://custom.github.company.com/api/v3
GITHUB_GRAPHQL_URL=https://custom.github.company.com/api/graphqlThis project uses modern Python tooling for enhanced developer experience:
- uv: Ultra-fast Python package manager and resolver
- Ruff: Extremely fast Python linter and formatter
- pyproject.toml: Modern Python project configuration file
- pytest: Modern testing framework with async support
- Speed: UV is 10-100x faster than pip for dependency resolution
- Reliability: Better dependency resolution and lock file generation
- Code Quality: Ruff provides comprehensive linting and formatting in milliseconds
- Developer Experience: Better IDE integration and faster feedback loops
- Consistency: Standardized configuration in pyproject.toml
For compatibility, the original requirements.txt file is maintained, but the modern workflow using pyproject.toml and UV is recommended for development.
If you're migrating from the old pip-based setup:
# Remove old virtual environment
rm -rf venv
# Install UV
pip install uv
# Install dependencies with UV
uv pip install -e ".[dev]"
# Format and lint your code
ruff format . && ruff check . --fix
# Run tests to ensure everything works
pytest