Skip to main content
Glama
ai-code-co

Lumenco Catalog MCP Server

by ai-code-co

Lumenco Catalog(阶段 1 爬虫 + 阶段 2 MCP)

本仓库包含两层:

  1. 阶段 1https://en.staging.lumenco.ca/ 抓取到 PostgreSQL。

  2. 阶段 2 通过一个只读的 Model Context Protocol 服务器暴露该目录,使 Claude 无需浏览 Lumenco 即可检索产品、规格、列表和推荐候选

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

阶段 1 抓取。阶段 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、价格、库存、规格表以及规格表链接。

规格表

通常是同源 PDF,位于 /dev/*.pdf 下。

站点地图

/sitemap.xml 当前返回 HTTP 500 错误。爬虫仍会尝试已知的站点地图路径,然后回退到品牌 + 类别发现。

GraphQL

/graphql 存在,但暂存环境的 schema 已损坏(Config element "String" is not declared)。HTML 抓取是可靠来源。

抓取

产品页面是服务端渲染的。Scrapling 的 HTTP FetcherSession 是默认选项。AsyncDynamicSession 注册为懒加载回退,当产品页面缺少必需字段时使用。

爬虫停留在 en.staging.lumenco.ca 上。外部规格表 PDF 可能作为产品文档下载。广告、分析、购物车、结账和社交 URL 会被忽略。

robots.txt 是为公共搜索引擎编写的(User-agent: * 禁止大多数路径,除了 /brand 和少数 CMS 页面)。此爬虫是对暂存环境的授权目录摄取,因此 ROBOTS_TXT_OBEY 默认为 false。如果您希望 Scrapling 遵守该文件,请将其设置为 true

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

Scrapling 的 HTTP/浏览器附加功能通过 scrapling[fetchers] 包含。如果您需要浏览器回退(DynamicFetcher),请安装浏览器二进制文件:

scrapling install

用于扫描或纯图像规格 PDF 的可选 OCR:

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 避免与已使用 5432 的 Windows PostgreSQL 安装冲突)

复制环境配置:

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 个,下载其规格表,将行存储到 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. 恢复抓取

通过 CRAWL_DIR(默认 ./data/crawl)启用 Scrapling 检查点。按一次 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. 规格表的处理方式

对于每个产品页面,解析器查找:

  • a.document-item-link(Lumenco 的“规格表”控件)

  • 等效标签:规格表、规格书、规格、技术数据、PDF、Fiche technique 等。

然后流程:

  1. 存储文档 URL。

  2. 使用 httpx(而非浏览器)下载文件。

  3. 验证 PDF 魔数(%PDF)。

  4. 保存确定性副本:data/specifications/{sku}_{hash16}.pdf

  5. 使用 PyMuPDF 提取文本。

  6. 清理空白,同时保留页面/章节分隔。

  7. 存储提取的文本、SHA-256 哈希、方法和状态。

  8. 从 PDF 解析 Label: Value 行,不虚构字段

  9. 将 PDF 规格与产品页面规格合并,保留来源:

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

如果 PDF 几乎没有文本,状态为 ocr_required(或当 ENABLE_OCR=true 时尝试 OCR)。空白的成功提取不会被静默存储。

未更改的 PDF 在后续抓取中通过内容哈希跳过。

8. 故障排除失败的产品

症状

处理方法

python -m scraper validate 报告问题

阅读 JSON issues 列表(missing_nameinvalid_urlempty_extracted_text 等)。

产品 HTTP 5xx / 超时失败

重新运行 python -m scraper crawl --resume。失败记录在 crawl_errors 中。

缺少规格表

某些 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_URLdocker compose pspython -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/价格解析、规格表检测、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

默认抓取模式为开发:最多成功处理 100 个产品,仅品牌(无类别遍历)。除非您传递 --mode full --limit N--mode full --confirm-full,否则拒绝完整目录抓取。

阶段 2.5 — 100 产品数据质量

本项目当前针对受控的约 100 个产品的 Lumenco 数据集。实时目录有 30,000+ SKU;完整目录抓取有意不在范围内。

流程

Scrapling → 产品提取 → PDF 下载 → PDF 文本或 OCR → 规格标准化 → PostgreSQL → 只读 MCP

首先尝试 PDF 文本提取。仅当 PDF 没有有意义的文本时,才运行 OCR(通过 pytesseract 的 Tesseract)。设置 ENABLE_OCR=true 并安装 Tesseract 以及 pip install pytesseract Pillow

标准化规格保留来源和冲突标志。原始规格表文本存储在 specification_documents.extracted_text 上。MCP get_product 返回紧凑的结构化规格;get_product_specificationsinclude_raw_text=true 时可以包含原始文本。

法语 Magento 类别 URL(例如 /eclairage-interieur/electricite)仍出现在英文主机的共享页头中。它们在那里返回 404。爬虫不会将这些路径入队。新的抓取还使用隔离的 Scrapling 检查点目录(data/crawl/run-<id>),因此旧的暂停文件无法恢复数千个类别 URL。仅使用 --resume 继续共享的 data/crawl 检查点。

重写到英文主机的法语 Magento 类别 URL 被分类为 expected_404,不计为产品失败。

抓取后:

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

阶段 3A — 向量搜索 + 产品嵌入

阶段 3A 通过 PostgreSQL + pgvector 添加语义产品表示。它实现相关/升级/交叉销售排名(那是阶段 3B)。

架构

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

设置

  1. 使用带 pgvector 的 Postgres 镜像(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_opsm=16ef_construction=64)——适合约 100 个产品的数据集,并且在目录增长时仍可使用。对于更大的目录,以后可以考虑 IVFFlat。

MCP

新的只读工具:search_similar_products。它只读取存储的向量;不调用嵌入 API 或抓取 Lumenco。现有的推荐工具不变。

阶段 3B — 混合推荐引擎

推荐结合 pgvector 相似度结构化产品规则。仅靠向量相似度不够:18W T8 灯管、30W T8 灯管和 T8 灯具可能在语义上接近,但它们分别映射到相关、升级和交叉销售。

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

类型

含义

相关

相似的使用场景 / 类别 / 规格

升级

同一系列 可衡量的改进(不仅仅是价格)

交叉销售

互补(驱动器、装饰、外壳、灯具↔灯管)

排名中不使用 LLM。MCP 工具 find_related_productsfind_upsell_productsfind_cross_sell_products 调用 RecommendationService(只读)。

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_WEIGHTUPSELL_TECHNICAL_WEIGHTCROSS_SELL_COMPATIBILITY_WEIGHT(参见 .env.example)。

阶段 3C — Claude + MCP 工作流

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

职责

作用

Scrapling

爬取 / 存储

PostgreSQL + pgvector

数据源 + 向量

RecommendationService

确定性推荐 / 关联/交叉销售排序

MCP

只读(无写入工具)

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+)有意不在范围内。

第二阶段 — Lumenco 产品数据库 MCP

名为 Lumenco 产品数据库 的只读 Streamable HTTP MCP 服务器。

架构

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. 完成第一阶段设置(PostgreSQL + .env + python -m alembic upgrade head)。

  2. 运行一次爬取,以便填充目录。

  3. 如果 requirements.txt 中还没有 MCP 附加依赖,请安装:

pip install -r requirements.txt
  1. .env 中设置 MCP 变量:

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

对于生产环境,创建一个只读角色:

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。它们都不会抓取 Lumenco URL。

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、名称、品牌、分类、描述、规格)。

可选过滤器:brandcategorysubcategoryskumin_pricemax_price

search_similar_products

基于存储的 pgvector 嵌入的语义邻居(余弦相似度)。不会生成嵌入或调用 LLM。

可选过滤器:brandcategorysubcategorymin_pricemax_price

混合 相关 候选(向量 + 分类/应用/规格)。包含 match_scoreconfidencescore_breakdownmatch_reasons。可选 debug=true

find_upsell_products

混合 升级销售 候选。要求有可衡量的改进(不仅仅是价格差异)。原因在 upgrade_reasons 中。

find_cross_sell_products

混合 交叉销售 候选。兼容性占主导;排除同类替代品。

推荐工具会排除源产品并对候选去重。Claude 应请求一个候选池,然后自行选择最终的 3 个相关 / 4 个升级销售 / 7 个交叉销售。

示例工作流

用户:分析 https://en.staging.lumenco.ca/brand/aaled 中的前 10 个产品,并给出 3 个相关、4 个升级销售、7 个交叉销售。

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

  2. 对每个源产品调用 get_product(product_id=...)

  3. 使用 limit=10 调用 find_related_products / find_upsell_products / find_cross_sell_products

  4. Claude 从候选池中选择最终结果

生产部署

仅暴露 MCP HTTPS 端点;保持 PostgreSQL 私有。

Internet → HTTPS → MCP server → private PostgreSQL

合适的主机:Railway、Render、Google Cloud Run、AWS、Cloudflare。

要求:

  • uvicorn / Docker 镜像前有 HTTPS 终止

  • 设置 MCP_AUTH_TOKEN(bearer 中间件是隔离的,因此以后可以用 OAuth 替换)

  • 只读的 DATABASE_URL

  • /health 上进行健康检查

不要发布端口 5432。

Claude 自定义连接器

服务器在公共 HTTPS URL 上可达后:

  1. 在 Claude 中,添加一个自定义连接器。

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

  3. 服务器名称应显示为 Lumenco 产品数据库

  4. 使用 MCP_AUTH_TOKEN 配置 bearer 认证,或者如果您替换了中间件,则使用 OAuth。

  5. 询问:“Lumenco 数据库中当前有多少产品?”Claude 应调用 get_catalog_status

用于本地测试的临时公共 HTTPS:Cloudflare Tunnel、ngrok 或类似工具,放在 localhost:8000 前面。

安全

  • 没有 execute_sqlfetch_urlrun_command 或爬取工具

  • 仅使用 SQLAlchemy 参数化查询

  • 强制查询限制

  • 会话在 PostgreSQL 上开启 SET TRANSACTION READ ONLY

  • 工具错误中不会返回密钥

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