关于 Django Chainsaw
Django Chainsaw 是用于发现 Django 及相关 Python 项目风险的确定性 MCP 服务和命令行工具。它通过源码语法和 Django 应用注册表分析,不执行应用代码,也不向机器外发送数据,并可用于 CI 检查。
主要功能
- 01检查 Django 模型、查询和迁移
- 02检测租户范围与 API 暴露风险
- 03分析 FastAPI 和 SQLAlchemy 模式
- 04按端点和严重程度归类问题
- 05导出 SARIF 和 HTML 报告
- 06支持基线和分支比较
适用场景
- 01部署前检查迁移安全性
- 02查找租户数据泄露和查询低效
- 03在拉取请求中仅审查新增问题
- 04生成 CI 或团队审查报告
MCP 相关
向 MCP 客户端提供项目分析工具和提示词,可检查迁移、查询、端点及删除影响。基于应用注册表的检查需要 Django 项目路径和 settings 模块。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
uvx django-chainsaw-mcpDJANGO_CHAINSAW_PROJECT_PATHAbsolute path to the Django project to analyse - the directory containing manage.py, or whichever directory the settings module is importable from. This server must run in an interpreter that can import that project, so install it into the project's own environment rather than an isolated one.DJANGO_CHAINSAW_SETTINGS_MODULEDotted path to the settings module, for example myproject.settings. Point it at the settings the site actually runs on: a base or partial module can import cleanly and load no models, and the server says so when that happens.本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。
工具
37收录的工具列表 · 更新于 2 周前
此工具无需参数。
详细介绍
django-chainsaw-mcp
一个分析 Django 项目而非描述项目的 MCP 服务和命令行工具。 它不回答 这里有什么,而是指出 哪些地方会出问题:删除某项会连带删除什么,哪个迁移会导致仍在运行的 Pod 出问题,哪个查询会返回其他租户的行,以及一次 save() 会在三步之外触发什么。
整个过程不涉及模型。 所有答案都来自 AST 和 Django 自身的应用注册表,因此相同输入总会得到相同输出,也不会有任何内容离开本机。它是一个 MCP 服务,助手可以向它提问;它也是一个命令行工具,CI 可以依据答案设置门禁。
共有 22 项检查:19 项需要应用注册表(其中 16 项针对 Django,另有 3 项也针对 DRF),1 项只需要 Python,1 项读取 FastAPI,1 项读取 SQLAlchemy。 为什么要做这个项目 →
安装
它必须在能够导入你项目的解释器中运行。 这里的所有功能都会读取应用注册表,这意味着需要执行 django.setup(),并使用你的设置和应用:
/path/to/project/.venv/bin/python -m pip install django-chainsaw-mcp
直接运行 uvx django-chainsaw-mcp 会启动后随即导致所有检查失败,因为 uvx 会为它提供一个独立环境,其中完全没有你的项目。若要避免安装,可以将依赖项交给 uv:
uvx --with-requirements requirements.txt --from django-chainsaw-mcp django-chainsaw check
通过两个环境变量指定项目:
| 变量 | 示例 |
|---|---|
DJANGO_CHAINSAW_PROJECT_PATH | /srv/app — 可以从该目录导入设置 |
DJANGO_CHAINSAW_SETTINGS_MODULE | myproject.settings |
django-chainsaw project-info 会在执行其他操作前验证设置,并指出缺少哪一项。五分钟快速上手 →
mcp-name: io.github.syrian963/django-chainsaw-mcp
一条命令
django-chainsaw check --tenant-root myapp.Organisation
44 finding(s): 1 critical, 14 high, 29 medium
CRITICAL
--------
[deploy-safety] RemoveField drops 'legacy_code' while code still uses it
shop/0002_remove_product_legacy_code
During a rolling deploy the old pods keep running against the new
schema and will fail.
fix: Ship a release that stops using it, deploy that everywhere,
then ship this migration.
合并所有分析结果,按风险从高到低排列,并返回一个退出码。
在拉取请求中使用
这决定了这类工具能否长期使用。让 tenancy 检查一个已有五年的项目,它会返回两百条候选结果;没人会逐条查看这两百条结果,于是有人加上 continue-on-error,它就会一直运行,却再也没人关注。
django-chainsaw tenancy --since main # only what this branch changed
django-chainsaw tenancy --baseline # everything old, ratcheted
django-chainsaw check --sarif out.json # annotate the diff, on the line
--since 会以合并基点进行比较,因此落后于 main 的分支不会因为其他人的更改而受到指责。--baseline 会将已有问题保留在报告中,同时不让它们阻断构建;任何新问题都会导致构建失败,修复旧问题也会被报告,因此问题数量只会减少。问题指纹基于文件和标识,而非行号,因此新增导入不会让二十条无人处理的问题重新出现。
--sarif 会写入 GitHub 和 GitLab 用于在拉取请求上添加注释的格式,让问题直接标注在代码行上,而不是出现在没人会打开的日志中。
作为 MCP 服务
claude mcp add django-chainsaw --scope local \
--env DJANGO_CHAINSAW_PROJECT_PATH=/srv/app \
--env DJANGO_CHAINSAW_SETTINGS_MODULE=myproject.settings \
-- /srv/app/.venv/bin/python -m django_chainsaw_mcp.server
先调用 project_info:这是能同时验证传输和 Django 启动的最小调用。五个提示词补上了工具本身不包含的调用顺序——before_deploy、why_is_this_slow、what_breaks_if_i_delete、triage、review_this_branch。
Claude Desktop、Cursor、VS Code、Windsurf、Zed、Docker →
或者生成一个 HTML 文件
django-chainsaw report --out findings.html --title myproject

