ntc-cdmx-mcp
MCP server for querying Mexico City building regulations (NTC CDMX 2004/2017/2023) with RAG-powered answers, hybrid search, and precise section retrieval, including citations and validated calculations.
README
RAG · Chatbot experto en NTC CDMX (2004 / 2017 / 2023)
Sistema de Retrieval-Augmented Generation sobre las Normas Técnicas Complementarias del Reglamento de Construcciones de la Ciudad de México, con búsqueda híbrida (BM25 + embeddings multilingües + RRF) y citas por edición y numeral.
Estructura
RAG/
├── src/
│ ├── config.py # rutas y mapeo PDF → (edición, norma)
│ ├── extract.py # PDF → páginas de texto por norma (temp/extracted_text/)
│ ├── structure.py # páginas → secciones X.Y.Z (data/corpus/*.json)
│ ├── index_build.py # secciones → catálogo + BM25 + embeddings (data/index/)
│ ├── retrieve.py # retriever híbrido (BM25 + embeddings + RRF + numeral)
│ ├── answer.py # generador de respuestas con LLM (DeepSeek V4 Flash)
│ ├── calc.py # cálculos validados (viento, sismo, combinaciones)
│ ├── evaluate.py # evaluación recall@k con el dataset de 21k Q&A
│ └── finetune_gen.py # genera dataset RAG-formateado para fine-tune del generador
├── app/app.py # interfaz web (Streamlit)
└── scripts/run_all.py # orquesta el pipeline completo
Servidor MCP (para opencode, codex, Claude Desktop, etc.)
El proyecto se expone como un servidor MCP con tres tools:
| Tool | Qué hace |
|---|---|
answer_ntc(query) |
Responde con RAG + LLM (DeepSeek V4 Flash) citando edición, norma y numeral; también resuelve cálculos validados |
search_ntc(query, edition, norm, top_k) |
Devuelve las secciones relevantes en bruto |
get_section(edition, norm, numeral) |
Devuelve el texto completo de un numeral concreto |
Instalación automática (registra el servidor en opencode y/o codex):
.venv\Scripts\python.exe scripts\install_mcp.py # opencode + codex
.venv\Scripts\python.exe scripts\install_mcp.py --opencode # solo opencode
.venv\Scripts\python.exe scripts\install_mcp.py --codex # solo codex
Reinicia opencode/codex y el RAG estará disponible como tools (answer_ntc, etc.).
El servidor lee la API key del proveedor de RAG/.env, la variable de entorno
correspondiente o ~/.config/ntc-cdmx/.env.
Instalación con un solo comando (GitHub + uv)
uvx --from git+https://github.com/Sobrio25/ntc-cdmx-mcp ntc-cdmx-install
Ese comando instala y registra el MCP en opencode, Codex, Command Code y Kilo Code. Reinicia los
clientes y
answer_ntc, search_ntc y get_section estarán disponibles. El índice (BM25 +
embeddings) viaja dentro del paquete; la API key del proveedor se configura en
~/.config/ntc-cdmx/.env.
Para instalar solamente el ejecutable:
uv tool install git+https://github.com/Sobrio25/ntc-cdmx-mcp
Rendimiento al arrancar (evita timeouts del cliente)
El servidor MCP responde el handshake y las tools al instante (~1 s). El índice
y el modelo de embeddings (intfloat/multilingual-e5-small, ~130 MB) se cargan en
segundo plano; la primera llamada responde rápido usando solo BM25 y pasa a la
búsqueda híbrida completa en cuanto el modelo está listo. No se bloquea la
conexión del cliente, así que opencode/codex no marcan el servidor como timeout.
Solo la primera vez en una máquina nueva hay una espera adicional inevitable:
uvx --from git+... construye el paquete (~15 s) y descarga el modelo (~130 MB).
Instalar una sola vez con uv tool install evita la reconstrucción en cada arranque.
Probar el servidor manualmente:
ntc-cdmx # stdio (modo instalado)
.venv\Scripts\python.exe src\mcp_server.py # stdio (modo desarrollo)
Pipeline
# 1) Extraer y estructurar e indexar
.venv/Scripts/python.exe scripts/run_all.py --steps extract structure index
# 2) Evaluar recall del retriever (muestra 400 preguntas del dataset de 21k)
.venv/Scripts/python.exe scripts/run_all.py --steps eval
# 3) Interfaz web
.venv/Scripts/python.exe -m streamlit run app/app.py
Configurar el LLM
Las respuestas usan DeepSeek V4 Flash. Configura el proveedor/API key en
src/answer.py (LLM_MODEL, LLM_BASE_URL).
Sin clave, el chatbot responde con las secciones recuperadas (sin LLM), útil para depurar.
Cálculos validados (src/calc.py)
Si la pregunta pide un cálculo (p. ej. "calcula la presión de viento para Vz=35 m/s"), el motor lo detecta y usa una fórmula verificada contra el texto de la norma, sin pasar por el LLM. Calculadoras incluidas:
| Cálculo | Fórmula | Fuente |
|---|---|---|
| Presión dinámica de viento | qz = 0.52·Vz² (m/s → Pa) | NTC-Viento 2023, §5.1.3 |
| Presión de diseño por viento | pz = 0.47·Cp·VD² | NTC-Viento 2017/2004, §3.2 |
| Fuerza de arrastre de viento | F = 0.47·CD·VD²·A | NTC-Viento 2017/2004, §3.3 |
| Cortante basal mínimo sísmico | Vo,min = amin·Wo | NTC-Sismo 2023, §7.5 |
| Combinación de cargas | Grupo B: 1.3·CM+1.5·CV · Grupo A: 1.5·CM+1.7·CV | NTC-Criterios 2023, §3.4.1 |
Si faltan datos, el chatbot los pide explícitamente.
Fine-tune del generador (src/finetune_gen.py)
Genera un dataset en formato chat donde cada ejemplo incluye el contexto recuperado (para que el generador aprenda a responder desde el contexto, en vez de memorizar las normas):
.venv/Scripts/python.exe src/finetune_gen.py --max 2000 --top_k 8 --require_all
Filtra automáticamente los ejemplos cuya respuesta "gold" NO está sustentada por el contexto recuperado (numerales citados ausentes → se descartan).
Evaluación
El módulo evaluate.py usa tu dataset de Documents\Fine_Tunning\NTC_CDMX\dataset.jsonl:
para cada pregunta con numerales citados en la respuesta "gold", verifica que el numeral
aparezca entre las secciones recuperadas.
Resultado de referencia (muestra 164 preguntas con cita, top-6): recall@q ≈ 0.58. Aproximadamente 18 % de los numerales citados por el dataset no existen en el corpus de su edición (posibles citas erróneas del dataset o huecos de extracción).
Notas técnicas
- Las ediciones 2004 y 2017 vienen en gacetas (varios documentos por PDF); las
fronteras de cada norma están mapeadas en
src/config.py. - El troceo es por sección numerada (nunca por párrafo), preservando fórmulas/tablas.
- Cada sección lleva metadata
{edición, norma, numeral, página}para citar con precisión. - Los PDFs 2023 tienen nombres con caracteres corruptos en disco; el extractor los resuelve por prefijo numérico.
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.