Skip to main content
Glama
mattshuttle

gristmill-mcp

by mattshuttle

gristmill-mcp

Ein MCP-Server, der KI-generierten Code inspiziert und eine deterministische Liste von strukturellen und sicherheitsrelevanten Verstößen zurückgibt, damit ein KI-Coding-Agent seine eigenen Ergebnisse korrigieren kann, bevor der Code landet.

Grist ist Getreide, das zum Mahlen in eine Mühle gebracht wird. KI-Ausgabe ist Grist — wirklich wertvoller Rohstoff, aber unverarbeitet. Die Mühle gibt ihm Struktur.

KI schreibt das Grist. Gristmill macht daraus Code, den Sie ausliefern können.

Warum ein MCP-Server und kein Skill

Ein Skill ist Text, der in den Kontext eines Modells geladen wird — er verändert, was das Modell weiß. Ein MCP-Server ist ein Programm, das das Modell ausführt — er verändert, was das Modell tun kann.

Stilrichtlinien („bevorzuge Klassen gegenüber lockeren Funktionen“) gehören in einen Skill. Überprüfung („diese Datei hat 7 Funktionen auf oberster Ebene in den Zeilen 12, 40, 66…“) erfordert die Ausführung von Code gegen die Datei. Ein Modell, das seine eigene Ausgabe liest und argumentiert, dass „dies zu viele Funktionen zu haben scheint“, ist eine Vermutung im Gewand einer Beobachtung — es hat keine Grundwahrheit dafür, was „zu viele“ in dieser Datei bedeutet, und keine zuverlässige Möglichkeit zu zählen. Gristmill parst den AST und zählt. Diese Unterscheidung — Anweisung versus Ausführung — ist der Grund, warum dies als Server existiert und nicht als Absatz eines Ratschlags.

Der Server ruft niemals ein LLM auf, variiert nie zwischen Läufen mit derselben Eingabe und gibt nie einen Konfidenzwert aus. Gleiche Eingabe → byteidentische Ausgabe, jedes Mal. Diese Determiniertheit ist das gesamte Produkt. Die KI-Schicht sitzt über diesem Server, konsumiert seine Ergebnisse und entscheidet, was damit zu tun ist — die Aufgabe des Servers endet mit der Meldung von Fakten mit Zeilennummern.

Related MCP server: code-verify-mcp

Install

git clone <this repo> gristmill-mcp
cd gristmill-mcp
python3 -m venv .venv
.venv/bin/pip install -e .

Claude Code

Registrieren Sie es mit der CLI, die auf das Konsolenskript der venv verweist:

claude mcp add gristmill -- /absolute/path/to/gristmill-mcp/.venv/bin/gristmill-mcp

Oder fügen Sie es direkt zu Ihrer MCP-Konfiguration hinzu (.mcp.json in einem Projekt oder Ihrer globalen Claude Code-Konfiguration):

{
  "mcpServers": {
    "gristmill": {
      "command": "/absolute/path/to/gristmill-mcp/.venv/bin/gristmill-mcp"
    }
  }
}

Andere MCP-Clients

Jeder stdio-basierte MCP-Client kann dieselbe Binärdatei starten — gristmill-mcp (oder python3 -m gristmill.server innerhalb der venv) spricht den standardmäßigen MCP-stdio-Transport ohne clientspezifische Konfiguration.

Kommandozeile (kein MCP-Client)

Für lokale Tests oder um das unten stehende ausgearbeitete Beispiel zu reproduzieren, umhüllt eine dünne CLI dieselbe Engine:

.venv/bin/gristmill-verify path/to/file_or_dir [--checks secrets structure comment_slop] [--severity-floor warning] [--json]

Ausgearbeitetes Beispiel

demo/billing.py, ein unredigierter erster Entwurf eines Stripe-Billing-Helfers:

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

