Skip to main content
Glama
ai-code-co

Lumenco Catalog MCP Server

by ai-code-co

Каталог Lumenco (скрапер Phase 1 + MCP Phase 2)

В этом репозитории два уровня:

  1. Phase 1 собирает данные с https://en.staging.lumenco.ca/ в PostgreSQL.

  2. Phase 2 предоставляет этот каталог через read-only сервер Model Context Protocol, чтобы Claude мог получать товары, спецификации, списки и кандидатов для рекомендаций без просмотра Lumenco.

CLAUDE
  │ MCP / HTTPS
  ▼
Lumenco Product Database (Streamable HTTP)
  │ tools → services → repositories
  ▼
PostgreSQL  (Phase 1 catalog)

Phase 1 собирает. Phase 2 предоставляет. Claude рассуждает.

MCP-сервер никогда не собирает данные с Lumenco, не скачивает PDF-файлы спецификаций, не вызывает LLM и не пишет в базу данных.

Как выглядит сайт

Стейджинг Lumenco — это витрина Magento 2.

Область

Поведение

Бренды

https://en.staging.lumenco.ca/brand перечисляет все бренды (Amasty Brands). Карточки брендов на этой странице часто указывают на staging.lumenco.ca; скрапер переписывает их на английский хост.

Списки брендов

https://en.staging.lumenco.ca/brand/{slug} с пагинацией Magento ?p=2 (24 товара на странице). Общее количество страниц указано в #am-page-count.

Товары

Канонические URL, например /aaled-aa-900018-1x4-bl.html. Серверный HTML включает JSON-LD, SKU, цену, наличие, таблицу спецификаций и ссылку Specification Sheet.

Спецификации

