Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,3 +154,26 @@ cgraph info [--repo <name>] # Repo stats + metadata
```

`--repo` defaults to the current directory name. Claude Code skill in `skills/code-graph/`.

## MCP server (for agents)

`cgraph-mcp` exposes the code graph over MCP stdio. Eight tools:
`index_repo`, `search_code`, `get_callers`, `get_callees`,
`get_dependencies`, `impact_analysis`, `find_path`, `ask`.

Drop the canonical agent guidance into any repo:

```bash
cgraph init-agent # writes CLAUDE.md + .cursorrules
cgraph init-agent --force # overwrite existing files
```

See `api/mcp/templates/claude_mcp_section.md` for the full tool table
and rules of thumb (start with `search_code`; prefer structural tools
over `ask`; run `impact_analysis` before refactoring).

Environment:

- `CODE_GRAPH_AUTO_INDEX=true` — auto-index CWD on MCP startup.
- `CGRAPH_MODE=mcp` — run `cgraph-mcp` instead of the FastAPI web
server when using the Docker image.
58 changes: 58 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,48 @@ npx skills add FalkorDB/code-graph

Then ask Claude things like *"what functions call analyze_sources?"* or *"find the dependency chain between parse_config and send_request"* — it will handle the indexing and querying automatically.

### MCP server (`cgraph-mcp`)

For agents that speak the [Model Context Protocol](https://modelcontextprotocol.io)
(Claude Code, Cursor, Cline, …), code-graph ships a stdio MCP server
that exposes the knowledge graph as 8 first-class tools: `index_repo`,
`search_code`, `get_callers`, `get_callees`, `get_dependencies`,
`impact_analysis`, `find_path`, and `ask` (NL→Cypher via GraphRAG).

Quickstart — Claude Code:

```bash
# 1. Install (in any venv with the cgraph package on PATH)
pip install code-graph # or: uv pip install code-graph

# 2. Register with Claude Code
claude mcp add-json code-graph '{
"command": "cgraph-mcp",
"env": {
"FALKORDB_HOST": "localhost",
"FALKORDB_PORT": "6379",
"CODE_GRAPH_AUTO_INDEX": "true"
}
}'

# 3. Drop agent guidance into your repo
cd /path/to/your/repo
cgraph init-agent # writes CLAUDE.md and .cursorrules
```

Quickstart — Docker Compose:

```bash
docker compose up -d falkordb # start the DB
docker compose --profile mcp run --rm -i code-graph-mcp # attach via stdio
```

The MCP server auto-bootstraps FalkorDB if it's missing on localhost
(via `cgraph ensure-db`). When `CODE_GRAPH_AUTO_INDEX=true` is set,
the current working directory is indexed automatically on start.

**Transport:** Phase 1 is stdio only. HTTP/SSE is deferred.

## Running with Docker

### Using Docker Compose
Expand All @@ -232,18 +274,34 @@ docker compose up --build

This starts FalkorDB and the CodeGraph app together. The checked-in compose file sets `CODE_GRAPH_PUBLIC=1` for the app service.

To run the **MCP stdio server** instead of the web app from the same
image, set `CGRAPH_MODE=mcp` and use the `mcp` profile:

```bash
docker compose --profile mcp run --rm -i code-graph-mcp
```

### Using Docker directly

```bash
docker build -t code-graph .

# Web mode (default)
docker run -p 5000:5000 \
-e FALKORDB_HOST=host.docker.internal \
-e FALKORDB_PORT=6379 \
-e MODEL_NAME=gemini/gemini-flash-lite-latest \
-e GEMINI_API_KEY=<YOUR_GEMINI_API_KEY> \
-e SECRET_TOKEN=<YOUR_SECRET_TOKEN> \
code-graph

