gristmill-mcp
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-mcpO 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.pySalida 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.pyactualmente tiene la clave reemplazada porNonepara 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 |
| secrets | ID de clave de acceso de AWS | error |
| secrets | Clave de acceso secreta de AWS | error |
| secrets | Token de GitHub | error |
| secrets | Clave de API de Google | error |
| secrets | Token de Slack | error |
| secrets | Clave en vivo de Stripe | error |
| secrets | Bloque de clave privada | error |
| secrets | JWT | error |
| secrets | URI de base de datos con contraseña en línea | error |
| secrets | Asignación genérica con forma de credencial | error |
| secrets | Literal de cadena de alta entropía | warning |
| structure | Demasiadas funciones de nivel superior (límite por defecto 5) | warning |
| structure | Prefijo de nombre de función compartido (3+ funciones) | warning |
| structure | Nombre de primer parámetro repetido (3+ funciones) | warning |
| structure | Función demasiado larga (límite por defecto 60 líneas) | warning |
| structure | Estado mutable a nivel de módulo, mutado en otra parte del archivo | warning |
| comment_slop | Dirección conversacional en comentario | warning |
| comment_slop | El comentario narra lo obvio | info |
| comment_slop | Bloque de comentario demasiado grande en una función corta | info |
| comment_slop | Andamio de marcador de posición dejado en su lugar | warning |
| 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
astytokenize).JavaScript/TypeScript — soporte completo, mediante
tree-sittercon las gramáticas compiladastree-sitter-javascriptytree-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 —structureycomment_slopfuncionan de manera idéntica independientemente de sinodeestá enPATH, y proporciona un AST real en lugar de una alternativa solo de texto.Cualquier otro — la comprobación
secretsaún se ejecuta (está basada en regex y es independiente del lenguaje);structureycomment_slopse omiten para ese archivo, informado enskipped_paths.
Limitaciones
Lee esto antes de confiar en la herramienta más de lo que se ha ganado:
secretssolo captura cadenas con forma o de alta entropía. Una contraseña humana de baja entropía comohunter2nunca 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.
structuremira 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_slopes 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. Consultadocs/RULES.mdpara 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
verifypor 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/ -qRegenera docs/RULES.md después de editar src/gristmill/rules.py:
.venv/bin/python3 scripts/generate_rules_doc.pyLas 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.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Tools
Related MCP Servers
- Alicense-qualityAmaintenanceAn 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.5724MIT
- Alicense-qualityDmaintenanceAn MCP server for verifying AI-generated code quality, security, and performance, addressing trust gaps in AI coding assistants.MIT
- Flicense-qualityCmaintenanceMCP server that helps AI agents inspect Minecraft project evidence (crash logs, mod files, datapacks) before writing development code.3
- Alicense-qualityCmaintenanceAn MCP server that gives AI coding agents structured access to a project's architecture, rules, modules, and technical decisions.MIT
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
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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