mariusei/file-scanner-mcp
GitHub: mariusei/file-scanner-mcp
Scantool 是一个基于 tree-sitter 的代码结构分析 MCP 服务器,帮助 AI 助手以更少的 token 精准理解代码库结构。
Stars: 3 | Forks: 0
# Scantool: 用于 Claude 的代码分析 MCP Server
[](https://pypi.org/project/scantool/)
[](https://opensource.org/licenses/MIT)
MCP server 为 AI agent 提供代码库的**结构** —— 类、函数、调用图、导入、热点函数,所有这些都带有精确的行号 —— 而不是原始的文件转储。适用于 **Claude Code**、**Claude Desktop**、**Cursor**、**VS Code** 以及任何 **Model Context Protocol** 客户端。通过 **tree-sitter** 支持 20 多种语言 —— 并通过相同的视角处理代码*和*文档(Markdown、HTML、CSS、SQL、配置文件),这是纯代码工具无法做到的。
**实际测量出的优势(而非空头声称):**
```
"Where is the cache invalidated?" scantool 378 tokens / 1 call
grep 9,370 tokens / 4 calls -> 25x less
pytest skipif-caching bug scantool solved in 3 calls
grep gave up after 13,450 tokens
```
在真实的 agent 任务中,scantool agent 以 **88% 的事实覆盖率 vs 73%** 击败了仅使用 grep 的 agent —— 锚定更准确,错误文件更少。诚实的范围评估:grep 在普通的字面查找和顶级概览方面仍然占优。Scantool 测量了**两个**维度,并且也会报告损失(`experiments/benchmark/`)。
**零基础设施**:无需构建索引,无需 API 密钥,无需向量数据库,无需下载模型。只需指向一个目录,它就会按需进行扫描。
## 快速开始
**需要 [uv](https://docs.astral.sh/uv/)**(提供 `uvx` 命令)。如果你还没有安装它,请先安装 —— 没有它,scantool 将无法静默启动:
```
# macOS / Linux / WSL
curl -LsSf https://astral.sh/uv/install.sh | sh
```
### Claude Code
```
# 在所有项目中可用(推荐)
claude mcp add --scope user scantool -- uvx scantool
# 或仅用于当前项目
claude mcp add scantool -- uvx scantool
```
重启 Claude Code 即可开始使用。
### Claude Desktop
添加到配置文件中(macOS 上位于 `~/Library/Application Support/Claude/claude_desktop_config.json`):
```
{
"mcpServers": {
"scantool": {
"command": "uvx",
"args": ["scantool"]
}
}
}
```
配置完成后重启 Claude Desktop。
### Cursor
添加到 `~/.cursor/mcp.json`(全局)或 `.cursor/mcp.json`(单个项目):
```
{
"mcpServers": {
"scantool": {
"command": "uvx",
"args": ["scantool"]
}
}
}
```
### Windsurf
添加到 `~/.codeium/windsurf/mcp_config.json`:
```
{
"mcpServers": {
"scantool": {
"command": "uvx",
"args": ["scantool"]
}
}
}
```
### VS Code (Copilot agent 模式)
添加到工作区的 `.vscode/mcp.json`:
```
{
"servers": {
"scantool": {
"command": "uvx",
"args": ["scantool"]
}
}
}
```
### Cline
在 Cline 面板中:MCP Servers 图标 → *Configure* 标签页 → *Configure MCP Servers*,然后添加与上述相同的 `mcpServers` 条目。(Cline CLI 会读取 `~/.cline/mcp.json`。)
### 故障排除:找不到 `uvx`
`uvx` 随 [uv](https://docs.astral.sh/uv/)(Python 包管理器)一起提供。请先安装它:
```
# macOS / Linux / WSL
curl -LsSf https://astral.sh/uv/install.sh | sh
# Windows (PowerShell)
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
```
**安装 uv 后,请重启你的终端**(或打开一个新终端),以便 `uvx` 加入你的 PATH。然后重新运行上方的设置命令。
如果重启终端后仍未找到 `uvx`,请手动将其添加到你的 PATH:
```
# Linux / WSL - 添加到 ~/.bashrc 或 ~/.zshrc:
export PATH="$HOME/.local/bin:$PATH"
# macOS - 通常开箱即用,但如果不可以:
export PATH="$HOME/.local/bin:$PATH"
```
### 替代方案:从源码安装
```
git clone https://github.com/mariusei/file-scanner-mcp.git
cd file-scanner-mcp
uv sync
# Claude Code
claude mcp add --transport stdio scantool -- uv run --directory /path/to/file-scanner-mcp scantool
# Claude Desktop
# 使用命令:"uv", args: ["run", "--directory", "/path/to/file-scanner-mcp", "scantool"]
```
### 与团队共享 (.mcp.json)
在你的项目根目录中添加一个 `.mcp.json` 文件,以便与团队共享配置:
```
{
"mcpServers": {
"scantool": {
"command": "uvx",
"args": ["scantool"]
}
}
}
```
Claude Code 会在首次使用时提示团队成员进行批准。
## 功能
### 多语言支持
Python, JavaScript, TypeScript, Rust, Go, C/C++, Java, PHP, C#, Ruby, Zig, Swift, SQL (PostgreSQL, MySQL, SQLite), HTML, CSS, SCSS, Markdown, Plain Text, Images
### 结构提取
- 类、方法、函数、导入
- 带有类型注解的函数签名
- 装饰器和属性
- Docstring 和 JSDoc 注释
- 精确的行号(起止范围)
### 分析工具
- **preview_directory**: 智能代码库分析,包含入口点、导入图、调用图和热点函数 (5-10秒)
- **scan_file**: 详细的文件结构,包含签名和元数据;`focus=` 逐字读取指定的一个函数/类/代码段及其父级上下文
- **scan_directory**: 紧凑的目录树,内联显示函数/类名
- **search_structures**: 按类型、名称模式、装饰器或复杂度进行过滤
- **list_directories**: 目录树(仅包含文件夹)
- **find_divergence**: 审查目录中的同级差异 —— 即破坏了其同级所遵循的调用模式的函数(调用 X 的同级也调用了 Y,但该函数没有);这仅作为审查提示,并非已验证的 bug;如果代码库一致,则不会有输出。相同的段落也会内联显示在 `scan_diff`(更改的代码)和 `preview_directory`(深度)中
### 输出格式
- 带有框线字符的树状格式
- 用于编程的 JSON 格式
- 可配置的显示选项
## 用法
### preview_directory - 代码分析(主要工具)
分析代码库结构,包括入口点、导入图、调用图和热点函数。
```
preview_directory(
directory=".",
depth="deep", # "quick", "normal", or "deep" (default: "deep")
max_files=10000, # Safety limit (default: 10000)
max_entries=20, # Entries per section (default: 20)
respect_gitignore=True # Honor .gitignore (default: True)
)
```
**深度级别:**
- `"quick"`: 仅元数据 (0.5s) - 文件数、大小、类型
- `"normal"`: 架构分析 (2-5s) - 导入、入口点、集群
- `"deep"`: 完整分析 (5-10s) - 包含热点函数和调用图(默认)
**输出示例 (depth="deep"):**
```
project/
--- ENTRY POINTS ---
main.py:main() @1
backend/application.py:Flask app @15
frontend/index.ts:export default
--- CORE FILES (by centrality) ---
backend/database.py: imports 0, used by 15 files
backend/auth.py: imports 1, used by 8 files
shared/utils.py: imports 2, used by 12 files
--- ARCHITECTURE ---
Entry Points: 25 files
Core Logic: 68 files
Plugins: 15 files
Tests: 42 files
--- HOT FUNCTIONS (most called) ---
get_database() (function): called by 41, calls 1 @backend/database.py
authenticate() (function): called by 23, calls 5 @backend/auth.py
validate_input() (function): called by 15, calls 2 @shared/utils.py
Analysis: 486 files in 4.82s (layer1+layer2)
```
**使用场景:**
- 首次探索代码库
- 了解多模态项目(前端/后端/数据库)
- 查找关键函数(热点)
- 识别入口点
### scan_file - 详细的文件分析
```
scan_file(
file_path="path/to/file.py",
focus=None, # Read ONE node verbatim by name ("query",
# "DatabaseManager.query", a markdown heading)
# instead of guessing line ranges — see below
show_signatures=True, # Include function signatures with types
show_decorators=True, # Include @decorator annotations
show_docstrings=True, # Include first line of docstrings
show_complexity=False, # Show complexity metrics
condense=True, # Condensed skeletons (set False for verbatim lines)
budget=None, # Approx token cap for skeletons — least salient
# functions degrade first, output stays predictable
output_format="tree" # "tree" or "json"
)
```
**输出示例:**
```
example.py (1-57)
- file-info: 1.4KB modified: 2 hours ago
- imports: import statements (3-5)
- class: DatabaseManager (8-26)
"Manages database connections and queries."
- method: __init__ (self, connection_string: str) (11-13)
- method: connect (self) (15-17)
"Establish database connection."
- method: query (self, sql: str) -> list (24-26)
"Execute a SQL query."
return self.cursor.execute(sql).fetchall()
- function: main () (53-57)
"Main entry point."
```
函数还会将其实现显示为压缩的方法
骨架:即没有行号的伪代码行,其中带有条件的控制流、
调用和返回都会被保留,而简单的语句会被折叠为 `…`
(逐字读取的行始终带有 `N |` 行号 —— 这就是你区分
它们的方法)。骨架分为两个层级:最突出的函数(根据 entropy、
uniqueness 和 centrality)获得全深度,其他所有函数获得
浅层的 depth-2 大纲 —— 这是根据测量得出的最佳 token 事实覆盖率。
标记是纯 ASCII 字符,因为框线字形每个会消耗 2-3 个 BPE token。
传入 `condense=False` 可获取带有行号的摘录(仅限顶层)。
压缩会根据语言进行适配:命令式语言(Python、TypeScript、
Go、Rust、Java 等)默认获取折叠骨架,声明式语言(CSS、
SQL、HTML)保留其内容,仅丢弃空格、注释和结束
标点符号,而文本/配置保持原样 —— 如果没有安全折叠的余地,
则原样显示原始摘录。
#### focus= — 读取步骤
在扫描或搜索定位到节点后,传入 `focus=` 即可逐字
读取该函数/类/方法/标题 —— 而无需为 Read/cat/sed 猜测行
范围:
```
scan_file(file_path="example.py", focus="DatabaseManager.query")
```
```
focus: DatabaseManager.query @24-26
example.py (3-57)
- import statements @3
- DatabaseManager @8 # Manages database connections and queries.
- __init__ (self, connection_string: str) @11
- connect (self) @15 # Establish database connection.
- disconnect (self) @19 # Close database connection.
- query (self, sql: str) -> list @24 # Execute a SQL query.
24 | def query(self, sql: str) -> list:
25 | """Execute a SQL query."""
26 | return []
- UserService @29 # Handles user-related operations.
- validate_email (email: str) -> bool @48 # Validate email format.
- main () @53 # Main entry point.
```
文件的其余部分保持为 depth-1 骨架,因此该节点会连同
其父级上下文一起返回。名称分三个层级进行解析:精确匹配、限定
路径(`ClassA.method`,也适用于 Markdown 标题),然后是
不区分大小写的子字符串;模棱两可的名称将返回合格的
候选列表,而不是进行猜测。根据真实 agent 任务的测量结果
(`experiments/benchmark/M2C.md`):在读取 token 数量比猜测 cat/sed 行范围少 75% 的情况下,获得了同等的答案质量。
### scan_file_content - 直接分析内容
无需文件路径即可扫描内容。适用于远程文件、API 或内存中的内容。
```
scan_file_content(
content="def hello(): pass\n\nclass MyClass:\n pass",
filename="example.py", # Extension determines parser
show_signatures=True,
show_decorators=True,
show_docstrings=True,
show_complexity=False,
output_format="tree"
)
```
### scan_directory - 紧凑概览
显示目录树,内联包含类/函数名。
```
scan_directory(
directory="./src",
pattern="**/*", # Glob pattern
max_files=None, # File limit
respect_gitignore=True, # Honor .gitignore
exclude_patterns=None, # Additional exclusions
output_format="tree" # "tree" or "json"
)
```
**输出示例:**
```
src/ (22 files, 15 classes, 127 functions, 89 methods)
├─ languages/
│ ├─ python.py (1-329) [11.9KB, 2 hours ago] - PythonLanguage
│ ├─ typescript.py (1-505) [18.9KB, 1 day ago] - TypeScriptLanguage
│ └─ rust.py (1-481) [17.6KB, 3 days ago] - RustLanguage
├─ scanner.py (1-232) [8.8KB, 5 mins ago] - FileScanner
└─ server.py (1-735) [27.2KB, just now] - scan_file, scan_directory, ...
```
**Pattern 示例:**
```
# 特定文件类型
scan_directory("./src", pattern="**/*.py")
# 多种类型
scan_directory("./src", pattern="**/*.{py,ts,js}")
# 浅层扫描(深入 1 层)
scan_directory(".", pattern="*/*")
# 排除目录
scan_directory(".", exclude_patterns=["tests/**", "docs/**"])
```
### search_structures - 查找和过滤
```
# 查找测试函数
search_structures(
directory="./tests",
type_filter="function",
name_pattern="^test_"
)
# 查找以 "Manager" 结尾的类
search_structures(
directory="./src",
type_filter="class",
name_pattern=".*Manager$"
)
# 查找带有 @staticmethod 的函数
search_structures(
directory="./src",
has_decorator="@staticmethod"
)
# 查找复杂函数(>100 行)
search_structures(
directory="./src",
type_filter="function",
min_complexity=100
)
```
### list_directories - 文件夹结构
显示不含文件的目录树。
```
list_directories(
directory=".",
max_depth=3, # Maximum depth (default: 3)
respect_gitignore=True # Honor .gitignore (default: True)
)
```
**输出示例:**
```
/Users/user/project/
├─ src/
│ ├─ components/
│ ├─ services/
│ └─ utils/
├─ tests/
│ ├─ unit/
│ └─ integration/
└─ docs/
```
## 输出契约
默认的输出格式就是 API:LLM agent 会直接
不加甄别地消费 scantool 的输出,因此格式偏移
就是消费者中的行为偏移(在 `experiments/benchmark/M2B.md` 中测量)。由此带来两个结果:
- **默认值即测量出的最优解 —— 参数是逃生舱。**
每一个默认值(双层压缩、显著性选择、骨架
深度、按语言区分的紧凑与逐字模式)都有 `experiments/condensation/`、`experiments/entropy_metrics/` 和
`experiments/benchmark/` 中的测量数据作为支撑。只有在特定情况
需要时才覆盖它们,而不是作为风格偏好。
- **默认格式被 golden 测试冻结**(`tests/test_golden.py`,
快照位于 `tests/golden/`)。刻意的格式更改需要
刻意的快照更新(`UPDATE_GOLDEN=1 uv run pytest
tests/test_golden.py`);意外更改会导致 CI 失败。依赖
环境的部分(文件大小/mtime、git churn、delta 内存)位于
冻结层之外。同级差异是代码的纯函数,因此它
也被冻结(`tests/golden/consensus.txt`,测试 fixture 位于
`tests/golden/consensus_fixture/`)。
## 支持的语言
| 扩展名 | 语言 | 提取的元素 |
|-----------|----------|-------------------|
| `.py`, `.pyw` | Python | 类、方法、函数、导入、装饰器、docstring |
| `.js`, `.jsx`, `.mjs`, `.cjs` | JavaScript | 类、方法、函数、导入、JSDoc 注释 |
| `.ts`, `.tsx`, `.mts`, `.cts` | TypeScript | 类、方法、函数、导入、类型注解、JSDoc |
| `.rs` | Rust | 结构体、枚举、trait、impl 块、函数、use 语句 |
| `.go` | Go | 类型、结构体、接口、函数、方法、导入 |
| `.c`, `.h` | C | 函数、结构体、枚举、include |
| `.cpp`, `.hpp`, `.cc`, `.hh` | C++ | 类、函数、命名空间、模板、include |
| `.java` | Java | 类、方法、接口、枚举、注解、导入 |
| `.php` | PHP | 类、方法、函数、trait、接口、命名空间 |
| `.cs` | C# | 类、方法、属性、结构体、枚举、命名空间 |
| `.rb` | Ruby | 模块、类、方法、单例方法 |
| `.zig` | Zig | 函数、结构体、枚举、联合体、测试 |
| `.swift` | Swift | 类、结构体、枚举、协议、函数、扩展 |
| `.sql` | SQL | 表、视图、函数、存储过程、索引、列 |
| `.html` | HTML | 文档结构、元素、属性 |
| `.css` | CSS | 选择器、属性、媒体查询 |
| `.scss` | SCSS | 选择器、mixin、变量、嵌套 |
| `.md` | Markdown | 标题 (h1-h6)、具有层级结构的代码块 |
| `.txt` | Plain Text | 章节、段落 |
| `.png`, `.jpg`, `.gif`, `.webp` | Images | 格式、尺寸、颜色、内容类型 |
所有文件都会自动包含元数据(大小、修改日期、权限)。
## 使用场景
### 代码导航
- 不熟悉代码库的结构概览
- 了解文件组织结构
- 使用精确的行范围进行导航
### 重构
- 识别类和函数边界以进行安全拆分
- 查找特定模式的实现
- 定位复杂度超过阈值的函数
### 代码审查
- 生成结构差异
- 查找带有特定装饰器的函数
- 识别测试覆盖盲区
- 同级差异:找出打破了其跨存储库同级所遵循的调用模式的已更改函数(这很可能是回归 —— 需通过阅读来判定)
### 文档
- 自动生成带行号的目录
- 提取 API 签名
- 将结构化数据提供给分析工具(JSON 输出)
### AI 代码辅助
- 主要的探索工具(取代 ls/grep/find 工作流)
- 为 LLM 上下文窗口智能拆分大文件
- 提取具有精确边界的代码段
- 跨代码库搜索模式
- 减少 token 使用:首先获取结构,仅在需要时读取内容
## 架构
```
scantool/
├── server.py # FastMCP server (stdio + HTTP entry points)
├── scanner.py # Core scanning logic using tree-sitter
├── formatter.py # Tree formatting with box-drawing characters
├── code_map.py # Architecture analysis (Layer 1 + 2)
├── call_graph.py # Hot functions, centrality analysis
├── preview.py # Quick directory preview
└── languages/ # Unified language system (one file per language)
├── base.py # BaseLanguage - all languages inherit from this
├── models.py # StructureNode, CallInfo, ImportInfo, etc.
├── python.py # PythonLanguage
├── typescript.py
├── rust.py
└── ... # 20+ languages
```
## HTTP 传输(高级)
适用于 stdio 无法工作的环境,或者需要在多个客户端之间共享服务器的情况:
```
# 启动 HTTP server
uvx --from scantool scantool-http
# 默认监听端口 8080(设置 PORT 环境变量来更改)
# 将 Claude Code 连接到它
claude mcp add --transport http scantool http://127.0.0.1:8080/mcp
```
注意:必须单独启动保持 HTTP 服务器运行。对于大多数用户来说,stdio 传输(默认)更简单,也是推荐的方式。
## 测试
```
# 运行所有测试
uv run pytest
# 运行特定测试
uv run pytest tests/languages/
uv run pytest tests/python/
uv run pytest tests/typescript/
# 运行 coverage
uv run pytest --cov=src/scantool
# 运行 verbose 输出
uv run pytest -v
```
## 贡献
有关添加语言支持的详细信息,请参阅 [CONTRIBUTING.md](CONTRIBUTING.md)。
## 许可证
MIT License - 详情请参阅 [LICENSE](LICENSE) 文件。
## 依赖项
- [FastMCP](https://github.com/jlowin/fastmcp) - MCP server 框架
- [tree-sitter](https://tree-sitter.github.io/) - 解析库
- [uv](https://github.com/astral-sh/uv) - Python 包安装器
## 已知的限制
### MCP 工具响应大小限制
Claude Desktop 对 MCP 工具响应强制执行 25,000 个 token 的限制。Claude Code 具有可配置的限制(设置 `MAX_MCP_OUTPUT_TOKENS` 环境变量以进行调整)。
**内置缓解措施:**
- `scan_directory()` 使用紧凑的内联格式
- 默认遵守 `.gitignore`(排除 node_modules、.venv 等)
- 显示带有相对时间戳的文件元数据
**手动控制:**
- 使用 `pattern` 限制范围:`"**/*.py"` vs `"*/*"`(浅层)
- 使用 `max_files` 限制处理的文件数量
- 使用 `exclude_patterns` 进行额外排除
- 扫描特定的子目录而不是整个代码库
**对于大型代码库:**
```
# 扫描特定区域
scan_directory("./src", pattern="**/*.py")
scan_directory("./tests", pattern="**/*.py")
```
### Agent 委托
使用 Claude Code 时,要求“探索代码库”可能会委托给无法访问 MCP 工具的 Explore agent。请明确指示:“使用 scantool 扫描代码库”以确保直接使用 MCP 工具。
## 支持
- [GitHub Issues](https://github.com/mariusei/file-scanner-mcp/issues)
- [GitHub Discussions](https://github.com/mariusei/file-scanner-mcp/discussions)
标签:AI辅助编程, Claude, CVE检测, MCP Server, SOC Prime, Tree-sitter, 云安全监控, 代码分析, 凭证管理, 开发工具, 逆向工具, 静态分析