Обычно PDF-файлы того же origin в /dev/*.pdf.

Sitemap

/sitemap.xml в настоящее время возвращает ошибку HTTP 500. Краулер всё равно пробует известные пути sitemap, затем переходит к обнаружению брендов и категорий.

GraphQL

/graphql существует, но схема стейджинга сломана (Config element "String" is not declared). Надёжный источник — HTML-краулинг.

Загрузка

Страницы товаров рендерятся на сервере. HTTP FetcherSession из Scrapling используется по умолчанию. AsyncDynamicSession зарегистрирован как ленивый запасной вариант, если на странице товара отсутствуют обязательные поля.

Краулер остаётся на en.staging.lumenco.ca. Внешние PDF-файлы Specification Sheet могут скачиваться как документы товаров. Реклама, аналитика, корзина, оформление заказа и URL соцсетей игнорируются.

robots.txt написан для публичных поисковых систем (User-agent: * запрещает большинство путей, кроме /brand и нескольких CMS-страниц). Этот скрапер — авторизованный сбор данных каталога со стейджинга, поэтому ROBOTS_TXT_OBEY по умолчанию имеет значение false. Установите его в true, если хотите, чтобы Scrapling учитывал этот файл.

Related MCP server: Catalog Services MCP Server

Структура проекта

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.sql

1. Установка зависимостей

Требуется Python 3.10+.

python -m venv .venv
# Windows
.venv\Scripts\activate
# macOS / Linux
source .venv/bin/activate

pip install -r requirements.txt

HTTP/браузерные дополнения Scrapling включены через scrapling[fetchers]. Если нужен браузерный запасной вариант (DynamicFetcher), установите бинарники браузера:

scrapling install

Необязательный OCR для сканированных/только-изображения PDF-спецификаций:

pip install pytesseract Pillow
# plus a Tesseract OCR engine on the host

OCR по умолчанию выключен (ENABLE_OCR=false). PDF-файлы на основе изображений сохраняются и помечаются ocr_required, а не сохраняются как пустой текст.

2. Настройка PostgreSQL

Самая быстрая локальная настройка:

docker compose up -d postgres

Это запускает PostgreSQL 16 с:

  • пользователь: lumenco

  • пароль: lumenco

  • база данных: lumenco

  • порт хоста: 5433 (порт контейнера остаётся 5432; 5433 позволяет избежать конфликта с установкой PostgreSQL на Windows, которая уже использует 5432)

Скопируйте конфигурацию окружения:

copy .env.example .env   # Windows
cp .env.example .env     # macOS / Linux

Строка подключения по умолчанию:

DATABASE_URL=postgresql+psycopg2://lumenco:lumenco@127.0.0.1:5433/lumenco
LUMENCO_BASE_URL=https://en.staging.lumenco.ca/

Создайте таблицы (подойдёт любой из вариантов):

python -m scraper init-db
python -m alembic upgrade head

3. Запуск тестового краула на 5 товаров

python -m scraper crawl --limit 5

Это обнаруживает товары с живого сайта, обрабатывает только первые 5, скачивает их Specification Sheet, сохраняет строки в PostgreSQL и выводит отчёт о крауле.

Также можно закрепить бренд:

python -m scraper crawl --limit 5 --url https://en.staging.lumenco.ca/brand/aaled

Или отдельный товар:

python -m scraper crawl --url https://en.staging.lumenco.ca/aaled-aa-900018-1x4-bl.html

4. Запуск полного краула

python -m scraper crawl

Это обходит все бренды (и списки категорий), проходит все страницы пагинации и собирает каждый обнаруживаемый товар. Не путайте --limit с ограничением производственного каталога — --limit предназначен только для разработки.

Ограничение скорости встроено: конкурентность, лимиты на домен, задержка скачивания, повторы с экспоненциальной задержкой и опциональный AutoThrottle. Настройте их в .env:

MAX_CONCURRENCY=5
CONCURRENT_REQUESTS_PER_DOMAIN=3
DOWNLOAD_DELAY=0.5
RETRY_COUNT=3
AUTOTHROTTLE_ENABLED=true

5. Возобновление краула

Контрольные точки Scrapling включены через CRAWL_DIR (по умолчанию ./data/crawl). Нажмите Ctrl+C один раз для корректной паузы. Запустите снова с:

python -m scraper crawl --resume

Поведение при возобновлении:

  • Scrapling восстанавливает ожидающие запросы из CRAWL_DIR.

  • Товары, уже сохранённые со статусом scrape_status=success, пропускаются, если не передать --force.

  • Неудачные товары повторяются.

  • PDF-файлы спецификаций не извлекаются повторно, если хэш документа не изменился.

6. Просмотр базы данных

python -m scraper stats
python -m scraper validate
python -m scraper product --sku aa-900018-1x4-bl

Или с помощью psql:

psql postgresql://lumenco:lumenco@127.0.0.1:5433/lumenco

Полезные запросы:

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. Как обрабатываются Specification Sheet

Для каждой страницы товара парсер ищет:

  • a.document-item-link (элемент управления "Specification Sheet" от Lumenco)

  • Эквивалентные метки: Specification Sheet, Spec Sheet, Specifications, Technical Data, PDF, Fiche technique и т. д.

Затем конвейер:

  1. Сохраняет URL документа.

  2. Скачивает файл с помощью httpx (не браузера).

  3. Проверяет магические байты PDF (%PDF).

  4. Сохраняет детерминированную копию: data/specifications/{sku}_{hash16}.pdf.

  5. Извлекает текст с помощью PyMuPDF.

  6. Очищает пробелы, сохраняя разрывы страниц/разделов.

  7. Сохраняет извлечённый текст, SHA-256 хэш, метод и статус.

  8. Разбирает строки Label: Value из PDF без выдумывания полей.

  9. Объединяет спецификации из PDF со спецификациями со страницы товара, сохраняя источник:

{
  "Voltage": {
    "value": "120-277V",
    "source": "product_page",
    "raw": "120-277V",
    "normalized": {"min": 120, "max": 277, "unit": "V"}
  }
}

Если в PDF мало текста или его нет, статус — ocr_required (или OCR выполняется, когда ENABLE_OCR=true). Пустые успешные извлечения не сохраняются молча.

Неизменённые PDF-файлы пропускаются при последующих краулах по хэшу содержимого.

8. Устранение неполадок с неудачными товарами

Симптом

Что делать

python -m scraper validate сообщает о проблемах

Прочитайте JSON-список issues (missing_name, invalid_url, empty_extracted_text, …).

Товар не прошёл HTTP 5xx / таймаут

Повторно запустите python -m scraper crawl --resume. Ошибки находятся в crawl_errors.

Отсутствует Specification Sheet

Ожидаемо для некоторых SKU. Статус — not_found; строка товара всё равно сохраняется.

PDF помечен ocr_required

Включите OCR-дополнения или просмотрите сохранённый файл в data/specifications/.

PDF помечен invalid_pdf

Связанный файл не был PDF (страница ошибки HTML и т. п.). Проверьте specification_documents.error_message.

Дублирующиеся товары

Не должно происходить: уникальные product_url / canonical_url / sku плюс upsert. Запустите validate.

Страницы брендов выглядят пустыми

Убедитесь, что вы на en.staging.lumenco.ca, а не на французском хосте. Спайдер переписывает это автоматически.

Ошибки DynamicFetcher

Запустите scrapling install. HTTP-загрузки достаточно для текущего HTML стейджинга.

Ошибки подключения к базе данных

Проверьте DATABASE_URL, docker compose ps и python -m scraper init-db.

Структурированные журналы выглядят так:

[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=...

Тесты

pytest

Покрытие включает нормализацию URL, разбор товара/SKU/цены, обнаружение spec-sheet, извлечение PDF, upsert в базу данных / предотвращение дубликатов, порядок элементов списков, оценку рекомендаций и интеграцию MCP-инструментов.

Справочник 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.server

Режим краула по умолчанию — development: максимум 100 успешно обработанных товаров, только бренды (без обхода категорий). Полный краул каталога отклоняется, если не передать --mode full --limit N или --mode full --confirm-full.

Phase 2.5 — качество данных на 100 товаров

Этот проект в настоящее время нацелен на контролируемый набор данных Lumenco из ~100 товаров. В живом каталоге более 30 000 SKU; полный краул каталога намеренно выходит за рамки.

Конвейер

Scrapling → извлечение товаров → скачивание PDF → текст PDF или OCR → нормализация спецификаций → PostgreSQL → read-only MCP

Сначала выполняется извлечение текста PDF. OCR (Tesseract через pytesseract) запускается только тогда, когда в PDF нет значимого текста. Установите ENABLE_OCR=true и установите Tesseract плюс pip install pytesseract Pillow.

Нормализованные спецификации сохраняют источник и флаги конфликтов. Сырой текст spec-sheet хранится в specification_documents.extracted_text. MCP get_product возвращает компактные структурированные спецификации; get_product_specifications может включать сырой текст при include_raw_text=true.

Французские URL категорий Magento (например, /eclairage-interieur и /electricite) по-прежнему появляются в общем заголовке на английском хосте. Там они возвращают 404. Краулер не ставит в очередь эти пути. Новые краулы также используют изолированный каталог контрольных точек Scrapling (data/crawl/run-<id>), чтобы старый файл паузы не мог возобновить тысячи URL категорий. Используйте --resume только для продолжения общего data/crawl контрольной точки.

Французские URL категорий Magento, переписанные на английский хост, классифицируются как expected_404 и не считаются ошибками товаров.

После краула:

python -m scraper stats
python -m scraper validate
python -m scraper sample
python -m scraper product --sku L0110TUT8002020

Phase 3A — векторный поиск + эмбеддинги товаров

Phase 3A добавляет семантические представления товаров с помощью PostgreSQL + pgvector. Он не реализует ранжирование Related/Upsell/Cross-sell (это Phase 3B).

Архитектура

~100 product dataset
        ↓
Canonical product text (cleaned, no HTML)
        ↓
EmbeddingService (OpenAI-compatible API)
        ↓
product_embeddings (pgvector)
        ↓
VectorSearchService
        ↓
MCP tool: search_similar_products

Настройка

  1. Используйте образ Postgres с pgvector (docker-compose.yml использует pgvector/pgvector:pg16).

  2. Задайте переменные окружения для эмбеддингов в .env (см. .env.example).

  3. Миграция:

python -m alembic upgrade head
  1. Генерация эмбеддингов для каталога разработки:

python -m scraper embeddings --limit 100
python -m scraper embedding-stats

Неизменённые товары пропускаются через content_hash. Используйте --force для полной перегенерации.

Стратегия индексов

HNSW по косинусному расстоянию (vector_cosine_ops, m=16, ef_construction=64) — хорошо подходит для набора из ~100 товаров и остаётся пригодным по мере роста каталога. IVFFlat можно рассмотреть позже для гораздо больших каталогов.

MCP

Новый read-only инструмент: search_similar_products. Он только читает сохранённые векторы; он не вызывает API эмбеддингов и не собирает данные с Lumenco. Существующие инструменты рекомендаций не изменяются.

Phase 3B — гибридный движок рекомендаций

Рекомендации сочетают сходство pgvector со структурированными правилами товаров. Одного векторного сходства недостаточно: трубка T8 на 18 Вт, трубка T8 на 30 Вт и светильник T8 могут быть семантически близки, но они соответствуют Related, Upsell и Cross-sell соответственно.

Product → vector candidates + structured neighbors
                ↓
        hard exclusions
                ↓
   Related / Upsell / Cross-sell scorers
                ↓
     scores + confidence + reasons → MCP

Тип

Значение

Related

Похожий сценарий использования / категория / спецификации

Upsell

То же семейство и измеримое улучшение (не только цена)

Cross-sell

Дополняющий (драйвер, отделка, корпус, светильник↔трубка)

В ранжировании не используется LLM. MCP-инструменты find_related_products, find_upsell_products и find_cross_sell_products вызывают RecommendationService (read-only).

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 3

Веса настраиваются через переменные окружения, такие как RELATED_VECTOR_WEIGHT, UPSELL_TECHNICAL_WEIGHT, CROSS_SELL_COMPATIBILITY_WEIGHT (см. .env.example).

Phase 3C — рабочий процесс Claude + MCP

User → Claude → MCP (/mcp) → PostgreSQL + pgvector + RecommendationService → Claude → User

Обязанности

Слой

Назначение

Scrapling

Обход / хранение

PostgreSQL + pgvector

Источник истины + векторы

RecommendationService

Детерминированный рейтинг «Похожие»/«Апселл»/«Кросс-сейл»

MCP

Получение только для чтения (без скрапинга, без записи, без LLM)

Claude

Диалог, выбор инструментов, объяснение

Навык Claude

Навык проекта: .cursor/skills/lumenco-product-mcp/SKILL.md

Сквозные промпты

См. docs/claude-e2e-tests.md.

Подключение Claude / Inspector

  1. docker compose up -d postgres

  2. python -m app.server

  3. Укажите клиенту на http://localhost:8000/mcp (Streamable HTTP)

  4. Необязательно: MCP_AUTH_TOKEN + Authorization: Bearer …

Для удалённого развёртывания позже: публикуйте только MCP HTTPS-эндпоинт; PostgreSQL держите в приватной сети.

Набор данных для разработки

Текущий каталог: ~100 товаров. Полный каталог Lumenco (30k+) намеренно выходит за рамки.

Фаза 2 — Lumenco Product Database MCP

MCP-сервер Streamable HTTP только для чтения с именем Lumenco Product Database.

Архитектура

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_embeddings

Локальная настройка

  1. Завершите настройку Фазы 1 (PostgreSQL + .env + python -m alembic upgrade head).

  2. Запустите обход, чтобы каталог заполнился.

  3. Установите дополнительные зависимости MCP, если их ещё нет в requirements.txt:

pip install -r requirements.txt
  1. Задайте MCP-переменные в .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=30

Для продакшена создайте роль только для SELECT:

psql postgresql://lumenco:lumenco@127.0.0.1:5433/lumenco -f scripts/create_readonly_user.sql

Затем укажите DATABASE_URL на lumenco_mcp.

Запуск

python -m app.server

Или:

uvicorn app.server:app --host 0.0.0.0 --port 8000

Docker:

docker compose up --build mcp

MCP-эндпоинт

http://localhost:8000/mcp

Проверка состояния

GET http://localhost:8000/health

{
  "status": "ok",
  "service": "lumenco-product-mcp",
  "database": "connected"
}

MCP Inspector

npx -y @modelcontextprotocol/inspector

Подключитесь к http://localhost:8000/mcp с транспортом Streamable HTTP. Если задан MCP_AUTH_TOKEN, добавьте:

Authorization: Bearer <token>

Убедитесь, что все восемь инструментов отображаются и выполняются.

Доступные инструменты

Все инструменты только читают PostgreSQL. Ни один не загружает URL-адреса Lumenco.

get_catalog_status

Размер каталога и свежесть последнего обхода. Без входных данных.

get_listing_products

Товары по URL-адресу листинга бренда/категории в исходной позиции листинга.

Входные данные

Обязательный

Примечания

listing_url

да

Нормализуется и используется как ключ базы данных

limit

нет

По умолчанию 20, максимум 100

offset

нет

По умолчанию 0

get_product

Полная запись товара по product_id и/или sku.

get_product_specifications

Структурированные характеристики плюс сохранённый текст спецификации. PDF-файлы не загружаются.

search_products

Поиск по локальному каталогу (SKU, название, бренд, категория, описание, характеристики).

Необязательные фильтры: brand, category, subcategory, sku, min_price, max_price.

search_similar_products

Семантические соседи из сохранённых pgvector-эмбеддингов (косинусное сходство). Не генерирует эмбеддинги и не вызывает LLM.

Необязательные фильтры: brand, category, subcategory, min_price, max_price.

Гибридные кандидаты Related (вектор + категория/применение/характеристики). Включает match_score, confidence, score_breakdown и match_reasons. Необязательный параметр debug=true.

find_upsell_products

Гибридные кандидаты Upsell. Требуется измеримое улучшение (не только цена). Причины в upgrade_reasons.

find_cross_sell_products

Гибридные кандидаты Cross-sell. Совместимость имеет решающее значение; альтернативы из того же семейства исключаются.

Инструменты рекомендаций исключают исходный товар и дедуплицируют кандидатов. Claude должен запросить пул кандидатов, а затем сам выбрать финальные 3 Related / 4 Upsell / 7 Cross-sell.

Пример рабочего процесса

Пользователь: проанализируй первые 10 товаров с https://en.staging.lumenco.ca/brand/aaled и дай 3 Related, 4 Upsell, 7 Cross-sell.

  1. get_listing_products(listing_url=..., limit=10)

  2. get_product(product_id=...) для каждого исходного товара

  3. find_related_products / find_upsell_products / find_cross_sell_products с limit=10

  4. Claude выбирает финальный набор из пулов кандидатов

Продакшен-развёртывание

Публикуйте только MCP HTTPS-эндпоинт. PostgreSQL держите в приватной сети.

Internet → HTTPS → MCP server → private PostgreSQL

Подходящие платформы: Railway, Render, Google Cloud Run, AWS, Cloudflare.

Требования:

  • Терминатор HTTPS перед uvicorn / Docker-образом

  • задан MCP_AUTH_TOKEN (bearer-мидлвара изолирована, чтобы позже её можно было заменить на OAuth)

  • DATABASE_URL только для чтения

  • проверка состояния на /health

Не публикуйте порт 5432.

Пользовательский коннектор Claude

После того как сервер станет доступен по публичному HTTPS-URL:

  1. В Claude добавьте пользовательский коннектор.

  2. MCP URL: https://your-host/mcp

  3. Имя сервера должно отображаться как Lumenco Product Database.

  4. Настройте bearer-аутентификацию с помощью MCP_AUTH_TOKEN или OAuth, если вы замените мидлвару.

  5. Спросите: «Сколько товаров сейчас в базе Lumenco?» Claude должен вызвать get_catalog_status.

Временный публичный HTTPS для локального тестирования: Cloudflare Tunnel, ngrok или аналогичные перед localhost:8000.

Безопасность

  • Нет инструментов execute_sql, fetch_url, run_command или обхода

  • Только параметризованные запросы SQLAlchemy

  • Применяются лимиты запросов

  • Сеансы открывают SET TRANSACTION READ ONLY в PostgreSQL

  • Секреты не возвращаются в ошибках инструментов

F
license - not found
Not graded
quality - not tested
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

  • 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.

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/ai-code-co/Claude_MCP_Lumenco'

If you have feedback or need assistance with the MCP directory API, please join our Discord server