Skip to main content
Glama
mattshuttle

gristmill-mcp

by mattshuttle

gristmill-mcp

Un servidor MCP que inspecciona código generado por IA y devuelve una lista determinista de infracciones estructurales y de seguridad, para que un agente de codificación de IA pueda corregir su propia salida antes de que el código llegue a producción.

Grist es el grano que se lleva al molino para ser molido. La salida de IA es grist — materia prima genuinamente valiosa, pero sin procesar. El molino le da estructura.

La IA escribe el grist. Gristmill lo convierte en código que puedes enviar.

Por qué un servidor MCP, no una habilidad

Una habilidad es texto cargado en el contexto del modelo — cambia lo que el modelo sabe. Un servidor MCP es un programa que el modelo ejecuta — cambia lo que el modelo puede hacer.

Las guías de estilo («prefiere clases sobre funciones sueltas») pertenecen a una habilidad. La verificación («este archivo tiene 7 funciones de nivel superior en las líneas 12, 40, 66…») requiere ejecutar código contra el archivo. Un modelo que lee su propia salida y razona «esto parece tener demasiadas funciones» es una suposición disfrazada de observación — no tiene una verdad objetiva sobre qué significa «demasiadas» en este archivo, ni una forma fiable de contar. Gristmill analiza el AST y cuenta. Esa distinción — instrucción versus ejecución — es la razón por la que esto existe como servidor en lugar de un párrafo de consejo.

El servidor nunca llama a un LLM, nunca varía entre ejecuciones sobre la misma entrada y nunca emite una puntuación de confianza. Misma entrada → salida byte-idéntica, siempre. Esa determinismo es el producto completo. La capa de IA se sitúa por encima de este servidor, consumiendo sus hallazgos y decidiendo qué hacer al respecto — el trabajo del servidor termina al informar hechos con números de línea.

Related MCP server: code-verify-mcp

Instalación

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

Claude Code

Regístralo con la CLI, apuntando al script de consola del venv:

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

O añádelo directamente a tu configuración de MCP (.mcp.json en un proyecto, o tu configuración global de Claude Code):

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

Otros clientes MCP

Cualquier cliente MCP basado en stdio puede lanzar el mismo binario — gristmill-mcp (o python3 -m gristmill.server dentro del venv) habla el transporte stdio MCP estándar sin configuración específica del cliente.

Línea de comandos (sin cliente MCP)

Para pruebas locales, o para reproducir el ejemplo detallado a continuación, una CLI ligera envuelve el mismo motor:

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

Ejemplo detallado

demo/billing.py, un primer borrador sin editar de un helper de Stripe para facturación:

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

