Skip to main content
Glama
bluemot
by bluemot
README.md
# 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

B3.2/5.0

Scored across 9 tools

Disambiguation4/5

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.

Naming Consistency2/5

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.

Tool Count4/5

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.

Completeness4/5

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.

Maintenance

ActivityInactive
ResponsivenessNo issues