内容
# 斯图勒MCP服务器
一个包装**斯图勒 v2 API**的MCP服务器,以便AI助手(Claude Code、Claude Desktop或任何MCP客户端)可以搜索斯图勒的产品目录,获取实时定价和库存,读取完整的产品详情/媒体,并下订单。
这是一个小型、依赖性轻的Node服务器。**您的斯图勒凭证从环境变量中读取,永远不会存储在代码中** - 存储库可以安全提交和共享。
---
## ⚠️ 需要凭证
该服务器在您添加自己的斯图勒凭证之前没有任何用处。没有任何内置的密钥。
您需要一个斯图勒**开发者登录** - 一套斯图勒.com凭证,*不能*登录到stuller.com网站,只能用于API请求。从您的斯图勒账户(账户→API/开发者访问)或询问您的斯图勒代表创建。身份验证是HTTP Basic,基于开发者登录用户名/密码。
---
## 设置
```bash
cd stuller-mcp
npm install
cp .env.example .env # Windows PowerShell: Copy-Item .env.example .env
```
然后打开 `.env` 并填写 **您的** 凭证:
```ini
STULLER_USERNAME=您的开发者登录用户名
STULLER_PASSWORD=您的开发者登录密码
# 可选:
STULLER_API_URL=https://api.stuller.com
STULLER_DISABLE_ORDERING=false
```
`.env` 被 git 忽略 - 它不会被提交。
验证它是否有效:
```bash
npm run smoke
```
没有凭证,烟雾测试会确认服务器已构建并跳过实时调用。有了凭证,它会进行一次只读的价格/库存查找。(如果默认不在您的价格清单上,可以用 `SMOKE_SKU=...` 覆盖测试 SKU。)
---
## 将其连接到MCP客户端
一旦发布到npm,最简单的设置是使用 `npx` 运行它 - 无需克隆或安装:
```jsonc
{
"mcpServers": {
"stuller": {
"command": "npx",
"args": ["-y", "stuller-mcp"],
"env": {
"STULLER_USERNAME": "您的开发者登录用户名",
"STULLER_PASSWORD": "您的开发者登录密码"
}
}
}
}
```
### Claude Code
```bash
claude mcp add stuller --env STULLER_USERNAME=... --env STULLER_PASSWORD=... -- npx -y stuller-mcp
```
### Claude Desktop
将上面的 `mcpServers` 块添加到 `claude_desktop_config.json`(设置 → 开发者 → 编辑配置),然后重启应用程序。
### 从本地克隆运行
将 `command`/`args` 指向您的checkout - 对开发有用的:
```jsonc
{
"mcpServers": {
"stuller": {
"command": "node",
"args": ["/绝对路径/to/stuller-mcp/index.js"],
"env": {
"STULLER_USERNAME": "您的开发者登录用户名",
"STULLER_PASSWORD": "您的开发者登录密码"
}
}
}
}
```
> 从本地克隆运行,服务器还会自动从其自己的目录加载 `.env` 文件,因此您可以将 `env` 从客户端配置中省略并依赖该文件。只需不要提交实际值。
---
## 工具
> **新手?** 只需询问助手 *"如何使用斯图勒服务器?"* - `get_started` 工具在聊天中返回一个完整的演练指南,服务器在连接时还会自动向您的客户端发送使用说明。
| 工具 | 类型 | 功能 |
|------|------|--------------|
| `get_started` | 读取 | 返回一个markdown使用指南(查找产品,定价,石头搜索,下订单)。询问助手如何使用服务器。 |
| `get_products` | 读取 | 按SKU获取一个或多个产品。返回规范的产品数据 + `notFound` 列表。 |
| `product_detail` | 读取 | 单个SKU的完整详情,包括图片,媒体和所有规格。 |
| `show_product` | 读取 | 获取产品图片并**内联**返回(在支持图片的客户端中渲染;在语音/TV界面中显示)。 |
| `pricing_availability` | 读取 | 批量SKU的精简实时价格 + 库存/可用性。 |
| `find_products` | 读取 | **自然语言搜索** - 给出一个普通短语(“白色黄金钻石耳环”),它将术语解析为实际的facet,然后搜索。 最简单的入口点。 |
| `advanced_product_filters` | 读取 | 发现您可以搜索的facet(ProductType,MetalQuality,StoneFamily,…)及其有效值。 |
| `discover_categories` | 读取 | 查找商品类别 + 它们的CategoryIds(例如“钻石耳环”)以浏览成品珠宝facet无法到达的类别。 |
| `search_products` | 读取 | 按系列/类别/高级筛选器筛选目录,带有 `nextPage` 分页。 |
| `metal_market_rates` | 读取 | 当前的斯图勒黄金/铂金/银市场利率。 |
| `search_diamonds` | 读取 | 按4C(克拉/颜色/净度/切工),形状,认证和价格范围搜索天然钻石。 |
| `search_lab_grown_diamonds` | 读取 | 与 `search_diamonds` 类似,但针对实验室培养的钻石库存。 |
| `search_gemstones` | 读取 | 按类型,颜色,形状和尺寸搜索彩色宝石(蓝宝石,红宝石,翡翠,…)。 |
| `find_stones_by_dimensions` | 读取 | 查找石头以**适合给定尺寸的镶嵌件**(例如更换丢失的4.1mm圆形石头),按拟合度排序。 |
| `search_virtual_products` | 读取 | 搜索可配置/半成品镶嵌件;返回镶嵌位置,戒指尺寸,兼容石头和 `baseProductId`。 |
| `configure_product` | 读取 | 为配置的镶嵌件(戒指尺寸,石头,刻字)报价 - 实时总价 + 预计发货日期 + 图像。 仅限报价;不下订单。 |
| `get_configured_product` | 读取 | 按其配置ID检索先前配置的商品。 |
| `order_status` | 读取 | 读取订单历史/状态(按订单号或日期范围)。 |
| `list_invoices` | 读取 | 履行视图:指定日期范围的发票,含**跟踪**的发货,合计和未发货的订单项。 |
| `get_shipment` | 读取 | 按发货头ID获取完整的发货详情(跟踪,承运人,包裹内容)。 |
| `quote_add_item` | 读取 | 将SKU(实时定价)或手动行(人工/定制)添加到会话报价中;返回运行的子总计。 |
| `quote_view` | 读取 | 显示报价与行/子总计和标志;`refresh` 实时重新定价。 |
| `quote_remove_item` | 读取 | 按SKU或索引删除一行。 |
| `quote_clear` | 读取 | 清空报价。 |
| `quote_to_order` | 读取 | 将报价转换为 `submit_order` 准备好的 `lines` 数组。 |
| `favorite_add` / `favorite_list` / `favorite_remove` | 读取* | 保存SKU以便快速重新订购 - 持久化到本地JSON文件(重启后仍然有效)。`favorite_list` 可以实时重新定价。 |
| `favorites_to_quote` | 读取* | 将所有收藏的商品加载到报价中(“重新订购我的常用商品”)。 |
| `submit_order` | **写入** | 下订单。 默认情况下为试运行;仅在 `confirm: true` 时传输。 |
### 搜索工作原理
斯图勒的产品端点**结构化**过滤 - 没有自由文本关键字搜索。 最简单的路径是 **`find_products`**,它接受一个普通短语,将其解析为实时facet词汇,并报告它理解的内容 (`resolvedFilters`) 和任何无法映射的单词 (`unmatchedTerms`)。 在底层,它使用相同的facet,您可以自己驱动:
您通过标识符(`SKU`,`productIds`,`series`,`categoryIds`)或 **分面过滤器** 查找产品。 分面流程分为两步:
1. **`advanced_product_filters`** - 发现可用的分面及其有效值。 有9种分面类型:`ProductType`,`MetalQuality`,`StoneShape`,`StoneFamily`,`StoneColor`,`StoneQuality`,`StoneUniqueness`,`StoneCut`,`StoneSize`。
2. **`search_products`** - 将选定的分面作为 `advancedProductFilters` 返回,任选组合 `filter` 标志(`InStock`,`Orderable`,`OnPriceList`,`Finished`,`BestSeller`)。 因此,“钻石耳环”变为 `ProductType=Earrings` + `StoneFamily=Diamond`。
使用返回的 `nextPage` 令牌分页浏览大型结果集(`hasMore` 告诉您何时停止)。 **搜索结果带有有限定价** - 在报价之前,请使用 `pricing_availability` 或 `product_detail` 重新检查选定的SKU。
### 钻石和宝石搜索
松散的石头使用与产品目录不同的,更丰富的搜索。 `search_diamonds` / `search_lab_grown_diamonds` 按 **4C** 加上形状,认证和范围过滤:
```jsonc
// "1–1.5ct, G color, VS1, round, GIA-certified"
{ "caratMin": 1.0, "caratMax": 1.5, "color": ["G"], "clarity": ["VS1"], "shape": ["Round"], "certification": ["GIA"] }
```
筛选值是纯代码/单词(`color: "G"`,`clarity: "VS1"`,`shape: "Round"`)。 结果包括每颗宝石的规格,价格,**证书编号** 和图片,带有 `nextPage` 分页和 `totalAvailable` 计数。 `search_gemstones` 以类似的方式适用于彩色宝石,通过 `stoneTypes` (例如 `[ "Sapphire"]`),`colors`,`shapes` 和毫米尺寸。
**更换丢失的石头?** `find_stones_by_dimensions` 获取目标尺寸(`lengthMm`,可选 `widthMm`,`shape`)并返回最接近匹配的石头,按偏差排序,每个石头都有一个 `fit` 块(测量尺寸 + 毫米偏差)。 选择 `source`:`diamond`(默认),`lab_grown_diamond` 或 `gemstone`(+`stoneType`)。 _注意:斯图勒没有服务端适合尺寸的终点,因此这是通过形状扫描和本地排名的 - 加宽 `tolerance` 如果没有合适。_
### 可配置和半成品产品
`search_virtual_products` 查找可配置的镶嵌件(半成品,您可以设置石头)。 每个结果公开其 `configurationModel`(戒指尺寸,设置位置,形状/尺寸/设置类型),`canBeSetWith`(兼容的宝石规格),`fullySetImages` 和 `baseProductId`。
将该 `baseProductId` 馈入 `configure_product` 以及您的选择(`ringSize`,`stones` 在位置,`engravings`,链长,...)以获取 **实时总价,预估发货日期和配置图像**。 这是一个报价 - 它不下订单(使用 `submit_order`)。 一个典型的自定义流程:`search_virtual_products` → 选择一个镶嵌件 → `find_stones_by_dimensions`/`search_diamonds` 查找石头 → `configure_product` 定价 → `submit_order`。
### `include` 选项
读取工具接受一个可选的 `include` 数组,用于斯图勒 **ProductInclude** 值(例如 `[ "All"]`,`["Prices"]`,`["Media"]`)以控制返回的数据量。 `product_detail` 默认值为 `[ "All"]`。 有关完整的枚举,请参阅 [斯图勒API帮助](https://api.stuller.com/Help)。
---
## 查看您购买的内容(图片)
每个可购买的结果都包含一个可渲染的 **`display`** 块,因此任何界面(Web UI,Kiosk,TV上的语音助手)都可以显示该商品,无需解析:
```jsonc
display: { title, price, currency, primaryImage, thumbnail, video }
```
`primaryImage`/`thumbnail` 是CDN URL(可配置的镶嵌件更喜欢 *fully-set* 完成的样式)。 对于轻量级/批量渲染,界面应直接使用这些URL。 要在 **聊天中内联渲染单个图像** (或将其推送到屏幕),请调用 **`show_product`** - 它下载图像并返回MCP图像内容块。 URL保持不变;内联(base64)是可选的,单个项目。
**图片尺寸。** 斯图勒的图像CDN通过查询令牌渲染尺寸,因此任何界面都可以通过交换它来调整大小(`?$…$`在`meteor.stullercloud.com/das/…`URL的末尾):
| 令牌 | 像素 | | 令牌 | 像素 |
|---|---|---|---|---|
| `$tiny$` | 40 | | `$standard$` | 300 |
| `$thumb$` | 75 | | `$xlarge$` | 640 |
| `$list$` | 165 | | `$zoom$` | 1500 |
无令牌 = 原始。 (不识别的令牌和显式 `WxH` 被忽略。) `show_product` 接受 `size` 选项(`tiny`…`zoom`/`original`) - 使用 `xlarge`/`zoom` 用于电视,使用 `tiny`/`thumb` 用于手表或列表。
## 工作示例:采购石头 + 镶嵌件定价
一个自定义设计流程,链接多个工具(真实形状,缩写):
```jsonc
// 1. 查找1-1.5ct圆形GIA钻石,价格低于$6k
search_diamonds({ caratMin:1, caratMax:1.5, shape:["Round"], certification:["GIA"], priceMax:6000 })
// → { count: …, diamonds: [{ serialNumber, caratWeight:1.0, color:"G", clarity:"VS1",
// price:5100, certificationNumber:"1408618343", … }] }
// 2. 查找可设置它的半成品
search_virtual_products({ filter:["Orderable"], pageSize:5 })
// → { products: [{ baseProductId:22145800, settingOptions:[{shape:"Marquise", sizeMM:7,…}],
// canBeSetWith:[{shape:"MARQUISE", size:"7.00"}], fullySetImages:[…] }] }
// 3. 为7号戒指配置镶嵌件定价
configure_product({ productId:22145800, ringSize:7 })
// → { totalPrice:715.10, currency:"USD", estimatedShipDate:…, images:[…10] }
// 4. 构建报价(斯图勒零件 + 您的劳动力)并转换为订单
quote_add_item({ sku:"SOLDER:0267:P", quantity:2 }) // 实时定价
quote_add_item({ description:"设置劳动力", unitPrice:120 })
quote_view() // → 运行子总计
quote_to_order() // → { lines:[{sku,quantity}], excluded:[{labor}] }
submit_order({ lines:[…] }) // 试运行 - 审查,然后确认:true 下订单
```
对于无法用分面搜索表达的成品珠宝(例如“钻石耳环”),
使用 `discover_categories({ productType:"Earrings", contains:"stud" })` → 选择
`categoryId` → `search_products({ categoryIds:[id] })`。
## 安全模型
- **读取** (除 `submit_order` 之外的所有操作 - 产品,石头,配置,`order_status`,`list_invoices`,`get_shipment`,...)永远不会修改任何内容。
- **`submit_order` 是唯一的写入工具。** 默认情况下为 **试运行** - 它返回它将发送的确切请求体,并且在您调用它时不会传输任何内容,直到 `confirm: true`。 试运行验证行SKU与目录并标记缺少的收货人/联系人/付款字段;如果确认的订单具有未知SKU,则拒绝。
> **部署说明:** 该服务器设计为 **每个用户通过stdio运行** (每个客户端一个进程)。 报价生成器和响应缓存进程内存中的状态,该状态 **在用户之间不隔离** - **不要为多个客户端托管单个共享实例** 而不添加每个会话的隔离。 每个用户都应使用自己的凭证运行自己的实例。
---
## API 参考
- 端点帮助和请求/响应模型: <https://api.stuller.com/Help>
- 斯图勒电子商务/开发者文档: <https://www.stuller.com/ecommerce-api-documentation/>
- Postman 示例: 斯图勒 API 工作区 → *产品 API 示例*
## 许可证
MIT。 本项目与斯图勒公司无关联,也未得到斯图勒公司的支持。