Salida con un literal en forma de clave real de Stripe en lugar del None anterior:

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`

(Las rutas de archivo se muestran relativas al .gristmill.toml más cercano — demo/ lleva el suyo propio para que la salida de este ejemplo se mantenga estable independientemente de la configuración del proyecto de nivel superior.)

Nota: La protección de push de GitHub bloquea cualquier archivo enviado que contenga un secreto en formato real — incluso en un comentario o un bloque de código markdown, incluido este README. demo/billing.py actualmente tiene la clave reemplazada por None para desbloquear el push inicial; esto es un TODO para restaurarlo (mediante una excepción de escaneo de secretos en lista blanca) para que la demo vuelva a estar activa.

La bandera --json (o la herramienta MCP verify, que devuelve ambas) proporciona la forma estructurada completa — archivo, línea, columna, una cadena de sugerencia estática y un campo evidence censurado (sk_l… (49 caracteres), nunca la clave en sí).

Herramientas

verify

Inspecciona archivos fuente en busca de secretos, problemas estructurales y comentarios de baja calidad. Devuelve hallazgos deterministas con rutas de archivo y números de línea. Llama a esto después de generar o editar código, antes de presentarlo como terminado.

Entrada: paths (archivos o directorios, obligatorio), checks (subconjunto opcional de secrets/structure/comment_slop, por defecto todos), severity_floor (opcional, por defecto info).

Salida: un resumen compacto legible por humanos, seguido del JSON estructurado completo — archivo, línea, columna, mensaje, evidencia censurada y una cadena de sugerencia estática por regla. Los hallazgos se ordenan por path, luego line, luego rule_id, siempre — esa estabilidad es lo que hace que las ejecuciones sean byte-idénticas y permite que un modelo navegue directamente al problema.

explain_rule

Toma un rule_id (ej. SEC001) y devuelve su fundamento, qué captura, qué omite y cómo suprimirlo — el mismo contenido que docs/RULES.md, servido bajo demanda para que la salida de verify pueda mantenerse concisa.

Reglas

Regla

Comprobación

Título

Gravedad por defecto

SEC001

secrets

ID de clave de acceso de AWS

error

SEC002

secrets

Clave de acceso secreta de AWS

error

SEC003

secrets

Token de GitHub

error

SEC004

secrets

Clave de API de Google

error

SEC005

secrets

Token de Slack

error

SEC006

secrets

Clave en vivo de Stripe

error

SEC007

secrets

Bloque de clave privada

error

SEC008

secrets

JWT

error

SEC009

secrets

URI de base de datos con contraseña en línea

error

SEC010

secrets

Asignación genérica con forma de credencial

error

SEC011

secrets

Literal de cadena de alta entropía

warning

STR001

structure

Demasiadas funciones de nivel superior (límite por defecto 5)

warning

STR002

structure

Prefijo de nombre de función compartido (3+ funciones)

warning

STR003

structure

Nombre de primer parámetro repetido (3+ funciones)

warning

STR004

structure

Función demasiado larga (límite por defecto 60 líneas)

warning

STR005

structure

Estado mutable a nivel de módulo, mutado en otra parte del archivo

warning

CMT001

comment_slop

Dirección conversacional en comentario

warning

CMT002

comment_slop

El comentario narra lo obvio

info

CMT003

comment_slop

Bloque de comentario demasiado grande en una función corta

info

CMT004

comment_slop

Andamio de marcador de posición dejado en su lugar

warning

CMT005

comment_slop

Banners repetidos de separación de secciones (4+ por archivo)

info

Fundamento completo, notas de falsos negativos e instrucciones de supresión por regla: docs/RULES.md.

Configuración

.gristmill.toml en la raíz del proyecto, todas las claves opcionales:

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

Un archivo .gristmillignore (sintaxis de gitignore) funciona junto con [ignore] paths. También se respeta la supresión en línea en la línea marcada o en la línea superior:

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

Soporte de lenguajes

  • Python — soporte completo (stdlib ast y tokenize).

  • JavaScript/TypeScript — soporte completo, mediante tree-sitter con las gramáticas compiladas tree-sitter-javascript y tree-sitter-typescript, en lugar de delegar a un analizador basado en Node. Esto intercambia una dependencia compilada de Python por independencia de que el host tenga Node instalado — structure y comment_slop funcionan de manera idéntica independientemente de si node está en PATH, y proporciona un AST real en lugar de una alternativa solo de texto.

  • Cualquier otro — la comprobación secrets aún se ejecuta (está basada en regex y es independiente del lenguaje); structure y comment_slop se omiten para ese archivo, informado en skipped_paths.

Limitaciones

Lee esto antes de confiar en la herramienta más de lo que se ha ganado:

  • secrets solo captura cadenas con forma o de alta entropía. Una contraseña humana de baja entropía como hunter2 nunca será marcada — no hay una forma fiable de distinguirla de una cadena corta normal. Las credenciales ensambladas en tiempo de ejecución (concatenación de cadenas, os.environ.get(...) or "fallback", piezas decodificadas en base64) son invisibles para un pase de regex/entropía sobre texto estático.

  • Los problemas estructurales que abarcan varios archivos son invisibles. structure mira un archivo a la vez; una clase que debería dividirse entre archivos, o lógica duplicada en dos módulos diferentes, está fuera del alcance.

  • El CMT002 de comment_slop es deliberadamente estrecho. Es la regla con mayor riesgo de falsos positivos del conjunto, por lo que está implementada para sesgar fuertemente hacia el silencio — pasará por alto narraciones reales con mucha más frecuencia de la que marcará en exceso. Consulta docs/RULES.md para la regla exacta de coincidencia de subconjuntos.

  • Los lenguajes fuera de Python y JS/TS solo reciben cobertura de secretos. Sin análisis estructural o de comentarios para Go, Rust, Ruby, etc. en v1.

  • Esto no es un escáner de secretos en el historial de git. Inspecciona el árbol de trabajo tal como se proporciona. Una clave que fue confirmada y luego eliminada del archivo actual no es preocupación de esta herramienta (un escáner de historial de git es una herramienta diferente y complementaria).

  • Sin corrección automática. Gristmill informa; el modelo que llama decide qué y cómo cambiar. Esa división es intencional (ver «Por qué un servidor MCP, no una habilidad» arriba), pero significa que una llamada a verify por sí sola nunca arregla nada.

Una herramienta que sobrevende su cobertura es peor que una que es sincera sobre sus puntos ciegos — el silencio supera a la falsa confianza aquí tanto como supera a los hallazgos ruidosos.

Hoja de ruta

Explícitamente fuera del alcance para v1, en orden de prioridad aproximado:

  • Corrección automática / generación de parches (el modelo que llama hace esto hoy, usando los hallazgos de verify)

  • Comprobación de frescura de dependencias y CVE (necesita llamadas de red a registros de paquetes — un v2 natural)

  • Soporte de lenguajes más allá de Python y JavaScript/TypeScript

  • Escaneo de historial de git para secretos que fueron confirmados y luego eliminados

  • Un servicio alojado, interfaz web o panel de control

Desarrollo

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

Regenera docs/RULES.md después de editar src/gristmill/rules.py:

.venv/bin/python3 scripts/generate_rules_doc.py

Las pruebas cubren (tests/): salida de archivo dorado para un directorio de fixtures conocido como sucio, determinismo 10x con y sin paralelismo, un corpus de falsos positivos que debe producir cero hallazgos, censura (ningún secreto bruto llega a ningún campo de salida), y resiliencia (sintaxis inválida, archivos binarios, vacíos y demasiado grandes nunca fallan una ejecución).

Licencia

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