Lumenco Catalog MCP Server
Catálogo Lumenco (Fase 1 scraper + Fase 2 MCP)
Este repositorio tiene dos capas:
La Fase 1 extrae
https://en.staging.lumenco.ca/a PostgreSQL.La Fase 2 expone ese catálogo a través de un servidor de Protocolo de Contexto de Modelo (MCP) de solo lectura para que Claude pueda recuperar productos, especificaciones, listados y candidatos de recomendación sin navegar por Lumenco.
CLAUDE
│ MCP / HTTPS
▼
Lumenco Product Database (Streamable HTTP)
│ tools → services → repositories
▼
PostgreSQL (Phase 1 catalog)La Fase 1 extrae. La Fase 2 expone. Claude razona.
El servidor MCP nunca extrae Lumenco, nunca descarga PDFs de especificaciones, nunca llama a un LLM y nunca escribe en la base de datos.
Cómo es el sitio
Lumenco staging es una tienda Magento 2.
Área | Comportamiento |
Marcas |
|
Listados de marcas |
|
Productos | URLs canónicas como |
Hojas de especificaciones | Normalmente PDFs del mismo origen en |
Mapa del sitio |
|
GraphQL |
|
Obtención | Las páginas de producto se renderizan en el servidor. El |
El rastreador permanece en en.staging.lumenco.ca. Los PDFs de hojas de especificaciones externas pueden descargarse como documentos de producto. Se ignoran los anuncios, análisis, carrito, pago y URLs de redes sociales.
robots.txt está escrito para motores de búsqueda públicos (User-agent: * no permite la mayoría de las rutas excepto /brand y algunas páginas CMS). Este scraper es una ingesta de catálogo autorizada contra staging, por lo que ROBOTS_TXT_OBEY está en false por defecto. Establézcalo en true si desea que Scrapling respete ese archivo.
Related MCP server: Catalog Services MCP Server
Estructura del proyecto
scraper/ Phase 1 Scrapling crawler
config.py
spider.py
discovery.py
fetcher.py
cli.py
selectors/
parsers/
pipelines/
database/ shared SQLAlchemy models + repositories
utils/
app/ Phase 2 read-only MCP server
server.py Streamable HTTP + /health
config.py
auth/middleware.py bearer token (replaceable with OAuth)
tools/ MCP tool layer
services/ catalog / product / search / recommendations
repositories/ read-only queries over Phase 1 tables
schemas/
database/session.py pooled, read-only sessions
alembic/ PostgreSQL migrations
tests/
scripts/create_readonly_user.sql1. Instalar dependencias
Se requiere Python 3.10+.
python -m venv .venv
# Windows
.venv\Scripts\activate
# macOS / Linux
source .venv/bin/activate
pip install -r requirements.txtLos extras HTTP/navegador de Scrapling se incluyen a través de scrapling[fetchers]. Si necesita el respaldo del navegador (DynamicFetcher), instale los binarios del navegador:
scrapling installOCR opcional para PDFs de especificaciones escaneados o solo imagen:
pip install pytesseract Pillow
# plus a Tesseract OCR engine on the hostEl OCR está desactivado por defecto (ENABLE_OCR=false). Los PDFs basados en imagen se almacenan y se marcan como ocr_required en lugar de guardarse como texto vacío.
2. Configurar PostgreSQL
La configuración local más rápida:
docker compose up -d postgresEso inicia PostgreSQL 16 con:
usuario:
lumencocontraseña:
lumencobase de datos:
lumencopuerto del host:
5433(el puerto del contenedor permanece en5432; 5433 evita que una instalación de PostgreSQL de Windows que ya usa 5432)
Copie la configuración de entorno:
copy .env.example .env # Windows
cp .env.example .env # macOS / LinuxCadena de conexión predeterminada:
DATABASE_URL=postgresql+psycopg2://lumenco:lumenco@127.0.0.1:5433/lumenco
LUMENCO_BASE_URL=https://en.staging.lumenco.ca/Cree las tablas (cualquier enfoque funciona):
python -m scraper init-db
python -m alembic upgrade head3. Ejecutar un rastreo de prueba de 5 productos
python -m scraper crawl --limit 5Esto descubre productos del sitio en vivo, procesa solo los primeros 5, descarga sus hojas de especificaciones, almacena filas en PostgreSQL e imprime un informe de rastreo.
También puede fijar una marca:
python -m scraper crawl --limit 5 --url https://en.staging.lumenco.ca/brand/aaledO un solo producto:
python -m scraper crawl --url https://en.staging.lumenco.ca/aaled-aa-900018-1x4-bl.html4. Ejecutar el rastreo completo
python -m scraper crawlEsto recorre todas las marcas (y listados de categorías), sigue cada página de paginación y extrae cada producto detectable. No confunda --limit con un tope de catálogo de producción — --limit es solo para desarrollo.
La limitación de velocidad está integrada: concurrencia, topes por dominio, retraso de descarga, reintentos con retroceso exponencial y AutoThrottle opcional. Ajústelos en .env:
MAX_CONCURRENCY=5
CONCURRENT_REQUESTS_PER_DOMAIN=3
DOWNLOAD_DELAY=0.5
RETRY_COUNT=3
AUTOTHROTTLE_ENABLED=true5. Reanudar un rastreo
El punto de control de Scrapling está habilitado a través de CRAWL_DIR (por defecto ./data/crawl). Presione Ctrl+C una vez para una pausa elegante. Ejecute de nuevo con:
python -m scraper crawl --resumeComportamiento de reanudación:
Scrapling restaura las solicitudes pendientes desde
CRAWL_DIR.Los productos ya almacenados con
scrape_status=successse omiten a menos que pase--force.Los productos fallidos se reintentan.
Los PDFs de especificaciones no se vuelven a extraer cuando el hash del documento no ha cambiado.
6. Inspeccionar la base de datos
python -m scraper stats
python -m scraper validate
python -m scraper product --sku aa-900018-1x4-blO con psql:
psql postgresql://lumenco:lumenco@127.0.0.1:5433/lumencoConsultas útiles:
SELECT count(*) FROM products;
SELECT sku, product_name, price, brand FROM products ORDER BY last_scraped_at DESC LIMIT 20;
SELECT p.sku, d.filename, d.extraction_status, left(d.extracted_text, 200)
FROM specification_documents d
JOIN products p ON p.id = d.product_id
WHERE d.extraction_status = 'extracted'
LIMIT 10;7. Cómo se procesan las hojas de especificaciones
Para cada página de producto, el analizador busca:
a.document-item-link(el control "Hoja de especificaciones" de Lumenco)Etiquetas equivalentes: Hoja de especificaciones, Ficha técnica, Especificaciones, Datos técnicos, PDF, Fiche technique, etc.
Luego, la canalización:
Almacena la URL del documento.
Descarga el archivo con
httpx(no un navegador).Valida los bytes mágicos del PDF (
%PDF).Guarda una copia determinista:
data/specifications/{sku}_{hash16}.pdf.Extrae el texto con PyMuPDF.
Limpia los espacios en blanco manteniendo los saltos de página/sección.
Almacena el texto extraído, el hash SHA-256, el método y el estado.
Analiza las líneas
Etiqueta: Valordel PDF sin inventar campos.Fusiona las especificaciones del PDF con las de la página del producto, conservando la fuente:
{
"Voltage": {
"value": "120-277V",
"source": "product_page",
"raw": "120-277V",
"normalized": {"min": 120, "max": 277, "unit": "V"}
}
}Si un PDF tiene poco o ningún texto, el estado es ocr_required (o se intenta el OCR cuando ENABLE_OCR=true). Las extracciones exitosas vacías no se almacenan silenciosamente.
Los PDFs sin cambios se omiten en rastreos posteriores mediante el hash de contenido.
8. Solución de problemas de productos fallidos
Síntoma | Qué hacer |
| Lea la lista JSON |
El producto falló con HTTP 5xx / tiempo de espera agotado | Vuelva a ejecutar |
Falta la hoja de especificaciones | Esperado para algunos SKUs. El estado es |
PDF marcado como | Habilite los extras de OCR o inspeccione el archivo guardado en |
PDF marcado como | El archivo vinculado no era un PDF (página de error HTML, etc.). Compruebe |
Productos duplicados | No debería suceder: |
Las páginas de marca se ven vacías | Confirme que está en |
Errores de DynamicFetcher | Ejecute |
Errores de conexión de base de datos | Compruebe |
Los registros estructurados se ven así:
[INFO] PRODUCT_FETCH url=https://en.staging.lumenco.ca/aaled-aa-900018-1x4-bl.html sku=aa-900018-1x4-bl status=success
[INFO] SPEC_SHEET sku=aa-900018-1x4-bl status=extracted duration=0.84s
[ERROR] SPEC_SHEET sku=... status=failed error=...Pruebas
pytestLa cobertura incluye normalización de URL, análisis de producto/SKU/precio, detección de hojas de especificaciones, extracción de PDF, upsert/prevención de duplicados en la base de datos, orden de pertenencia a listados, puntuación de recomendaciones e integración de herramientas MCP.
Referencia de CLI
python -m scraper crawl --limit 100
python -m scraper crawl --mode development --limit 100 --url https://en.staging.lumenco.ca/brand/aaled
python -m scraper crawl --resume
python -m scraper reprocess-specs
python -m scraper embeddings --limit 100
python -m scraper embedding-stats
python -m scraper recommend --sku ABC123 --type related --limit 5
python -m scraper recommendation-eval
python -m scraper validate
python -m scraper stats
python -m scraper sample
python -m scraper product --sku ABC123
python -m scraper init-db
python -m app.serverEl modo de rastreo predeterminado es desarrollo: como máximo 100 productos procesados correctamente, solo marcas (sin recorrido de categorías). Se rechaza un rastreo de catálogo completo a menos que pase --mode full --limit N o --mode full --confirm-full.
Fase 2.5 — Calidad de datos de 100 productos
Este proyecto actualmente se dirige a un conjunto de datos Lumenco controlado de ~100 productos. El catálogo en vivo tiene más de 30,000 SKUs; el rastreo de catálogo completo está explícitamente fuera de alcance.
Canalización
Scrapling → extracción de productos → descarga de PDF → texto PDF u OCR → normalización de especificaciones → PostgreSQL → MCP de solo lectura
La extracción de texto PDF se intenta primero. El OCR (Tesseract a través de pytesseract) se ejecuta solo cuando el PDF no tiene texto significativo. Establezca ENABLE_OCR=true e instale Tesseract más pip install pytesseract Pillow.
Las especificaciones normalizadas mantienen la fuente y las banderas de conflicto. El texto sin procesar de la hoja de especificaciones se almacena en specification_documents.extracted_text. El get_product de MCP devuelve especificaciones estructuradas compactas; get_product_specifications puede incluir texto sin procesar cuando include_raw_text=true.
Las URLs de categorías francesas de Magento (por ejemplo, /eclairage-interieur y /electricite) aún aparecen en el encabezado compartido en el host en inglés. Allí devuelven 404. El rastreador no pone en cola esas rutas. Los nuevos rastreos también usan un directorio de punto de control de Scrapling aislado (data/crawl/run-<id>) para que un archivo de pausa antiguo no pueda reanudar miles de URLs de categorías. Use --resume solo para continuar el punto de control compartido data/crawl.
Las URLs de categorías francesas de Magento reescritas en el host en inglés se clasifican como expected_404 y no se cuentan como fallos de producto.
Después de un rastreo:
python -m scraper stats
python -m scraper validate
python -m scraper sample
python -m scraper product --sku L0110TUT8002020Fase 3A — Búsqueda vectorial + incrustaciones de productos
La Fase 3A agrega representaciones semánticas de productos con PostgreSQL + pgvector. No implementa la clasificación de Relacionados/Mejora/Venta cruzada (eso es la Fase 3B).
Arquitectura
~100 product dataset
↓
Canonical product text (cleaned, no HTML)
↓
EmbeddingService (OpenAI-compatible API)
↓
product_embeddings (pgvector)
↓
VectorSearchService
↓
MCP tool: search_similar_productsConfiguración
Use una imagen de Postgres con pgvector (
docker-compose.ymlusapgvector/pgvector:pg16).Establezca las variables de entorno de incrustación en
.env(vea.env.example).Migre:
python -m alembic upgrade headGenere incrustaciones para el catálogo de desarrollo:
python -m scraper embeddings --limit 100
python -m scraper embedding-statsLos productos sin cambios se omiten mediante content_hash. Use --force para regenerar todo.
Estrategia de índice
HNSW en distancia coseno (vector_cosine_ops, m=16, ef_construction=64) — bueno para el conjunto de datos de ~100 productos y sigue siendo utilizable a medida que crece el catálogo. IVFFlat se puede considerar más adelante para catálogos mucho más grandes.
MCP
Nueva herramienta de solo lectura: search_similar_products. Solo lee vectores almacenados; no llama a la API de incrustación ni extrae Lumenco. Las herramientas de recomendación existentes no cambian.
Fase 3B — Motor de recomendación híbrido
Las recomendaciones combinan similitud de pgvector con reglas de productos estructurados. La similitud vectorial por sí sola no es suficiente: un tubo T8 de 18 W, un tubo T8 de 30 W y una luminaria T8 pueden ser semánticamente cercanos, pero se asignan a Relacionados, Mejora y Venta cruzada respectivamente.
Product → vector candidates + structured neighbors
↓
hard exclusions
↓
Related / Upsell / Cross-sell scorers
↓
scores + confidence + reasons → MCPTipo | Significado |
Relacionados | Caso de uso / categoría / especificaciones similares |
Mejora | Misma familia y mejora medible (no solo precio) |
Venta cruzada | Complementario (driver, recorte, carcasa, luminaria↔tubo) |
No se usa ningún LLM dentro de la clasificación. Las herramientas MCP find_related_products, find_upsell_products y find_cross_sell_products llaman a RecommendationService (solo lectura).
CLI
python -m scraper recommend --sku L0110TUT8002020 --type related --limit 5
python -m scraper recommend --sku L0110TUT8002020 --type upsell --limit 5 --debug
python -m scraper recommend --sku L0110TUT8002020 --type cross-sell --limit 5
python -m scraper recommendation-eval --sample-size 10 --limit 3Los pesos se pueden configurar a través de variables de entorno como RELATED_VECTOR_WEIGHT, UPSELL_TECHNICAL_WEIGHT, CROSS_SELL_COMPATIBILITY_WEIGHT (vea .env.example).
Fase 3C — Flujo de trabajo Claude + MCP
User → Claude → MCP (/mcp) → PostgreSQL + pgvector + RecommendationService → Claude → UserResponsabilidades
Capa | Función |
Scrapling | Rastreo / almacenamiento |
PostgreSQL + pgvector | Fuente de verdad + vectores |
RecommendationService | Ranking determinista de Relacionados/Upsell/Cross-sell |
MCP | Recuperación de solo lectura (sin rastreo, sin escrituras, sin LLM) |
Claude | Conversación, selección de herramientas y explicación |
Habilidad de Claude
Habilidad del proyecto: .cursor/skills/lumenco-product-mcp/SKILL.md
Prompts de extremo a extremo
Consulta docs/claude-e2e-tests.md.
Conectar Claude / Inspector
docker compose up -d postgrespython -m app.serverApunta el cliente a
http://localhost:8000/mcp(Streamable HTTP)Opcional:
MCP_AUTH_TOKEN+Authorization: Bearer …
Para el despliegue remoto más adelante: expón solo el endpoint HTTPS del MCP; mantén PostgreSQL privada.
Conjunto de datos de desarrollo
Catálogo actual: ~100 productos. El catálogo completo de Lumenco (30k+) está intencionadamente fuera de alcance.
Fase 2 — Lumenco Product Database MCP
Servidor MCP Streamable HTTP de solo lectura llamado Lumenco Product Database.
Arquitectura
Claude
│ MCP / Streamable HTTP
▼
Lumenco MCP Server (/mcp, /health)
│
▼
MCP Tool Layer
│
▼
Service Layer catalog / product / search / similarity / recommendation
│
▼
Repository Layer SQLAlchemy, no raw SQL in tools
│
▼
PostgreSQL + pgvector products, specs, listings, product_embeddingsConfiguración local
Completa la configuración de la Fase 1 (PostgreSQL +
.env+python -m alembic upgrade head).Ejecuta un rastreo para que el catálogo quede poblado.
Instala los extras de MCP si aún no están en
requirements.txt:
pip install -r requirements.txtDefine las variables de MCP en
.env:
MCP_HOST=0.0.0.0
MCP_PORT=8000
MCP_AUTH_TOKEN=replace-with-a-long-random-token
DATABASE_URL=postgresql+psycopg2://lumenco:lumenco@127.0.0.1:5433/lumenco
DB_POOL_SIZE=10
DB_MAX_OVERFLOW=20
DB_POOL_TIMEOUT=30Para producción, crea un rol de solo SELECT:
psql postgresql://lumenco:lumenco@127.0.0.1:5433/lumenco -f scripts/create_readonly_user.sqlDespués apunta DATABASE_URL a lumenco_mcp.
Ejecución
python -m app.serverO:
uvicorn app.server:app --host 0.0.0.0 --port 8000Docker:
docker compose up --build mcpEndpoint de MCP
http://localhost:8000/mcp
Estado de salud
GET http://localhost:8000/health
{
"status": "ok",
"service": "lumenco-product-mcp",
"database": "connected"
}MCP Inspector
npx -y @modelcontextprotocol/inspectorConecta con http://localhost:8000/mcp con el transporte Streamable HTTP. Si MCP_AUTH_TOKEN está definido, añade:
Authorization: Bearer <token>Confirma que las ocho herramientas aparecen listadas y se pueden ejecutar.
Herramientas disponibles
Todas las herramientas solo leen PostgreSQL. Ninguna recupera las URLs de Lumenco.
get_catalog_status
Tamaño del catálogo y frescura del último rastreo. Sin entrada.
get_listing_products
Productos de una URL de listado de una marca/categoría, en la posición original del listado.
Entrada | Requerido | Notas |
| sí | Normalizada y usada como clave de base de datos |
| no | Por defecto 20, máximo 100 |
| no | Por defecto 0 |
get_product
Registro completo del producto por product_id y/o sku.
get_product_specifications
Especificaciones estructuradas más el texto de la ficha de especificaciones almacenada. No descarga PDFs.
search_products
Búsqueda en el catálogo local (SKU, nombre, marca, categoría, descripción, especificaciones).
Filtros opcionales: brand, category, subcategory, sku, min_price, max_price.
search_similar_products
Vecinos semánticos a partir de los embeddings pgvector almacenados (similitud por coseno). No genera embeddings ni llama a un LLM.
Filtros opcionales: brand, category, subcategory, min_price, max_price.
find_related_products
Candidatos híbridos de Related (vector + categoría/aplicación/especificaciones). Incluye match_score, confidence, score_breakdown y match_reasons. debug=true opcional.
find_upsell_products
Candidatos híbridos de Upsell. Requiere una mejora medible (no solo el precio). Razones en upgrade_reasons.
find_cross_sell_products
Candidatos híbridos de Cross-sell. La compatibilidad domina; se excluyen alternativas de la misma familia.
Las herramientas de recomendación excluyen el producto fuente y deduplican los candidatos. Claude debe solicitar un pool de candidatos y luego elegir la selección final: 3 Related / 4 Upsell / 7 Cross-sell.
Flujo de ejemplo
El usuario: analiza los primeros 10 productos de https://en.staging.lumenco.ca/brand/aaled y devuelve 3 Related, 4 Upsell, 7 Cross-sell.
get_listing_products(listing_url=..., limit=10)get_product_listget_product(product_id=...)para cada fuentefind_related_products/find_upsell_products/find_cross_sell_productsconlimit=10Claude selecciona el conjunto final de los pools de candidatos
Despliegue en producción
Expone solo el endpoint HTTPS de MCP. Mantén PostgreSQL privada.
Internet → HTTPS → MCP server → private PostgreSQLHosts disponibles: Railway, Render, Google Cloud Run, AWS, Cloudflare.
Requisitos:
Terminador HTTPS delante de
uvicorn/ de la imagen DockerMCP_AUTH_TOKENestablecido (el middleware Bearer está aislado, de modo que OAuth podrá sustituirlo más adelante)DATABASE_URLde solo lecturaHealth check en
/health
No publicar el puerto 5432.
Conector personalizado de Claude
Cuando el servidor sea accesible mediante una URL HTTPS pública:
En Claude, añade un conector personalizado.
URL de MCP:
https://your-host/mcpEl nombre del servidor debe aparecer como Lumenco Product Database.
Configura la autenticación Bearer con
MCP_AUTH_TOKEN, u OAuth si sustituyes el middleware.Pregunta: "¿Cuántos productos hay actualmente en la base de datos de Lumenco?" Claude debe llamar a
get_catalog_status.
HTTPS público temporal para pruebas locales: Cloudflare Tunnel, ngrok o similar delante de localhost:8000.
Seguridad
No hay herramientas
execute_sql,fetch_url,run_commandni de rastreoSolo consultas parametrizadas de SQLAlchemy
Límites de consulta aplicados
Las sesiones abren
SET TRANSACTION READ ONLYen PostgreSQLLos secretos no se devuelven en errores de las herramientas
This server cannot be installed
Maintenance
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
- FlicenseNot gradedqualityCmaintenanceEnables searching and retrieving product information from DigiKey's API, including part lookup, keyword search, product details, and pricing.
- FlicenseAqualityDmaintenanceEnables interaction with Adobe Commerce Catalog Services to retrieve product variants, price overrides, category permissions, and environment details via MCP.7
- FlicenseAqualityCmaintenanceExposes marketing catalogs (offers, assets, campaigns, and computed metrics) to MCP clients, enabling natural language queries and AI-driven marketing analysis.8
- AlicenseAqualityBmaintenanceEnables read-only discovery and verification of products across droplinked's KYB-attested merchant network via tools for inventory, merchant, and brand attestation lookups.7MIT
Related MCP Connectors
Federated commerce search across independent WooCommerce merchants. Keyless, read-only MCP server.
Agent-native product catalog for AI shopping agents. 296M+ products, 28 countries.
Manage products, EU Digital Product Passports, operator parties, and GS1 EPCIS supply-chain events.
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/ai-code-co/Claude_MCP_Lumenco'
If you have feedback or need assistance with the MCP directory API, please join our Discord server