Ausgabe mit einem echten Stripe-Live-Key-förmigen Literal anstelle des None oben:

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`

(Dateipfade werden relativ zum nächsten .gristmill.toml angezeigt — demo/ hat sein eigenes, sodass die Ausgabe dieses Beispiels unabhängig von der übergeordneten Projektkonfiguration stabil bleibt.)

Hinweis: Der Push-Schutz von GitHub blockiert jede gepushte Datei, die ein Secret im echten Format enthält — einschließlich in einem Kommentar oder einem Markdown-Codeblock, dieser README eingeschlossen. demo/billing.py hat derzeit den Schlüssel durch None ersetzt, um den initialen Push zu ermöglichen; dies ist ein TODO, um es wiederherzustellen (über eine auf die Whitelist gesetzte Ausnahme der Secret-Prüfung), damit die Demo wieder live ist.

Das --json-Flag (oder das verify-MCP-Tool, das beides zurückgibt) liefert die vollständige strukturierte Form — Datei, Zeile, Spalte, einen statischen Vorschlagsstring und ein redigiertes evidence-Feld (sk_l… (49 Zeichen), niemals der Schlüssel selbst).

Tools

verify

Untersucht Quelldateien auf Secrets, strukturelle Probleme und minderwertige Kommentare. Gibt deterministische Ergebnisse mit Dateipfaden und Zeilennummern zurück. Rufen Sie dies auf, nachdem Sie Code generiert oder bearbeitet haben, bevor Sie ihn als fertig präsentieren.

Eingabe: paths (Dateien oder Verzeichnisse, erforderlich), checks (optionaler Teil von secrets/structure/comment_slop, Standard alle), severity_floor (optional, Standard info).

Ausgabe: eine kompakte, für Menschen lesbare Zusammenfassung, gefolgt vom vollständigen strukturierten JSON — Datei, Zeile, Spalte, Meldung, redigierter Beweis und ein statischer Vorschlagstring pro Regel. Die Ergebnisse werden immer nach path, dann line, dann rule_id sortiert — diese Stabilität ist es, die Läufe byteidentisch macht und einem Modell ermöglicht, direkt zum Problem zu navigieren.

explain_rule

Nimmt eine rule_id (z. B. SEC001) entgegen und gibt deren Begründung zurück, was sie erfasst, was sie übersieht und wie sie unterdrückt werden kann — derselbe Inhalt wie docs/RULES.md, auf Abruf bereitgestellt, damit die verify-Ausgabe kurz bleiben kann.

Regeln

Regel

Prüfung

Titel

Standardschwere

SEC001

secrets

AWS-Zugriffsschlüssel-ID

error

SEC002

secrets

AWS-Geheimzugriffsschlüssel

error

SEC003

secrets

GitHub-Token

error

SEC004

secrets

Google-API-Schlüssel

error

SEC005

secrets

Slack-Token

error

SEC006

secrets

Stripe-Live-Schlüssel

error

SEC007

secrets

Privater Schlüsselblock

error

SEC008

secrets

JWT

error

SEC009

secrets

Datenbank-URI mit Inline-Passwort

error

SEC010

secrets

Generische, wie Credentials geformte Zuweisung

error

SEC011

secrets

Stringliteral mit hoher Entropie

warning

STR001

structure

Zu viele Funktionen auf oberster Ebene (Standardlimit 5)

warning

STR002

structure

Geteiltes Funktionsnamen-Präfix (3+ Funktionen)

warning

STR003

structure

Wiederholter erster Parametername (3+ Funktionen)

warning

STR004

structure

Funktion zu lang (Standardlimit 60 Zeilen)

warning

STR005

structure

Veränderbarer Zustand auf Modulebene, der an anderer Stelle in der Datei verändert wird

warning

CMT001

comment_slop

Konversationelle Ansprache im Kommentar

warning

CMT002

comment_slop

Kommentar beschreibt das Offensichtliche

info

CMT003

comment_slop

Übergroßer Kommentarblock bei einer kurzen Funktion

info

CMT004

comment_slop

Platzhaltergerüst an Ort und Stelle belassen

warning

CMT005

comment_slop

Wiederholte Abschnittstrenn-Banner (4+ pro Datei)

info

Vollständige Begründung, Hinweise zu falsch Negativen und Unterdrückungsanweisungen pro Regel: docs/RULES.md.

Konfiguration

.gristmill.toml im Projektstammverzeichnis, alle Schlüssel optional:

[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"]

Eine .gristmillignore-Datei (gitignore-Syntax) funktioniert zusammen mit [ignore] paths. Die Inline-Unterdrückung wird auch in der markierten Zeile oder der Zeile darüber berücksichtigt:

SUPPRESSED = "ghp_" + "..."  # gristmill: ignore SEC003
// gristmill: ignore SEC003
const suppressed = "ghp_" + "...";

Sprachunterstützung

  • Python — vollständige Unterstützung (stdlib ast und tokenize).

  • JavaScript/TypeScript — vollständige Unterstützung über tree-sitter mit den kompilierten Grammatiken tree-sitter-javascript und tree-sitter-typescript, anstatt einen Node-basierten Parser auszulagern. Dies tauscht eine kompilierte Python-Abhängigkeit gegen die Unabhängigkeit davon, ob der Host überhaupt Node installiert hat — structure und comment_slop funktionieren identisch, unabhängig davon, ob node im PATH ist, und liefern einen echten AST anstelle eines Nur-Text-Fallbacks.

  • Alles andere — die secrets-Prüfung läuft weiterhin (sie ist regexbasiert und sprachunabhängig); structure und comment_slop werden für diese Datei übersprungen und in skipped_paths gemeldet.

Einschränkungen

Lesen Sie dies, bevor Sie dem Tool mehr vertrauen, als es verdient hat:

  • secrets erfasst nur geformte oder hochentropische Zeichenketten. Ein niedrigentropisches menschliches Passwort wie hunter2 wird niemals markiert — es gibt keine zuverlässige Möglichkeit, es von einer gewöhnlichen kurzen Zeichenkette zu unterscheiden. Anmeldedaten, die zur Laufzeit zusammengesetzt werden (Zeichenkettenverkettung, os.environ.get(...) or "fallback", base64-dekodierte Teile) sind für einen Regex-/Entropie-Durchlauf über statischen Text unsichtbar.

  • Strukturprobleme, die sich über Dateien erstrecken, sind unsichtbar. structure betrachtet eine Datei nach der anderen; eine Klasse, die auf mehrere Dateien aufgeteilt werden sollte, oder doppelte Logik in zwei verschiedenen Modulen, liegt außerhalb des Rahmens.

  • CMT002 von comment_slop ist bewusst eng gefasst. Es ist die Regel mit dem höchsten Risiko für falsch Positive im Set, daher ist sie so implementiert, dass sie stark zur Stille neigt — sie wird echte Erzählungen weitaus häufiger übersehen, als sie übermäßig kennzeichnet. Siehe docs/RULES.md für die genaue Subset-Match-Regel.

  • Sprachen außerhalb von Python und JS/TS erhalten nur Secret-Abdeckung. Keine Struktur- oder Kommentaranalyse für Go, Rust, Ruby usw. in v1.

  • Dies ist kein Scanner für Secrets in der Git-Historie. Er untersucht den Arbeitsbaum wie gegeben. Ein Schlüssel, der eingecheckt und später aus der aktuellen Datei entfernt wurde, ist nicht das Anliegen dieses Tools (ein Git-Verlaufsscanner ist ein anderes, ergänzendes Tool).

  • Keine automatische Korrektur. Gristmill meldet; das aufrufende Modell entscheidet, was und wie geändert wird. Diese Trennung ist beabsichtigt (siehe „Why an MCP server, not a skill“ oben), aber es bedeutet, dass ein einzelner verify-Aufruf niemals etwas repariert.

Ein Tool, das seine Abdeckung überverkauft, ist schlimmer als eines, das seine blinden Flecken offenlegt — Stille schlägt falsches Vertrauen hier so sehr, wie es laute Ergebnisse schlägt.

Roadmap

Explizit nicht im Umfang von v1, in grober Prioritätsreihenfolge:

  • Automatische Korrektur / Patch-Generierung (das aufrufende Modell erledigt dies heute unter Verwendung der verify-Ergebnisse)

  • Aktualität von Abhängigkeiten und CVE-Prüfung (benötigt Netzwerkaufrufe an Paketregister — eine natürliche v2)

  • Sprachunterstützung über Python und JavaScript/TypeScript hinaus

  • Scannen der Git-Historie nach Secrets, die eingecheckt und später entfernt wurden

  • Ein gehosteter Dienst, eine Weboberfläche oder ein Dashboard

Entwicklung

.venv/bin/pip install -e ".[dev]"
.venv/bin/pytest tests/ -q

Regenerieren Sie docs/RULES.md nach dem Bearbeiten von src/gristmill/rules.py:

.venv/bin/python3 scripts/generate_rules_doc.py

Tests decken ab (tests/): Golden-File-Ausgabe für ein bekanntes, verschmutztes Fixture-Verzeichnis, 10-fache Determiniertheit mit und ohne Parallelisierung, ein Korpus falsch-positiver Fälle, der null Ergebnisse liefern muss, Schwärzung (kein rohes Secret gelangt jemals in ein Ausgabefeld) und Robustheit (ungültige Syntax, Binär-, leere und überdimensionierte Dateien stürzen nie einen Lauf ab).

Lizenz

MIT — siehe 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