按端点分组才是关键视图:哪些页面涉及此问题,以及通过什么调用路径。无需服务、网络或构建步骤——CSS、脚本和数据都在文件中,因此可以从 CI 构建产物或电子邮件附件中直接使用。report.md
检查项
Django 项目 — 这些检查会读取应用注册表,因此除了项目路径,还需要设置 DJANGO_CHAINSAW_SETTINGS_MODULE
| 工具 | 解答的问题 |
|---|---|
project_info | 目标项目能否加载?出现故障时,先运行此项。 |
list_models | 列出每个模型的字段、关联类型、方向和 on_delete。 |
delete_impact | 删除一条记录会怎样:哪些内容会级联删除、阻止删除或被置空。包括传递影响。 |
find_n_plus_one | 模板中的关联遍历各自会产生一次查询,并给出修复方法。 |
scan_templates | 扫描整个目录中的同类问题,并从视图解析上下文。 |
migration_risk | 对迁移进行评级:阻止写入、重建表或破坏正在运行的代码。 |
deploy_safety | 这个破坏性迁移现在可以安全发布了吗? |
find_unscoped_queries | 哪些查询读取了调用者可能无权访问的数据? 这就是 IDOR 问题的表现形式。 |
what_happens_on | 这次保存操作实际上会触发什么? 追踪信号链。 |
missing_indexes | 代码用于筛选或排序但没有索引的字段。 |
datetime_audit | 时钟变化时会出问题的无时区时间,以及字段默认值。 |
serializer_exposure | DRF 序列化器会公开哪些内容,包括下一次迁移将添加的内容。 |
serializer_nplusone | DRF 序列化器中的 N+1 问题;在 API 项目中,这正是问题所在。 |
explain_model | 一个模型的所有信息,以及只有综合分析才能发现的风险。 |
endpoint_cost | 在任何人发送请求之前,计算一次请求会产生多少次查询。 |
api_contract / api_contract_check | 此分支会如何改变 API,以及会影响哪些调用者。 |
escaping_side_effects | 事务中触发但事务仍可能回滚的邮件和任务。 |
bypassed_effects | 跳过 save() 链所承诺的所有操作的批量写入。 |
race_conditions | 将计数器读入 Python、修改后再保存的操作,以及不安全的 upsert。 |
money_precision | 十进制金额会在哪里失去精确性。 |
celery_arguments | 工作进程实际收到的内容,以及任务是否可被调用。 |
queries_in_loops | 循环中编写的查询,并按适用的三种修复方式分类。 |
defeated_prefetches | 已付出成本执行预取、随后又被读取数据的访问器重新查询的关联。 |
request_impact | 按能够触达问题的入口点对所有发现进行分组,从而明确该修复哪个端点。 |
choice_typos | 字段的 choices 永远不会匹配的字面值:SQL 有效、返回零行,也不会抛出异常。 |
multiplied_aggregates | 通过两个多值关联进行连接后被重复计算的计数和总和。 |
dangling_references | 无法解析的 URL 名称、模板、信号发送者和 Celery 任务。 |
open_endpoints | 任何人都能调用的端点上公开的敏感字段。 |
unused_eager_loading | 响应中没有读取的连接和预取。 |
check | 运行所有适用的检查,将结果整理为一个按严重程度排序的列表,并返回一个退出码。 |
suggest_fixes | 将发现转化为代码,并按应用安全性分组。 |
任何 Python 项目 — 无需 Django,也无需设置模块
| 工具 | 回答的问题 | | --- | --- | | `project_profile` | 这是基于什么构建的?根据项目自身的导入项统计。 | | `blocking_in_async` | **哪个同步调用会阻塞每个请求的事件循环?** | | `fastapi_exposure` | 序列化内容超出声明范围的端点。 | | `sqlalchemy_nplusone` | 逐行加载的关系,包括序列化期间加载的关系。 | | `amplification` | **陌生人可以利用哪个端点耗尽数据库?** |以及资源 django://models。check 会先分析项目,再运行适用的检查;对于其余检查,会说明 “不适用,原因如下”——如果不作说明,就会让人误以为检查结果正常。FastAPI 支持中的所有导入都不会导入项目,因此即使检出目录完全没有安装依赖,这些检查也能运行。
37 个工具中有 36 个声明了 readOnlyHint,因此客户端无需每次调用都询问权限;例外是 api_contract_check,当 update=True 时,它会写入快照并明确说明这一点。
查看所有工具、参数和输出格式 →
它不会告诉你什么
这里的任何操作都不会执行目标项目或读取其中的数据,这带来了安全性和速度,但也降低了确定性。每个工具都会在自己的输出中说明其盲点:
delete_impact不会运行信号或自定义的delete()覆盖方法。find_n_plus_one报告的是候选项;它读取模板和模型关系图,不会读取视图中的查询集。migration_risk不知道行数、PostgreSQL 版本或部署策略。deploy_safety无法看到getattr(obj, name)、运行时 SQL 或其他仓库。CLEAR表示在此处没有发现任何内容。
自信地给出错误答案,比给出不完整答案更糟。这类工具的失效模式不是崩溃,而是给出一句看似合理的话,把人引向错误方向。limitations.md
它会对你的代码做什么
它会导入目标项目。django.setup() 会导入你的设置以及 INSTALLED_APPS 中的每个应用,检查还会导入声明序列化器、视图和 URL 的模块——因此这些模块在导入时执行的任何操作都会发生。不要将它用于你不会运行的代码。
它不会运行你的应用程序:不会运行视图、任务或管理命令。
有一项检查会以只读方式读取数据库——MigrationLoader 会读取 django_migrations,不会写入任何内容。
只有在你要求时才会写入文件:fix --write 只会应用机械式修复;基线、契约快照或 --sarif 也只会写入你指定的位置。任何内容都不会离开本机——不会进行网络调用、遥测或上传。
文档
docs/ 是索引。
why.md | 为什么要做这个项目、值得了解的三项检查,以及新检查需要达到的标准 |
quickstart.md | 从克隆到发现首个问题,只需五分钟 |
usage.md | 在真实项目中安装、Docker、故障排除 |
clients.md | Claude Code、Cursor、VS Code、Windsurf、Zed |
cli.md | 命令、退出代码、CI |
tools.md | 所有工具、参数和输出格式 |
tested-against.md | 18 个公开项目、它们在此工具中发现的问题,以及从未触发的检查 |
limitations.md | 分析无法看到的内容 |
baseline.md | 逐步提高标准,让工具适用于遗留代码库 |
fixes.md | 将建议作为实际代码提供,以及哪些建议可以应用 |
architecture.md | 组件构成方式,以及引导程序为何决定了设计 |
performance.md | 大型项目中的耗时分布 |
贡献
CONTRIBUTING.md | 工作流、项目风格,以及如何运行测试套件 |
CHANGELOG.md | 每次发布,以及变更背后的原因 |
SECURITY.md | 此工具会如何处理你指定的代码 |
CODE_OF_CONDUCT.md | 坦诚待人,也要保持友善 |
新增检查的提案需要回答四个问题,问题模板会直接询问:缺陷在代码中是什么样子、在生产环境中会如何出错、现有哪些工具能发现它,以及它必须对哪些情况保持沉默。测量结果表明,两个已完成的功能无法区分真正的问题和正确的代码,因此已从此仓库中删除。
MIT。一个进程会一直绑定到它加载的第一个项目,因为无法撤销 django.setup() 的效果——要处理第二个项目,请运行第二个实例。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。