Skip to main content
Glama
ManaswiniGupta

RepoImpact MCP Server

README.md
# RepoImpact

A lightweight repository intelligence engine that uses structural code analysis โ€” not embeddings โ€” to determine change impact and execution workflows in Python codebases, exposed through MCP.


### Streamlit App

[๐Ÿš€ Try the Live Streamlit App](https://manaswinigupta-repoimpact--mcp-tool-for-re-repoimpactapp-41rlpy.streamlit.app/)

<p align="center">
  <img src="./streamlit.png" alt="RepoImpact Streamlit Demo" width="600">
</p>

# Demo

<!-- <p align="center">
  <img src="./demo.gif" alt="RepoImpact Demo" width="600">
</p> -->

[โ–ถ Watch Full Demo](./demo2.mp4)
<!-- <p align="center">
  <img src="./demo.gif" alt="RepoImpact Demo" width="600">
</p> -->


## The problem

Large repositories are hard for LLMs to understand efficiently.

The conventional approach is generic RAG:

```
chunk โ†’ embed โ†’ vector search โ†’ LLM
```

RepoImpact instead does:

```
AST โ†’ symbols โ†’ relationships โ†’ dependency graph โ†’ impact analysis โ†’ compact LLM context
```

Structural questions โ€” "who calls this?", "what breaks if I change it?", "which tests cover it?" โ€” can be answered deterministically from a call graph. They don't need semantic embeddings, and embeddings can't reliably answer them anyway (a vector index can tell you two functions are *similar*; it can't tell you one *calls* the other).

No embeddings. No vector database. No agent framework. AST + SQLite + graph traversal + MCP.

## Install

```
pip install -e .[dev]
```

Requires Python 3.11+ and the `git` executable on PATH (for cloning GitHub repositories).

## Usage

### Analyze a repository

```python
from repoimpact.repository import open_repository

session = open_repository("https://github.com/owner/repo")
# or: open_repository("/path/to/local/repo")
```

This clones (if needed), parses every `.py` file, resolves call relationships, and builds a SQLite index at `data/repositories/<repo-id>/repo.db`.

### MCP server

```
python -m repoimpact.mcp_server <github-url-or-local-path>
```

or set `REPOIMPACT_REPOSITORY` and run with no arguments. Exposes five tools: `search_code`, `find_symbol`, `analyze_impact`, `trace_workflow`, `explain`.

### LLM synthesis (optional)

`explain()` always performs deterministic analysis first โ€” resolving the question to a symbol, then computing impact and workflow via `impact.py`/`graph.py`/`workflow.py`. Set `GEMINI_API_KEY` to also get a natural-language answer (via Gemini 2.5 Flash) grounded in that evidence:

```
export GEMINI_API_KEY=your-key-here
```

The LLM is never given repository source or asked to decide what the facts are โ€” it only turns the already-computed symbol/impact/workflow bundle into prose (see `repoimpact/llm.py`). Without a key set, `explain()` and the Chat tab both still work, just showing the structured evidence directly instead of a prose answer. Swapping providers means adding a new `LLMProvider` subclass, not touching any other module.

### Web UI

```
streamlit run repoimpact/app.py
```

Enter a GitHub URL or local path, then use the Overview / Chat / Search / Impact tabs. The UI calls the same core engine as the MCP server โ€” no separate logic.

### Tests

```
pytest
```

## Demo

The examples above run against [`examples/demo_repo`](examples/demo_repo), a small, deterministic Flask-style app: `POST /login` flows through `login_endpoint โ†’ login โ†’ validate_user/create_token`, and `POST /checkout` flows through `checkout_endpoint โ†’ checkout โ†’ process_payment`. Point either the MCP server or the UI at it locally to reproduce every example below exactly โ€” `tests/test_demo_repo.py` pins these results so they can't silently drift from what's advertised here.

**Where is authentication implemented?**

```
search_code("login")
```
finds `login()` in `auth.py`, `login_endpoint()` in `routes.py`, and `test_login_success()` in `tests/test_auth.py`.

**Explain the login workflow.**

```
POST /login
    โ†“
login_endpoint()
    โ†“
login()
    โ”œโ”€โ”€ create_token()
    โ””โ”€โ”€ validate_user()
            โ””โ”€โ”€ UserRepository.get_user()
```

**Who calls `create_token()`?**

```
find_symbol("create_token")
โ†’ callers: login(), test_login_success()
```

**What breaks if I remove `create_token()`?**

```
analyze_impact("create_token")

Impact: HIGH

Direct callers:      login, test_login_success
Indirect callers:     login_endpoint, test_login_invalid_password
Affected files:       auth.py, routes.py, tests/test_auth.py
Affected workflows:   POST /login
API entry points:     POST /login

Reason: The target has 4 downstream callers, including a detected
public API entry point and 2 related tests.
```

**Which tests are affected?**

`test_login_success` and `test_login_invalid_password` โ€” both reach `create_token()` (directly and via `login()`, respectively).

## What makes this different

```
LLM โ†’ MCP โ†’ structured repository intelligence โ†’ AST + dependency graph โ†’ SQLite
```

The LLM is the interface. The graph is the intelligence.

RepoImpact does **not**: embed every file, build a vector database, chunk the whole repository, upload code to a third-party indexing service, or preload the entire repository into an LLM's context. It **does**: parse with Python's `ast`, resolve calls through a fixed, bounded resolution order (same-module โ†’ `self.method()` โ†’ imports โ†’ simple instance assignment โ†’ qualified module โ†’ unique-name fallback โ€” see `plan.md` ยง15), store the result in one SQLite file per repository, and hand the LLM a few hundred tokens of pre-computed structural context instead of raw source.

## Symbol resolution & confidence

Every resolved call carries a confidence level, because a wrong graph edge is worse than a missing one:

- **HIGH** โ€” same-module call, `self.method()`, resolved import, or a direct `x = ClassName()` instance assignment.
- **LOW** โ€” resolved only via a unique-name fallback (exactly one symbol in the whole repo has that name, but nothing connects the call site to it โ€” no import, no scope).
- **UNRESOLVED** โ€” the name is ambiguous (multiple candidates) or unrelated to anything in the repo (e.g. an external library call). No edge is created.

`analyze_impact`'s HIGH/MEDIUM/LOW score counts only HIGH-confidence callers. LOW-confidence matches are surfaced separately as "possible references" and never silently inflate the score.

## Limitations

This is static analysis, not a type checker or a runtime tracer. It cannot perfectly understand:

- dynamic imports, monkey-patching, or reflection
- runtime-generated attributes or dependency injection
- dynamic dispatch or complex metaprogramming
- an instance whose type is only knowable from another module (e.g. a module-level singleton imported and called through, rather than instantiated locally โ€” the resolver only tracks direct `x = ClassName()` assignments in the same file, not types inferred across a `from module import instance` import)

Impact results are **static-analysis estimates, not guaranteed production-breakage predictions**. The `LOW`/`MEDIUM`/`HIGH` impact score is a heuristic based on downstream caller count, entry-point exposure, and workflow count โ€” not a machine-learning prediction, not a probability.

`explain()`'s natural-language synthesis step (Gemini 2.5 Flash) only ever sees the compact structured evidence already computed by `impact.py`/`graph.py`/`workflow.py` โ€” never repository source, and it never decides what the facts are. Without `GEMINI_API_KEY` set, `explain()` still works, returning that same structured evidence without a prose "answer" field.

## Project structure

```
repoimpact/
โ”œโ”€โ”€ repository.py     # GitHub/local-path input, cloning, session setup
โ”œโ”€โ”€ parser.py         # AST extraction + reference resolution
โ”œโ”€โ”€ models.py         # dataclasses โ€” no ORM
โ”œโ”€โ”€ storage.py        # SQLite schema + transactional reindex
โ”œโ”€โ”€ graph.py          # call graph traversal (callers/callees, transitive)
โ”œโ”€โ”€ search.py         # lexical/structural search, find_symbol
โ”œโ”€โ”€ impact.py         # change-impact analysis (the flagship feature)
โ”œโ”€โ”€ workflow.py        # execution-flow tracing from entry points
โ”œโ”€โ”€ llm.py             # LLMProvider abstraction + Gemini implementation
โ”œโ”€โ”€ mcp_server.py      # the 5 MCP tools
โ””โ”€โ”€ app.py             # Streamlit UI

examples/demo_repo/    # small, deterministic demo app used above
tests/                 # pytest suite (99 tests)
plan.md                # the full design specification this was built from
```