gristmill-mcp
gristmill-mcp
一个 MCP 服务器,用于检查 AI 生成的代码,并返回确定性的结构和安全违规列表,以便 AI 编码代理在代码落地前修复自己的输出。
Grist 是送入磨坊研磨的谷物。AI 输出就是 grist——真正有价值的原材料,但未经加工。磨坊赋予它结构。
AI 写出 grist。Gristmill 让它成为可以交付的代码。
为什么是 MCP 服务器,而不是技能
技能是加载到模型上下文中的文本——它改变模型知道的内容。MCP 服务器是模型执行的程序——它改变模型能做什么。
风格指导("优先使用类而非松散函数")属于技能。验证("此文件在第 12、40、66 行有 7 个顶级函数")需要对文件运行代码。模型阅读自己的输出并推理"这看起来函数太多了"是一种伪装成观察的猜测——它没有关于"太多"在这个文件中意味着什么的真实依据,也没有可靠的计数方法。Gristmill 解析 AST 并进行计数。指令与执行之间的这种区别,就是为什么它作为一个服务器存在,而不是一段建议文本。
该服务器从不调用 LLM,在相同输入上运行结果从不变化,也从不输出置信度分数。相同输入 → 每次字节相同的输出。这种确定性就是整个产品的价值所在。AI 层位于此服务器之上,消费其发现结果并决定如何处理——服务器的工作止于报告带有行号的事实。
Related MCP server: code-verify-mcp
安装
git clone <this repo> gristmill-mcp
cd gristmill-mcp
python3 -m venv .venv
.venv/bin/pip install -e .Claude Code
通过 CLI 注册它,指向虚拟环境的控制台脚本:
claude mcp add gristmill -- /absolute/path/to/gristmill-mcp/.venv/bin/gristmill-mcp或者直接将其添加到你的 MCP 配置中(项目中的 .mcp.json,或全局 Claude Code 配置):
{
"mcpServers": {
"gristmill": {
"command": "/absolute/path/to/gristmill-mcp/.venv/bin/gristmill-mcp"
}
}
}其他 MCP 客户端
任何基于 stdio 的 MCP 客户端都可以启动相同的二进制文件——gristmill-mcp(或虚拟环境中的 python3 -m gristmill.server)使用标准 MCP stdio 传输协议,无需客户端特定配置。
命令行(无 MCP 客户端)
用于本地测试,或复现下面的工作示例,一个轻量级 CLI 封装了相同的引擎:
.venv/bin/gristmill-verify path/to/file_or_dir [--checks secrets structure comment_slop] [--severity-floor warning] [--json]工作示例
demo/billing.py,一个 Stripe 计费助手的未经编辑的初稿:
import stripe
# I've added this as you requested — sets up the Stripe client
STRIPE_SECRET_KEY = None # was a literal sk_live_... key — see note below
stripe.api_key = STRIPE_SECRET_KEY
def customer_create(config):
return stripe.Customer.create(**config)
def customer_delete(config):
return stripe.Customer.delete(config["id"])
def customer_find(config):
return stripe.Customer.retrieve(config["id"])
def customer_update(config):
return stripe.Customer.modify(config["id"], **config).venv/bin/gristmill-verify demo/billing.py输出,其中包含一个真实的 Stripe 活动密钥形状的字面量(替换了上面的 None):
gristmill: 1 files scanned, 0 skipped (2 error, 4 warning, 0 info) in 1ms
[WARNING] STR002 billing.py:1 4 top-level functions share the prefix `customer_` — consider a `Customer` class or module
[WARNING] STR003 billing.py:1 4 top-level functions take a first parameter named `config` — consider making it instance state
[WARNING] CMT001 billing.py:3 Comment addresses the reader conversationally ('as you requested')
[ERROR ] SEC006 billing.py:4:22 Stripe live key assigned to `STRIPE_SECRET_KEY`
[ERROR ] SEC010 billing.py:4:22 String literal assigned to `STRIPE_SECRET_KEY`, which looks credential-shaped
[WARNING] SEC011 billing.py:4:22 High-entropy string literal (5.1 bits/char) assigned to `STRIPE_SECRET_KEY`(文件路径相对于最近的 .gristmill.toml 显示——demo/ 目录携带了自己的配置,因此此示例的输出独立于顶层项目配置保持稳定。)
注意: GitHub 的推送保护会阻止任何包含真实格式密钥的推送文件——包括在注释或 Markdown 代码块中,本 README 也不例外。
demo/billing.py当前已将密钥替换为None以解除初始推送的阻塞;这是一个 TODO,需要恢复(通过允许列表中的密钥扫描例外)以使演示重新生效。
--json 标志(或 verify MCP 工具,两者都返回)提供完整的结构化形式——文件、行、列、静态建议字符串,以及经过脱敏处理的 evidence 字段(sk_l… (49 chars),绝不包含密钥本身)。
工具
verify
检查源文件中的密钥、结构问题和低质量注释。返回带有文件路径和行号的确定性发现结果。在生成或编辑代码后、将其作为完成品呈现之前调用此工具。
输入:paths(文件或目录,必填),checks(可选的 secrets/structure/comment_slop 子集,默认为全部),severity_floor(可选,默认为 info)。
输出:一个紧凑的人类可读摘要,后跟完整的结构化 JSON——文件、行、列、消息、脱敏证据,以及每个规则的静态建议字符串。发现结果始终按 path、line、rule_id 排序——这种稳定性使运行结果字节相同,并让模型能够直接导航到问题所在。
explain_rule
接受一个 rule_id(例如 SEC001)并返回其原理、捕获内容、遗漏内容以及如何抑制它——与 docs/RULES.md 相同的内容,按需提供,以便 verify 输出保持简洁。
规则
规则 | 检查 | 标题 | 默认严重级别 |
| secrets | AWS 访问密钥 ID | error |
| secrets | AWS 秘密访问密钥 | error |
| secrets | GitHub 令牌 | error |
| secrets | Google API 密钥 | error |
| secrets | Slack 令牌 | error |
| secrets | Stripe 活动密钥 | error |
| secrets | 私钥块 | error |
| secrets | JWT | error |
| secrets | 包含内联密码的数据库 URI | error |
| secrets | 通用凭证形状的赋值 | error |
| secrets | 高熵字符串字面量 | warning |
| structure | 顶级函数过多(默认限制 5 个) | warning |
| structure | 共享函数名前缀(3 个以上函数) | warning |
| structure | 重复的第一个参数名(3 个以上函数) | warning |
| structure | 函数过长(默认限制 60 行) | warning |
| structure | 可变的模块级状态,在文件其他位置被修改 | warning |
| comment_slop | 注释中的对话式称呼 | warning |
| comment_slop | 注释叙述显而易见的内容 | info |
| comment_slop | 短函数上的超大注释块 | info |
| comment_slop | 占位符脚手架未移除 | warning |
| comment_slop | 重复的分节分隔横幅(每个文件 4 个以上) | info |
每个规则的完整原理、假阴性说明和抑制说明:docs/RULES.md。
配置
项目根目录下的 .gristmill.toml,所有键均为可选:
[checks]
enabled = ["secrets", "structure", "comment_slop"]
[structure]
max_top_level_functions = 5
max_function_lines = 60
[secrets]
entropy_threshold = 4.5
[ignore]
paths = ["legacy/**", "vendor/**"]
rules = ["CMT003"].gristmillignore 文件(gitignore 语法)与 [ignore] paths 配合使用。在标记行或其上一行也支持内联抑制:
SUPPRESSED = "ghp_" + "..." # gristmill: ignore SEC003// gristmill: ignore SEC003
const suppressed = "ghp_" + "...";语言支持
Python — 完全支持(stdlib
ast和tokenize)。JavaScript/TypeScript — 完全支持,通过
tree-sitter及编译后的tree-sitter-javascript和tree-sitter-typescript语法实现,而非调用基于 Node 的解析器。这以编译后的 Python 依赖为代价,换取了独立于主机是否安装 Node 的独立性——无论node是否在PATH上,structure和comment_slop都能以相同方式工作,并且提供真正的 AST 而非纯文本回退。其他语言 —
secrets检查仍然运行(基于正则表达式且与语言无关);对于该文件,structure和comment_slop被跳过,并在skipped_paths中报告。
局限性
在信任此工具超出其应得范围之前,请阅读以下内容:
secrets仅捕获有形状或高熵的字符串。 像hunter2这样的低熵人类密码永远不会被标记——没有可靠的方法将其与普通短字符串区分开来。在运行时拼装的凭据(字符串拼接、os.environ.get(...) or "fallback"、base64 解码的片段)对静态文本的正则表达式/熵检查是不可见的。跨文件的结构性问题不可见。
structure一次只查看一个文件;应该跨文件拆分的类,或两个不同模块中的重复逻辑,不在范围内。comment_slop的 CMT002 故意设置得很窄。 它是该集合中假阳性风险最高的规则,因此实现上偏向于保持沉默——它遗漏真实叙述的频率远高于过度标记。确切的子集匹配规则请参见docs/RULES.md。Python 和 JS/TS 之外的语言仅获得 secrets 覆盖。 v1 版本中不对 Go、Rust、Ruby 等语言进行结构或注释分析。
这不是一个 Git 历史密钥扫描器。 它按给定方式检查工作树。已提交但后来从当前文件中删除的密钥不是此工具的关注点(Git 历史扫描器是一个不同的、互补的工具)。
无自动修复。 Gristmill 报告;调用模型决定更改什么以及如何更改。这种分离是有意为之(参见上面的"为什么是 MCP 服务器,而不是技能"),但这意味着单独的
verify调用永远不会修复任何问题。
一个夸大其覆盖范围的工具,比一个坦诚说明其盲点的工具更糟糕——在这里,沉默胜过虚假的信心,就像它胜过嘈杂的发现一样。
路线图
v1 明确不在范围内,按大致优先级排序:
自动修复/补丁生成(目前由调用模型使用
verify发现结果完成)依赖新鲜度和 CVE 检查(需要网络调用包注册表——自然的 v2 功能)
Python 和 JavaScript/TypeScript 之外的语言支持
对已提交但后来删除的密钥进行 Git 历史扫描
托管服务、Web UI 或仪表板
开发
.venv/bin/pip install -e ".[dev]"
.venv/bin/pytest tests/ -q编辑 src/gristmill/rules.py 后重新生成 docs/RULES.md:
.venv/bin/python3 scripts/generate_rules_doc.py测试覆盖(tests/):已知脏数据的黄金文件输出、有并行和无并行情况下的 10 倍确定性、必须产生零发现的假阳性语料库、脱敏处理(原始密钥绝不进入任何输出字段)、以及健壮性(语法无效、二进制、空文件和超大文件永远不会导致运行崩溃)。
许可证
MIT — 参见 LICENSE。
Available Tools
2 toolsexplain_ruleA
Look up a gristmill rule by id (e.g. SEC001, STR002, CMT004): its rationale, what it catches, what it misses, and how to suppress it.
| Name | Required | Description | Default |
|---|---|---|---|
| rule_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It correctly implies a read-only operation ('Look up') and lists the content returned. However, it does not explicitly state that the tool has no side effects, nor does it mention authorization requirements, rate limits, or error handling for invalid rule IDs. A 3 is adequate but leaves gaps.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single sentence that is front-loaded with the action and resource, includes concrete examples in parentheses, and conveys the full return intent. There is no wasted text; every part earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description covers the tool's purpose, the parameter, and the core return values. An output schema exists to handle return type details, so the description does not need to reiterate those. However, it omits mention of what happens if the rule ID is invalid or missing (e.g., error or null response), which would make it more complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0% (no parameter descriptions in the input schema), so the description must compensate. It adds value by specifying the parameter is a 'rule id' and provides examples (SEC001, STR002, CMT004), hinting at a consistent format. However, it does not fully specify the pattern or acceptable formats, leaving ambiguity for the agent.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the verb 'Look up', identifies the resource as a 'gristmill rule', and specifies exactly what information is returned: rationale, what it catches, what it misses, and how to suppress it. This distinguishes it from the sibling tool 'verify', which likely performs a different function.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies usage when you need details about a specific rule (e.g., by its ID), but it does not explicitly state when to use this tool versus the sibling 'verify', nor does it provide guidance on when not to use it or any prerequisites. More specific exclusions or comparisons would improve this dimension.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
verifyA
Inspect source files for secrets, structural problems, and low-quality comments. Returns deterministic findings with file paths and line numbers. Call this after generating or editing code, before presenting it as finished.
| Name | Required | Description | Default |
|---|---|---|---|
| paths | Yes | ||
| checks | No | ||
| severity_floor | No | info |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Without any annotations, the description must disclose behavioral traits fully. It states that findings are 'deterministic' and include 'file paths and line numbers,' which adds value. However, it does not address permissions, side effects (though likely read-only), rate limits, or what happens when no issues are found.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three efficiently structured sentences: purpose, output nature, and usage timing. No redundant or extraneous content. Every sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The presence of an output schema partially offsets the need to describe return values. However, the description does not explain how the three parameters interact or provide examples for common use cases, leaving gaps for a tool invoked after code generation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate. It only implicitly refers to 'paths' via 'source files' and does not explain 'checks' (the enum options) or 'severity_floor' at all. This forces the agent to rely solely on parameter names, which are insufficient.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb ('inspect') and resource ('source files') and enumerates three concrete issue types (secrets, structural problems, low-quality comments). With only one sibling tool 'explain_rule', the purpose is clearly distinct.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly tells when to call this tool: 'after generating or editing code, before presenting it as finished.' It provides clear context but does not mention when not to use it or compare to alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
2 tool updates
v0.1.0- First observed
explain_rule - First observed
verify
TDQS
Scored across 2 tools
The two tools have clearly distinct purposes: one is for static analysis of code, the other for documentation of rules. An agent would not confuse them.
The naming is inconsistent: 'verify' uses a plain verb while 'explain_rule' uses verb_noun pattern. Both are clear in isolation, but the lack of a unified pattern (e.g., 'verify_code' vs 'explain_rule') makes the set feel ad-hoc.
With only 2 tools, the server feels thin for a tool suite called 'gristmill-mcp'. A code analysis server typically needs more tools like listing rules or scanning for specific categories to feel properly scoped.
The server only provides a scan tool and a rule lookup tool, but is missing operations like listing all rules, skipping specific rules, or generating reports. Users cannot discover available rules without knowing their IDs, creating a dead end.
Maintenance
Related MCP Connectors
An MCP server that gives your AI access to the source code and docs of all public github repos
Official DevSpeak MCP server — translate technical text into formal specs from any AI IDE or agent
MCP server teaching AI agents to implement TideCloak: auth, E2EE, IGA, security analysis
Find, compare, and audit software for AI agents. Scored registry of tools and MCP servers.
Related MCP Servers
- AlicenseNot gradedqualityBmaintenanceAn MCP server that provides AI coding agents with AST-accurate, context-budget-aware codebase querying, safety gates, and team policy integration via structured tools and a local plugin layer.104 npm4MIT
- AlicenseNot gradedqualityCmaintenanceAn MCP server for verifying AI-generated code quality, security, and performance, addressing trust gaps in AI coding assistants.MIT
- FlicenseNot gradedqualityCmaintenanceMCP server that helps AI agents inspect Minecraft project evidence (crash logs, mod files, datapacks) before writing development code.2-
- AlicenseNot gradedqualityDmaintenanceAn MCP server that gives AI coding agents structured access to a project's architecture, rules, modules, and technical decisions.MIT