Skip to main content
Glama
mattshuttle

gristmill-mcp

by mattshuttle

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.tomldemo/ имеет свой собственный, поэтому вывод этого примера остается стабильным независимо от конфигурации корневого проекта.)

Примечание: Защита от публикации 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 мог оставаться кратким.

Правила

Правило

Проверка

Название

Серьезность по умолчанию

SEC001

secrets

Идентификатор ключа доступа AWS

error

SEC002

secrets

Секретный ключ доступа AWS

error

SEC003

secrets

Токен GitHub

error

SEC004

secrets

Ключ Google API

error

SEC005

secrets

Токен Slack

error

SEC006

secrets

Live-ключ Stripe

error

SEC007

secrets

Блок приватного ключа

error

SEC008

secrets

JWT

error

SEC009

secrets

URI базы данных с встроенным паролем

error

SEC010

secrets

Присваивание в форме учетных данных

error

SEC011

secrets

Строковый литерал с высокой энтропией

warning

STR001

structure

Слишком много функций верхнего уровня (лимит по умолчанию 5)

warning

STR002

structure

Общий префикс имени функции (3+ функций)

warning

STR003

structure

Повторяющееся имя первого параметра (3+ функций)

warning

STR004

structure

Слишком длинная функция (лимит по умолчанию 60 строк)

warning

STR005

structure

Изменяемое состояние на уровне модуля, изменяемое в другом месте файла

warning

CMT001

comment_slop

Разговорное обращение в комментарии

warning

CMT002

comment_slop

Комментарий описывает очевидное

info

CMT003

comment_slop

Слишком большой блок комментариев для короткой функции

info

CMT004

comment_slop

Оставленный заполнитель-заглушка

warning

CMT005

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.

Install Server
A
license - permissive license
A
quality
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

View all related MCP servers

Related MCP Connectors

  • Hosted MCP server for structured code review passes on human- and AI-written code. Free tier.

  • An MCP server that gives your AI access to the source code and docs of all public github repos

  • MCP server teaching AI agents to implement TideCloak: auth, E2EE, IGA, security analysis

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/mattshuttle/gristmill-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server