# MCP stdio mode (same image)
docker run --rm -i \
-e CGRAPH_MODE=mcp \
-e FALKORDB_HOST=host.docker.internal \
-e FALKORDB_PORT=6379 \
-e MODEL_NAME=gemini/gemini-flash-lite-latest \
code-graph
```

## Creating a Code Graph
Expand Down
42 changes: 42 additions & 0 deletions api/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -413,5 +413,47 @@ def info(
_json_out({"repo": name, "branch": branch, **stats, "metadata": metadata})


# ── init-agent ─────────────────────────────────────────────────────────


_TEMPLATES_DIR = Path(__file__).parent / "mcp" / "templates"


@app.command("init-agent")
def init_agent(
force: bool = typer.Option(
False, "--force", "-f", help="Overwrite existing CLAUDE.md / .cursorrules."
),
) -> None:
"""Drop AI-agent guidance files (CLAUDE.md, .cursorrules) into CWD.

Copies the canonical code-graph MCP guidance bundled with this
package so any repo can announce the tools to Cursor and Claude
Code with one command.
"""
targets = {
"CLAUDE.md": _TEMPLATES_DIR / "claude_mcp_section.md",
".cursorrules": _TEMPLATES_DIR / "cursorrules.template",
}

cwd = Path.cwd()
if not force:
existing = [name for name in targets if (cwd / name).exists()]
if existing:
_json_error(
f"Refusing to overwrite existing files: {', '.join(existing)}. "
"Re-run with --force to clobber."
)

written: List[str] = []
for name, template in targets.items():
dest = cwd / name
dest.write_text(template.read_text(encoding="utf-8"), encoding="utf-8")
written.append(str(dest))
_stderr(f"Wrote {dest}")

_json_out({"status": "ok", "written": written, "force": force})


if __name__ == "__main__":
app()
42 changes: 42 additions & 0 deletions api/mcp/templates/claude_mcp_section.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# code-graph MCP server — agent guidance

This repo is indexed into a FalkorDB **code knowledge graph** exposed
to you over MCP as `code-graph`. Use it instead of grepping when you
need to understand how symbols connect.

## When to call each tool

| Tool | Call this when… | Example |
|---|---|---|
| `index_repo(path_or_url, branch?)` | **First** thing in a new repo; or after large changes outside your edits. Project name is **derived from the folder or repo URL** — read it back from the response. | `index_repo(path_or_url=".")` |
| `search_code(prefix, project)` | You know part of a symbol name and need its id. | `search_code(prefix="processPay", project="myrepo")` |
| `get_callers(symbol_id, project)` | "Who calls this?" — refactoring a function, tracking down a regression. | `get_callers(symbol_id=42, project="myrepo")` |
| `get_callees(symbol_id, project)` | "What does this call?" — understanding a function before editing it. | `get_callees(symbol_id=42, project="myrepo")` |
| `get_dependencies(symbol_id, project)` | All edges out of a symbol (CALLS + IMPORTS + DEFINES). | `get_dependencies(symbol_id=42, project="myrepo")` |
| `impact_analysis(symbol_id, project, direction, depth)` | **"What breaks if I change this?"** Transitive upstream callers. | `impact_analysis(symbol_id=42, project="myrepo", direction="IN", depth=3)` |
| `find_path(source_id, dest_id, project)` | Show the call chain between two known symbols. | `find_path(source_id=10, dest_id=42, project="myrepo")` |
| `ask(question, project)` | Open-ended natural-language question. **More expensive — use last.** | `ask(question="why does login fail when MFA is on?", project="myrepo")` |

## Rules of thumb

1. **Start with `search_code`** to turn names into ids. Most tools take a `symbol_id`.
2. **Prefer structural tools over `ask`.** `get_callers` is one cheap Cypher
hop; `ask` is two LLM round-trips. Use `ask` for fuzzy/conceptual
questions, not for "who calls X".
3. **`impact_analysis` before refactoring.** Even when you think you know
the answer — the transitive closure often surprises you.
4. **`branch` is optional** but pass it when working on a feature branch
so you query the right per-branch index.
5. **Response shape.** Tools that return collections (`search_code`,
`get_callers`, `get_callees`, `get_dependencies`, `find_path`,
`impact_analysis`) put the array in `structuredContent.result` per
the MCP spec. The text content is the same JSON for convenience.
`index_repo` and `ask` return a single object.

## Environment

- `CODE_GRAPH_AUTO_INDEX=true` — auto-index CWD on first tool call (off by
default; opt-in because indexing big repos takes minutes).
- `FALKORDB_HOST` / `FALKORDB_PORT` — defaults to `localhost:6379`. If
unreachable on localhost, the server runs `cgraph ensure-db` to
spin up the official Docker image.
32 changes: 32 additions & 0 deletions api/mcp/templates/cursorrules.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Cursor rules — code-graph MCP

This project is indexed into a FalkorDB code knowledge graph via the
`code-graph` MCP server. Use it instead of grepping when you need to
understand how symbols connect.

## Tool selection

- Symbol lookup by name: use `code-graph.search_code` (gives you the
numeric id every other tool needs).
- "Who calls X?": `code-graph.get_callers`.
- "What does X call?": `code-graph.get_callees`.
- All outgoing edges (CALLS + IMPORTS + DEFINES): `code-graph.get_dependencies`.
- Refactoring impact ("what breaks if I change X"):
`code-graph.impact_analysis` with `direction="IN"`.
- Call chain between two specific symbols: `code-graph.find_path`.
- Natural-language question over the graph (expensive — last resort):
`code-graph.ask`.

## Rules

- Always `search_code` first to resolve names to ids.
- Prefer structural tools (`get_callers`, `find_path`, `impact_analysis`)
over `ask` for "who/what/where" questions.
- Run `impact_analysis(direction="IN", depth=3)` before any non-trivial
refactor.
- Pass `branch` when on a feature branch.

## First run

If the repo isn't indexed yet, call `index_repo(path=".")` once. After
that, navigate via the structural tools.
19 changes: 18 additions & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,21 @@ services:
- FALKORDB_PORT=6379
- OPENAI_API_KEY=${OPENAI_API_KEY:-}
- SECRET_TOKEN=${SECRET_TOKEN:-}
- CODE_GRAPH_PUBLIC=1
- CODE_GRAPH_PUBLIC=1

# MCP stdio server — opt-in. Bring up with:
# docker compose run --rm -i code-graph-mcp
# then point Claude Code / Cursor at the running container's stdio.
code-graph-mcp:
build: .
depends_on:
- falkordb
profiles: ["mcp"]
stdin_open: true
tty: false
environment:
- CGRAPH_MODE=mcp
- FALKORDB_HOST=falkordb
- FALKORDB_PORT=6379
- MODEL_NAME=${MODEL_NAME:-gemini/gemini-flash-lite-latest}
- CODE_GRAPH_AUTO_INDEX=${CODE_GRAPH_AUTO_INDEX:-}
3 changes: 3 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ build-backend = "setuptools.build_meta"
[tool.setuptools.packages.find]
where = ["."]

[tool.setuptools.package-data]
"api.mcp" = ["templates/*"]

[dependency-groups]
dev = [
"pytest>=9.0.2",
Expand Down
Loading