gristmill-mcp
gristmill-mcp
MCP-сервер, который проверяет сгенерированный ИИ код и возвращает детерминированный список структурных нарушений и нарушений безопасности, чтобы ИИ-агент мог исправить свой собственный вывод до того, как код попадет в репозиторий.
Grist — это зерно, привезенное на мельницу для помола. Вывод ИИ — это grist, действительно ценный сырой материал, но необработанный. Мельница придает ему структуру.
ИИ пишет grist. Gristmill превращает его в код, который можно отправлять.
Почему MCP-сервер, а не навык
Навык — это текст, загруженный в контекст модели — он меняет то, что модель знает. MCP-сервер — это программа, которую модель выполняет — он меняет то, что модель может сделать.
Рекомендации по стилю («предпочитайте классы свободным функциям») относятся к навыку. Верификация («в этом файле 7 функций верхнего уровня на строках 12, 40, 66…») требует выполнения кода для файла. Модель, читающая свой собственный вывод и рассуждающая «похоже, здесь слишком много функций» — это догадка, замаскированная под наблюдение — у нее нет истинного понимания того, что означает «слишком много» в этом файле, и нет надежного способа подсчитать. Gristmill парсит AST и считает. Это различие — инструкция против выполнения — вот почему это существует как сервер, а не как абзац советов.
Сервер никогда не вызывает LLM, никогда не меняется между запусками на одних и тех же входных данных и никогда не выдает оценку уверенности. Те же входные данные → побайтово идентичный вывод, каждый раз. Эта детерминированность и есть весь продукт. Уровень ИИ находится над этим сервером, потребляя его результаты и решая, что с ними делать — работа сервера заканчивается на сообщении фактов с номерами строк.
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-клиенты
Любой MCP-клиент на основе stdio может запустить тот же бинарный файл — 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-live-ключа вместо 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 (или MCP-инструмент verify, который возвращает оба) дает полную структурированную форму — файл, строка, столбец, статическая строка предложения и отредактированное поле evidence (sk_l… (49 символов), никогда сам ключ).
Инструменты
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 | error |
| secrets | Секретный ключ доступа AWS | error |
| secrets | Токен GitHub | error |
| secrets | Ключ Google API | error |
| secrets | Токен Slack | error |
| secrets | Live-ключ 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 на хосте —structureиcomment_slopработают одинаково, независимо от того, есть лиnodeвPATH, и это дает настоящий AST вместо текстового запасного варианта.Все остальное — проверка
secretsвсе еще выполняется (она основана на регулярных выражениях и не зависит от языка);structureиcomment_slopпропускаются для этого файла, о чем сообщается вskipped_paths.
Ограничения
Прочтите это, прежде чем доверять инструменту больше, чем он заслужил:
secretsловит только строки определенной формы или с высокой энтропией. Пароль с низкой энтропией, такой какhunter2, никогда не будет отмечен — нет надежного способа отличить его от обычной короткой строки. Учетные данные, собранные во время выполнения (конкатенация строк,os.environ.get(...) or "fallback", части, декодированные из base64), невидимы для прохода по регулярным выражениям/энтропии статического текста.Структурные проблемы, охватывающие несколько файлов, невидимы.
structureсмотрит на один файл за раз; класс, который следует разделить на несколько файлов, или дублированная логика в двух разных модулях, выходят за рамки.comment_slop's CMT002 намеренно узок. Это правило с самым высоким риском ложноположительных результатов в наборе, поэтому оно реализовано со смещением в сторону молчания — оно будет пропускать реальные повествования гораздо чаще, чем выдавать ложные срабатывания. См.docs/RULES.mdдля точного правила сопоставления подмножеств.Языки, отличные от Python и JS/TS, получают покрытие только для секретов. Никакого структурного анализа или анализа комментариев для Go, Rust, Ruby и т.д. в v1.
Это не сканер секретов в истории git. Он проверяет рабочее дерево как есть. Ключ, который был закоммичен, а затем удален из текущего файла, не является задачей этого инструмента (сканер истории git — это другой, дополняющий инструмент).
Нет автоисправления. Gristmill сообщает; вызывающая модель решает, что и как менять. Это разделение намеренно (см. «Почему MCP-сервер, а не навык» выше), но это означает, что один вызов
verifyникогда ничего не исправляет.
Инструмент, который переоценивает свое покрытие, хуже, чем тот, который честно говорит о своих слепых зонах — молчание здесь лучше ложной уверенности так же, как и шумные находки.
План развития
Явно выходит за рамки v1, в примерном порядке приоритета:
Автоисправление / генерация патчей (вызывающая модель делает это сегодня, используя результаты
verify)Проверка свежести зависимостей и CVE (требует сетевых вызовов к реестрам пакетов — естественный v2)
Поддержка языков помимо Python и JavaScript/TypeScript
Сканирование истории git на предмет секретов, которые были закоммичены, а затем удалены
Хостинг-сервис, веб-интерфейс или панель мониторинга
Разработка
.venv/bin/pip install -e ".[dev]"
.venv/bin/pytest tests/ -qПерегенерируйте docs/RULES.md после редактирования src/gristmill/rules.py:
.venv/bin/python3 scripts/generate_rules_doc.pyТесты покрывают (tests/): вывод golden-файла для заведомо грязной директории фикстур, 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