CRAG-MCP
# CRAG-MCP: Config-Aware Code Graph via MCP
程式碼 graph 建構與查詢 MCP Server,支援條件編譯(#ifdef)動態過濾。
每個 workspace 獨立儲存 graph + config,支援多專案比較。
## 核心概念:Config-Aware Graph
```
傳統 Graph:
cfg80211_p2p_init() ──→ cfg80211_get_bss()
(不知道這個 function 需要什麼條件才能存在)
CRAG Graph:
cfg80211_p2p_init()
active_conditions: {"WIFI_P2P_SUPPORT": "y"}
──→ cfg80211_get_bss()
Query: preprocess_config({"WIFI_P2P_SUPPORT": "n"})
Result: cfg80211_p2p_init() 被自動過濾掉
Query: preprocess_config({"WIFI_P2P_SUPPORT": "y"})
Result: cfg80211_p2p_init() 出現
```
## 架構
```
crag-mcp/
├── crag_mcp/
│ ├── core/
│ │ ├── workspace.py # Workspace 掃描
│ │ └── config_context.py # Config / #ifdef 管理
│ ├── parsers/
│ │ └── tree_sitter_parser.py # AST + #ifdef 條件提取
│ ├── llm/
│ │ └── small_llm.py # Semantic analysis
│ ├── graph/
│ │ └── kuzu_graph.py # Kùzu + active_conditions
│ └── server/
│ └── mcp_server.py # 7 tools
├── pyproject.toml
└── README.md
```
## MCP Tools (7)
| Tool | 用途 |
|------|------|
| `configure(workspace_path?, small_llm?)` | 設定 workspace 與 LLM |
| **`preprocess_config(config_path?, define_overrides?, workspace_path?)`** | **載入條件編譯設定(綁定 workspace)** |
| `query_graph(query, max_results?, workspace_path?)` | 搜尋(自動套用 config 過濾) |
| `get_callers(func, depth?, workspace_path?)` | Graph: upstream(config-aware) |
| `get_callees(func, depth?, workspace_path?)` | Graph: downstream(config-aware) |
| `get_call_path(A, B, workspace_path?)` | Graph: path(config-aware) |
| `graph_stats(workspace_path?)` | Graph 狀態 |
> 所有查詢 tool 都接受 `workspace_path` 參數,指向要操作的 workspace。
> 不傳則用最後一次 `configure()` 設定的 workspace。
## Atomic 設計哲學
**每個 workspace 完全獨立**,各自擁有自己的:
```
/ws/A/.crag-mcp/
├── graph.kuzu/ # Kùzu DB(函式 + 呼叫關係)
└── file_cache/ # parse cache
```
- `query_graph(ws=A)` 只查 A 的 DB、只套 A 的 config
- `query_graph(ws=B)` 只查 B 的 DB、只套 B 的 config
- 兩者完全不會互相干擾
Agent(或 LLM)負責 orchestration — 輪流查不同 workspace,再自行比較結果。
## 使用流程
### 1. 一般專案(無 #ifdef)
```python
configure(workspace_path="/path/to/project")
query_graph("authentication flow")
# 無條件過濾,所有 code 都出現
```
### 2. C / Linux Kernel(有 #ifdef)
```python
configure(workspace_path="/path/to/linux")
preprocess_config(
config_path="/path/to/linux/.config",
define_overrides={"WIFI_P2P_SUPPORT": "y"}
)
query_graph("WIFI P2P implementation")
# 只有 WIFI_P2P_SUPPORT=y 的 code 會出現
# 改 config,重新查詢
preprocess_config(
config_path="/path/to/linux/.config",
define_overrides={"WIFI_P2P_SUPPORT": "n"}
)
query_graph("WIFI P2P implementation")
# P2P 相關 code 被自動過濾掉
```
### 3. 多 Workspace 比較(Agent 層次)
```python
configure(workspace_path="/ws/A")
preprocess_config(config_path="/ws/A/.config", workspace_path="/ws/A")
configure(workspace_path="/ws/B")
preprocess_config(config_path="/ws/B/.config", workspace_path="/ws/B")
result_a = query_graph("wifi p2p flow", workspace_path="/ws/A")
result_b = query_graph("wifi p2p flow", workspace_path="/ws/B")
# Agent 自行比較,再決定要不要查 C
result_c = query_graph("wifi p2p flow", workspace_path="/ws/C")
```
## preprocess_config 支援的格式
| 格式 | 範例 | 說明 |
|------|------|------|
| Linux .config | `CONFIG_WIFI=y` | 自動 parse |
| C Header | `#define WIFI 1` | `#define` 提取 |
| Makefile | `CFLAGS += -DWIFI=1` | `-D` 提取 |
| JSON | `{"WIFI": "y"}` | 直接載入 |
| Manual | `define_overrides={}` | 程式設定 |
## Config 過濾邏輯
```python
# Graph node 儲存
{
"name": "cfg80211_p2p_init",
"active_conditions": {"WIFI_P2P_SUPPORT": "y"}
}
# Query 時比對
preprocess_config(define_overrides={"WIFI_P2P_SUPPORT": "n"})
# → cfg80211_p2p_init 被過濾(條件不滿足)
preprocess_config(define_overrides={"WIFI_P2P_SUPPORT": "y"})
# → cfg80211_p2p_init 出現(條件滿足)
# 無 active_conditions → 永遠出現(always active)
```
## 本地儲存位置
每個 workspace 會在自己的根目錄下建立 `.crag-mcp/` 目錄:
```
/path/to/project/.crag-mcp/
├── graph.kuzu/ # Kùzu DB(二進制目錄)
└── file_cache/ # parse cache(JSON)
```
加到 `.gitignore`:
```gitignore
.crag-mcp/
```
## 安裝
```bash
cd /path/to/crag-mcp/
pip install -e .
```
或使用 `uv`:
```bash
cd /path/to/crag-mcp/
uv pip install -e .
```
## OpenCode 設定
```json
{
"mcpServers": {
"crag": {
"command": "uv",
"args": ["run", "--directory", "/path/to/crag-mcp", "-m", "crag_mcp.server.mcp_server"],
"env": {
"CRAG_WORKSPACE": "${workspaceFolder}",
"CRAG_SMALL_LLM": "gemma4:31b-cloud"
}
}
}
}
```
## Agent 決策流程
```
Agent 看到專案:
├── 有 .config / Kconfig / #ifdef → 呼叫 preprocess_config()
├── 純 Python / JS / Go → 不呼叫(無條件編譯)
└── 使用者提到 "kernel" / "config" → 詢問是否 preprocess
```
## Token 節省
| 場景 | 傳統 | CRAG-MCP |
|------|------|----------|
| Kernel query | 餵全部 code(含 dead code) | 只查 active code |
| Config 切換 | 重新 index 整個 repo | 只改 query 條件 |
| #ifdef 分析 | LLM 自己猜條件 | graph 標記清楚 |
## License
MIT
TDQS
Scored across 9 tools
The tools are mostly distinct in purpose. `configure` and `preprocess_config` both relate to setup but target different aspects (general workspace vs. preprocessing for conditional compilation). Other tools like `read_function_body`, `query_graph`, and the call graph tools have clearly separate roles. A minor overlap exists but descriptions help disambiguate.
Tool names are inconsistent: some follow verb_noun (read_function_body, query_graph, summarize_function, get_callers), while `configure` is a bare verb, `preprocess_config` uses verb_noun but with a different verb style, and `graph_stats` is noun_noun with no verb. This mixed pattern reduces predictability.
9 tools is appropriate for a code analysis server covering configuration, code reading, graph indexing, function summarization, and call queries (callers, callees, paths). The scope feels well-balanced without being too heavy or too thin.
The tool set covers the main workflows for call graph analysis: setup, source retrieval, graph search, deep analysis, and call relationship queries. Missing features like variable cross-references or type queries are beyond the stated domain, so the set is reasonably complete for its purpose.