leakguard-mcp
Static-analyzes Python code for lookahead bias and data leakage, preventing invalid backtests in time-series ML.
README
<!-- mcp-name: io.github.doazvjettu/leakguard-mcp -->
leakguard-mcp
Squawk for backtests. A local-first MCP server that static-analyzes agent-generated Python code and flags lookahead bias & data leakage before the backtest runs.
Works for any time-series ML code — quant trading (crypto, equities, forex, futures),
demand forecasting, energy, weather, IoT sensors — wherever a wrong .shift() or a
global normalization silently poisons your results.
- Pure source analysis (libcst) — your code never leaves the machine, no API calls.
- Heuristic, not a proof: severity tiers (🔴 error / 🟡 warning), like an aviation squawk.
- Framework-agnostic: pandas / numpy / polars, any stack.
- MCP-native (stdio): works directly inside Claude Code, Cursor, and any MCP-compatible agent.
- All 10 rules ship free — no license, no tiers, no phone-home.

Why this exists
AI agents (Claude Code, Cursor) write feature engineering and strategy code faster than humans can review it. But they introduce lookahead bias at scale — subtle time-boundary errors that backtest perfectly and fail catastrophically in live trading or production:
# Agent writes this — looks fine, is catastrophically wrong
df['momentum'] = df['close'].shift(-5) # uses FUTURE prices as a feature
df['vol_norm'] = (df['close'] - df['close'].mean()) / df['close'].std() # leaks future mean
leakguard catches these in the same agent loop — before the backtest runs:
LG001 🔴 line 2: Future shift used as feature — shift(-5) references 5 bars ahead.
Fix: df['momentum'] = df['close'].shift(5) (lag, not lead)
LG003 🔴 line 3: Global-fit normalization — mean/std computed over the full series
before any train/test split, leaking future statistics into the past.
Fix: df['vol_norm'] = (df['close'] - df['close'].expanding().mean()) / df['close'].expanding().std()
The agent reads the finding + fix snippet and self-corrects in one turn. No human review needed.
Install
Requirements
- Python 3.11+
- uv (recommended) or pip
From PyPI
pip install leakguard-mcp
From source
git clone https://github.com/doazvjettu/leakguard-mcp
cd leakguard-mcp
uv sync
Setup with Claude Code
Add to your MCP config (~/.claude/claude_desktop_config.json or .claude/settings.json
in your project):
{
"mcpServers": {
"leakguard": {
"command": "python",
"args": ["-m", "leakguard.server"]
}
}
}
Or if installed via uv:
{
"mcpServers": {
"leakguard": {
"command": "uv",
"args": ["run", "python", "-m", "leakguard.server"]
}
}
}
Restart Claude Code. leakguard's tools are now available to the agent.
Setup with Cursor
Add the same block under mcpServers in your Cursor MCP settings file.
MCP Tools
| Tool | Description |
|---|---|
lint_code(code) |
Analyze a code string, return findings |
lint_file(path) |
Analyze a file on disk |
lint_paths(glob) |
Analyze all matching files |
list_rules() |
List all rules with severities |
explain_rule(rule_id) |
Full rationale + fix patterns for a rule |
CLI
The same scanner is available as a CLI — handy for a pre-commit hook or CI step (exits non-zero when leakage is found):
uv run leakguard path/to/strategy.py
# or, installed: leakguard path/to/strategy.py
It prints each finding with its severity, line/col, and a concrete fix snippet — the same output shown in the demo above.
Rules
All 10 rules active, no tiers:
| ID | Severity | Pattern |
|---|---|---|
| LG001 | 🔴 | Future shift as feature: shift(-n) / diff(-n) / pct_change(-n) |
| LG002 | 🔴 | Centered windows: rolling(center=True) |
| LG003 | 🔴 | Global-fit scaling: StandardScaler().fit(full_df) / hand-rolled mean-std before split |
| LG004 | 🔴 | Shuffled time-series split: train_test_split default, KFold, cross_val_score(cv=n) |
| LG005 | 🔴 | Label leakage: future-derived target column reused in features |
| LG006 | 🟡 | Whole-history aggregates as features: .max() / .mean() over full series |
| LG007 | 🔴 | Backfill imputation: bfill() / fillna(method='bfill') |
| LG008 | 🔴 | Forward asof-joins: merge_asof(direction='forward'/'nearest') |
| LG009 | 🟡 | Resample label/closed mismatch on bar timestamps |
| LG010 | 🟡 | groupby().transform()/agg() spanning train/test boundary |
Each finding includes a concrete fix snippet so the calling agent can self-correct immediately.
Benchmark
Measured on two labeled corpora, 49 snippets total.
Reproduce with uv run python -m benchmark.run.
Honesty note: the trading corpus was written by the tool's author — treat its numbers as regression fixtures, not independent validation. The general-ML corpus is one arm's length removed in domain (author-composed reproductions of widely documented leakage anti-patterns, not a downloaded public dataset). The corpus deliberately includes adversarial snippets the scanner is known to miss; they are counted against it.
Trading corpus — 39 snippets (23 leaky, 16 clean + hard negatives):
| Rule | Precision | Recall | TP | FP | FN |
|---|---|---|---|---|---|
| LG001 | 75% | 100% | 6 | 2 | 0 |
| LG002 | 100% | 100% | 5 | 0 | 0 |
| LG003 | 75% | 100% | 3 | 1 | 0 |
| LG004 | 100% | 100% | 4 | 0 | 0 |
| LG005 | 100% | 100% | 5 | 0 | 0 |
| LG006 | 100% | 100% | 5 | 0 | 0 |
| LG007 | 100% | 100% | 5 | 0 | 0 |
| LG008 | 100% | 100% | 2 | 0 | 0 |
| LG009 | 75% | 100% | 3 | 1 | 0 |
| LG010 | 100% | 100% | 2 | 0 | 0 |
| Overall | 91% | 100% | 40 | 4 | 0 |
General-ML corpus — 10 snippets (LG003/LG004/LG010): Precision 88%, Recall 100% (TP 7 / FP 1 / FN 0).
Combined: Precision 90.4%, Recall 100% (TP 47 / FP 5 / FN 0).
Recall is 100% on this corpus — every adversarial miss exposed has since been fixed
(constant propagation, hand-rolled normalization, cv=<int>, drop-based selection).
Leak shapes not yet in the corpus are still missed — see Known Limitations below.
Known false positives (clean code that gets flagged)
- LG001: a forward-return label built with a negative shift and used only as
y— pure AST cannot distinguish a target column from a feature. - LG003: fit inside a helper defined above the split call site — line-order heuristic confuses definition order with execution order.
- LG004: shuffled splits on genuinely non-temporal data — no datetime-index inference yet.
- LG009: resampling for reporting/plotting rather than features — intent is invisible to static analysis.
Known false negatives (leak shapes not yet covered)
- LG004:
cross_val_score(...)withcvomitted (defaults to KFold). - LG005: taint through
df.loc[:, 'col'] = ...ordf.assign(col=...). - All rules: values flowing through function calls, dicts, or non-constant variables — no cross-function dataflow.
These sets are pinned in tests/test_benchmark.py: any new miss or silent fix fails the
suite until docs and corpus are updated to match.
Develop
uv sync --extra dev
uv run pytest # 96 tests
uv run python -m leakguard.server # stdio MCP server
uv run leakguard demo/strategy_leaky.py # CLI on the demo file
uv run python -m benchmark.run # precision/recall tables + FP/FN lists
The scanner core lives in leakguard/core/ (pure, no MCP imports); server.py and
cli.py are thin wrappers. Each rule has a fixture pair under tests/fixtures/.
Limitations (v1)
- Heuristic static analysis — catches ~90% of common patterns, not 100%.
- Single-file only — no cross-module taint tracking.
- Python only (pandas / numpy / polars).
- No runtime execution — cannot catch patterns that only emerge at runtime.
Contributions welcome: new corpus snippets (especially real bugs you've hit) strengthen the benchmark more than new rules do.
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。