Skip to main content
Glama
devatraj

AI-Code-Reviewer

by devatraj
README.md
# ai-code-reviewer-mcp

An AI code reviewer, shipped as an installable [MCP](https://modelcontextprotocol.io)
server. It reviews a diff/PR against a target repository's own coding conventions —
learned via RAG over that repo's real code, docs, and lint config — rather than a fixed,
generic linter ruleset.

Point it at any repo, ask it to review a diff, and it comes back with findings that cite
the *actual* file:line in that repo the convention came from — not generic advice.

## How it works

```
MCP Host (Claude Code / Cursor / Claude Desktop)
        │  stdio (JSON-RPC over MCP)
        ▼
FastMCP server (Python)
  ├── index_repo / get_index_status   — RAG indexing pipeline
  ├── explain_convention              — one-shot grounded Q&A over the index
  └── review_diff / review_file       — LangGraph multi-step review agent
        │
        ▼
Local state: ~/.ai-code-reviewer-mcp/<repo-hash>/{chroma/, manifest.sqlite}
        │
        ▼ (only the review-generation/critic LLM calls leave the laptop)
Gemini API (gemini-flash-lite-latest, free tier)
```

Retrieval, chunking, and the vector store all run **locally and for free** — chunking
is done with Python's `ast` module at symbol boundaries (one chunk per function/method/
class, not prose-style sliding windows), and embeddings are computed on-device via
[fastembed](https://github.com/qdrant/fastembed) (`sentence-transformers/all-MiniLM-L6-v2`,
ONNX runtime, no GPU/torch needed). Only the review-generation and critic steps call
Gemini's API.

### The review agent (LangGraph)

`review_diff` runs a mostly-linear graph with exactly one bounded conditional loop:

```
parse_diff → retrieve_conventions → generate_hunk_review → critic_selfcheck ─┐
                     ▲                                                       │
                     └──────────── (weak citation, retry-capped at 1) ───────┘
                                                                              │
                                                          aggregate_and_dedup ◄┘
                                                                  │
                                                            format_output
```

- **`generate_hunk_review`** — one structured-output Gemini call per diff hunk. The
  model must cite a `chunk_id` from the retrieved conventions — it can't free-type a
  file:line, which is what prevents hallucinated citations.
- **`critic_selfcheck`** — two independent passes: (a) a **deterministic** check (no
  LLM) that every cited chunk really exists in the retrieved set and that the repo
  hasn't changed since indexing; (b) an **LLM judgment** pass that keeps/downgrades/
  suppresses each finding and can trigger one bounded re-retrieval if the citation looks
  weak.

The graph is kept linear everywhere else on purpose — the parse → retrieve → generate →
critique → aggregate sequence is fully knowable upfront, so a dynamic planner node would
add complexity without payoff. The one retry loop is the actual justification for using
LangGraph over a plain function pipeline here.

## Tools exposed

| Tool | Purpose |
|---|---|
| `index_repo` | (Re)index a local repo's source/docs/lint-config. Incremental — only files whose git blob sha changed are re-embedded. |
| `get_index_status` | Whether a repo is indexed, and whether the index is stale vs. current HEAD. |
| `review_diff` | Review a diff (or `git diff base..head` computed for you) against the repo's own conventions. |
| `review_file` | Whole-file review fallback — same pipeline, file treated as fully added. |
| `explain_convention` | Ask a plain-English question about the repo's conventions, grounded in retrieved chunks. |
| `ping` | Health check. |

## Install

Requires [`uv`](https://docs.astral.sh/uv/) and a free Gemini API key from
[Google AI Studio](https://aistudio.google.com/apikey) (no credit card).

```bash
git clone <this-repo>
cd ai-code-reviewer-mcp
uv sync
```

Create a `.env` file (gitignored) with your key:

```
GEMINI_API_KEY=AIza...
```

### Add to an MCP host

Point your host's MCP config at this directory:

```json
{
  "mcpServers": {
    "ai-code-reviewer": {
      "command": "uv",
      "args": ["--directory", "/absolute/path/to/ai-code-reviewer-mcp", "run", "ai-code-reviewer-mcp"],
      "env": { "GEMINI_API_KEY": "AIza..." }
    }
  }
}
```

(Config file location differs per host — Claude Desktop, Claude Code, and Cursor each
have their own; check that host's current docs.)

## Usage

1. `index_repo(repo_path="/path/to/some/repo")`
2. `review_diff(repo_path="/path/to/some/repo", base_ref="HEAD~1", head_ref="HEAD")` — or
   pass an explicit `diff` string.
3. `explain_convention(repo_path="...", question="how should I raise a custom error here?")`

## Eval results

`uv run python evals/run_eval.py` runs 6 hand-authored fixtures (2 clean, 4 with a
known convention violation) against a small fixture repo, and checks two things:

- **Grounding** — for every finding produced, the cited `(file, line_start, line_end)`
  is verified to really exist in the repo and the cited snippet is checked against the
  real file content. Last run: **5/5 citations verified (100%)** — this is the claim
  that matters most for this product.
- **Directional precision/recall** against the hand-labeled expected findings. Last
  run: **4/6 cases passed** on `gemini-flash-lite-latest` (free tier) — zero false
  positives across all 6 cases, but two recall misses (one of two co-located issues in
  a single hunk, and a print-vs-logging convention). This is a small, honest sanity
  check on a tiny fixture set, not a rigorous benchmark, and it's *not* prompt-tuned
  against its own fixtures — the whole point of the grounding check above is to keep
  that discipline honest.

## Design notes / scope cuts

- **Python-only chunking** via the stdlib `ast` module — deliberate v1 scope cut.
  Multi-language support would mean `tree-sitter`, whose grammar-package compatibility
  churns across versions; not worth the risk for a portfolio-scoped v1.
- **Dense-only retrieval** (Chroma + fastembed) — no BM25/hybrid fusion or reranking
  yet. A complete, legitimate v1 on its own; hybrid search is the first thing to add
  if this project continues.
- **Per-repo index state lives under `~/.ai-code-reviewer-mcp/<hash>/`**, not inside the
  target repo — avoids writing generated vector-store files into someone else's repo.
- **No GitHub API integration** — `review_diff` takes diff text directly or computes it
  from local git refs; no automated PR fetching or webhook bot in v1.
- **Rate-limit aware** — free-tier Gemini keys have real per-minute quotas; LLM calls
  retry with backoff on 429 rather than failing the whole review.

### v2 ideas

GitHub webhook bot that posts review comments automatically; Java support via
tree-sitter; per-repo `.ai-code-reviewer.yml` for severity/category tuning; real hybrid
search + reranking; a standalone trace-visualizer; multi-repo convention-drift
detection; prompt caching for the repeated retrieved-context portion of prompts.

TDQS

A4/5.0

Scored across 6 tools

Disambiguation5/5

Each tool serves a distinct purpose: ping for health, index_repo for indexing, get_index_status for checking indexing state, explain_convention for Q&A on conventions, and review_diff/review_file for reviewing code changes. No two tools overlap in functionality.

Naming Consistency4/5

Most tool names follow a consistent verb_noun pattern (e.g., index_repo, review_diff), but 'ping' deviates as a noun-only name. This minor inconsistency is acceptable.

Tool Count5/5

With 6 tools, the server is well-scoped for its purpose of indexing and reviewing code conventions. Each tool earns its place, covering indexing, status, health, and two review methods.

Completeness4/5

The tool set covers the core workflow (index, check status, review diff/file, explain conventions). Missing a tool to retrieve all conventions or clear the index are minor gaps, but the essential review cycle is complete.

Maintenance

ActivitySlowing
ResponsivenessNo issues