gristmill-mcp
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-mcpOder 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.pyAusgabe 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.pyhat derzeit den Schlüssel durchNoneersetzt, 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 |
| secrets | AWS-Zugriffsschlüssel-ID | error |
| secrets | AWS-Geheimzugriffsschlüssel | error |
| secrets | GitHub-Token | error |
| secrets | Google-API-Schlüssel | error |
| secrets | Slack-Token | error |
| secrets | Stripe-Live-Schlüssel | error |
| secrets | Privater Schlüsselblock | error |
| secrets | JWT | error |
| secrets | Datenbank-URI mit Inline-Passwort | error |
| secrets | Generische, wie Credentials geformte Zuweisung | error |
| secrets | Stringliteral mit hoher Entropie | warning |
| structure | Zu viele Funktionen auf oberster Ebene (Standardlimit 5) | warning |
| structure | Geteiltes Funktionsnamen-Präfix (3+ Funktionen) | warning |
| structure | Wiederholter erster Parametername (3+ Funktionen) | warning |
| structure | Funktion zu lang (Standardlimit 60 Zeilen) | warning |
| structure | Veränderbarer Zustand auf Modulebene, der an anderer Stelle in der Datei verändert wird | warning |
| comment_slop | Konversationelle Ansprache im Kommentar | warning |
| comment_slop | Kommentar beschreibt das Offensichtliche | info |
| comment_slop | Übergroßer Kommentarblock bei einer kurzen Funktion | info |
| comment_slop | Platzhaltergerüst an Ort und Stelle belassen | warning |
| 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
astundtokenize).JavaScript/TypeScript — vollständige Unterstützung über
tree-sittermit den kompilierten Grammatikentree-sitter-javascriptundtree-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 —structureundcomment_slopfunktionieren identisch, unabhängig davon, obnodeimPATHist, 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);structureundcomment_slopwerden für diese Datei übersprungen und inskipped_pathsgemeldet.
Einschränkungen
Lesen Sie dies, bevor Sie dem Tool mehr vertrauen, als es verdient hat:
secretserfasst nur geformte oder hochentropische Zeichenketten. Ein niedrigentropisches menschliches Passwort wiehunter2wird 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.
structurebetrachtet 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_slopist 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. Siehedocs/RULES.mdfü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/ -qRegenerieren Sie docs/RULES.md nach dem Bearbeiten von src/gristmill/rules.py:
.venv/bin/python3 scripts/generate_rules_doc.pyTests 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.
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 gradedqualityCmaintenanceAn 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.238 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