@lofder/dsers-mcp-product 1.5.7 → 1.5.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +78 -0
- package/README.md +118 -59
- package/dist/analytics/client-detect.d.ts +18 -0
- package/dist/analytics/client-detect.d.ts.map +1 -0
- package/dist/analytics/client-detect.js +50 -0
- package/dist/analytics/client-detect.js.map +1 -0
- package/dist/analytics/stats.d.ts +56 -0
- package/dist/analytics/stats.d.ts.map +1 -0
- package/dist/analytics/stats.js +187 -0
- package/dist/analytics/stats.js.map +1 -0
- package/dist/analytics/tracker.d.ts +45 -0
- package/dist/analytics/tracker.d.ts.map +1 -0
- package/dist/analytics/tracker.js +149 -0
- package/dist/analytics/tracker.js.map +1 -0
- package/dist/dsers/product.d.ts +1 -1
- package/dist/dsers/product.d.ts.map +1 -1
- package/dist/dsers/product.js +11 -3
- package/dist/dsers/product.js.map +1 -1
- package/dist/oauth/crypto.d.ts +24 -0
- package/dist/oauth/crypto.d.ts.map +1 -1
- package/dist/oauth/crypto.js +42 -1
- package/dist/oauth/crypto.js.map +1 -1
- package/dist/tools.d.ts +9 -1
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +28 -1
- package/dist/tools.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,45 @@
|
|
|
8
8
|
|
|
9
9
|
## English
|
|
10
10
|
|
|
11
|
+
### 1.5.8 — 2026-04-15
|
|
12
|
+
|
|
13
|
+
Catch-up release folding 1.5.2 → 1.5.8 into a single published npm version. The npm CLI behaviour on this release is effectively identical to 1.5.7 — the code changes since 1.5.1 either landed in intermediate releases already on your machine, or affect only the Vercel-hosted deployment. The main user-facing update is a documentation pass and affiliate links in the README.
|
|
14
|
+
|
|
15
|
+
#### Bugfixes (`persist_failed` saga — 1.5.2 → 1.5.7)
|
|
16
|
+
|
|
17
|
+
Five releases chasing one DSers-BFF bug with progressively more correct fixes. Summary for anyone who saw `status=persist_failed` on `dsers_product_update_rules` or `dsers_store_push`:
|
|
18
|
+
|
|
19
|
+
- **1.5.2** — `deepCleanNone` introduced for DSers API writes; top-level-only `cleanNone` was preserving nested `null` values DSers rejects.
|
|
20
|
+
- **1.5.3** — rolled back GET → merge → PUT pattern that was masking the real error, added surface-level DSers error messages.
|
|
21
|
+
- **1.5.4** — restored GET → merge → PUT but matched the Python `vendor-dsers` reference implementation exactly: filter nulls from the updates dict, never from the original product. 7 integration tests added.
|
|
22
|
+
- **1.5.5** — root cause #1: `Cookie: sessionId=...; state=...` header was required in addition to `Authorization: Bearer` on all DSers BFF write endpoints. Without it, writes silently failed.
|
|
23
|
+
- **1.5.6** — confirmed 1.5.5 fix against live DSers API; added diagnostic logging in `saveDraftImpl`.
|
|
24
|
+
- **1.5.7** — **actual root cause**: DSers BFF uses Protobuf encoding on the import-list PUT endpoint. Sending `tags: ["foo"]` as a JSON string array triggered `CODEC: body unmarshal proto: syntax error`. Fix: skip `tags` in the PUT body entirely and apply them at push time. Also: diagnostic warnings no longer truncated at `MAX_WARNING_CHARS=120`.
|
|
25
|
+
|
|
26
|
+
If you were stuck on 1.5.0–1.5.6, upgrade to 1.5.8 fixes it.
|
|
27
|
+
|
|
28
|
+
#### Bugfixes (other)
|
|
29
|
+
|
|
30
|
+
- **`deepCleanNone` safety** (R-PERF-06). Depth limit (20) + `WeakSet` cycle detection prevents infinite recursion on malformed or self-referential payloads.
|
|
31
|
+
- **Vercel OAuth metadata — broken issuer removed.** The `OAUTH_ISSUER_URL` env var pointed at a missing `silentrillmcp.com` deployment by default, causing every remote OAuth client to hit `DEPLOYMENT_NOT_FOUND`. The env var support is removed entirely; the issuer is now always computed from the request host. (Affects self-hosted deployments only.)
|
|
32
|
+
- **OAuth callback — friendly stale-state page.** When a browser re-hit the callback URL after the real 302 redirect already consumed the state (back button, preconnect, extension strip), the old `400 Missing state parameter` made users think the whole OAuth flow was broken. Now a polite HTML page explains the URL already did its job.
|
|
33
|
+
|
|
34
|
+
#### Features (Vercel-hosted only)
|
|
35
|
+
|
|
36
|
+
- **Proper OAuth proxy to DSers.** Replaced the legacy "paste your DSers session cookie" stub page with a real two-layer PKCE OAuth proxy. Client ↔ Vercel uses the client's PKCE; Vercel ↔ DSers uses our own generated verifier. All state is AES-GCM encrypted into the URL — no server-side session storage required.
|
|
37
|
+
- **Analytics dashboard.** PV / UV (HyperLogLog) / tool-call count / per-tool success rate / MCP client identity / country / hourly activity — surfaced via `/admin/stats?pw=...` HTML dashboard. Writes are fire-and-forget pipelined to Upstash Redis (no-op if env vars are missing). Auto-detects any Vercel Storage prefix.
|
|
38
|
+
- **`registerTools` accepts an optional `onToolCall` callback** so analytics hooks can observe tool invocations without each tool needing to be touched. Backwards compatible; the npm CLI does not pass the callback.
|
|
39
|
+
|
|
40
|
+
#### Docs
|
|
41
|
+
|
|
42
|
+
- **README polish.** Tool table tightened (13 tools, consistent verb-first voice, tool 13 now fits on one line). FAQ expanded with four new entries: remote vs local server, 1688 authorization, store currency, headless token. New Troubleshooting section covering `persist_failed`, pricing rule conflict, 1688 unsupported source, OAuth port conflict, remote 401, and `npx command-not-found` exit 127.
|
|
43
|
+
- **DSers affiliate links** added in Hero, Prerequisites ("A DSers account"), and the "Is it free?" FAQ. Existing users are unaffected; new users hitting npm or GitHub get a referral link.
|
|
44
|
+
- **Accio.com links updated** to the referral URL.
|
|
45
|
+
- **"What's Next" refreshed** — order-level tools and refresh-token support for the remote MCP are now the top priorities.
|
|
46
|
+
- **Python version positioning clarified** — it is a feature-parity subset; the TypeScript version is the primary maintained release.
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
11
50
|
### 1.5.1 — 2026-04-10
|
|
12
51
|
|
|
13
52
|
Security hardening + 7 bugfixes from npm testing. No new tools, no algorithm changes — purely defensive.
|
|
@@ -145,6 +184,45 @@ Previous releases live in the git history. Mostly OAuth 2.1 + remote MCP + Verce
|
|
|
145
184
|
|
|
146
185
|
## 中文
|
|
147
186
|
|
|
187
|
+
### 1.5.8 — 2026-04-15
|
|
188
|
+
|
|
189
|
+
追尾版本,把 1.5.2 → 1.5.8 合成单次 npm 发布。如果你已经在 1.5.7,npm CLI 行为基本没变化 —— 1.5.1 之后的代码改动要么已经在中间版本里被你拿到过,要么只影响 Vercel 托管部署。这一版面向用户的更新主要是 README 打磨和 affiliate 链接。
|
|
190
|
+
|
|
191
|
+
#### Bug 修复(`persist_failed` saga — 1.5.2 → 1.5.7)
|
|
192
|
+
|
|
193
|
+
5 次版本追同一个 DSers BFF bug,每次都修得更接近真相。如果你在 `dsers_product_update_rules` 或 `dsers_store_push` 上看到过 `status=persist_failed`,下面是完整叙事:
|
|
194
|
+
|
|
195
|
+
- **1.5.2** — 为 DSers API 写入引入 `deepCleanNone`;顶层 `cleanNone` 会保留 DSers 拒绝的嵌套 `null`。
|
|
196
|
+
- **1.5.3** — 回退了 GET → merge → PUT,之前它掩盖了真实错误;把 DSers 的错误消息直接暴露出来。
|
|
197
|
+
- **1.5.4** — 重新启用 GET → merge → PUT,但严格对齐 Python `vendor-dsers` 参考实现:只过滤更新 dict 里的 null,永远不过滤原始 product。新增 7 个集成测试。
|
|
198
|
+
- **1.5.5** — 根因 #1:DSers BFF 所有写入 endpoint 除了 `Authorization: Bearer` 之外,还**必须带** `Cookie: sessionId=...; state=...`。少了这个头,写入会静默失败。
|
|
199
|
+
- **1.5.6** — 用 live DSers API 验证 1.5.5 修复;`saveDraftImpl` 里加诊断日志。
|
|
200
|
+
- **1.5.7** — **真正的根因**:DSers BFF 在 import-list PUT endpoint 用的是 Protobuf 编码。把 `tags: ["foo"]` 作为 JSON 字符串数组发过去会触发 `CODEC: body unmarshal proto: syntax error`。修复:PUT body 完全跳过 `tags`,改到推送时应用。顺带把诊断 warning 从 `MAX_WARNING_CHARS=120` 截断里解放出来。
|
|
201
|
+
|
|
202
|
+
如果你卡在 1.5.0–1.5.6,升到 1.5.8 即可。
|
|
203
|
+
|
|
204
|
+
#### Bug 修复(其他)
|
|
205
|
+
|
|
206
|
+
- **`deepCleanNone` 安全性** (R-PERF-06)。深度上限 20 + `WeakSet` 循环检测,防止恶意或自引用 payload 把进程卡死。
|
|
207
|
+
- **Vercel OAuth metadata — 去掉坏的 issuer**。`OAUTH_ISSUER_URL` 默认指向一个不存在的 `silentrillmcp.com` 部署,导致所有远程 OAuth 客户端吃 `DEPLOYMENT_NOT_FOUND`。整个 env var 支持被移除,issuer 改为始终由请求 host 计算。(仅影响 self-hosted 部署)
|
|
208
|
+
- **OAuth callback — 失效 state 显示友好页面**。当浏览器在真正的 302 redirect 之后又二次请求 callback URL(后退、预连接、扩展剥查询)时,旧代码返回干巴的 `400 Missing state parameter`,让人以为整个 OAuth 都炸了。现在返回礼貌 HTML 页面说明"这个页面已经完成了它的任务"。
|
|
209
|
+
|
|
210
|
+
#### 新功能(仅 Vercel 托管版)
|
|
211
|
+
|
|
212
|
+
- **真正的 DSers OAuth 代理**。替换掉旧版"把 DSers session cookie 贴进来"的 stub 页,改为标准双层 PKCE OAuth 代理。客户端 ↔ Vercel 用客户端的 PKCE;Vercel ↔ DSers 用我们自己生成的 verifier。所有 state AES-GCM 加密塞进 URL —— 不需要服务端 session 存储。
|
|
213
|
+
- **数据看板**。PV / UV(HyperLogLog 去重)/ 每 tool 调用数 / 成功率 / MCP 客户端识别 / 国家 / 小时活跃度 —— 全部通过 `/admin/stats?pw=...` 的 HTML dashboard 暴露。写入是 pipelined fire-and-forget 到 Upstash Redis(env 不存在时自动 noop)。自动识别任意 Vercel Storage prefix。
|
|
214
|
+
- **`registerTools` 接受可选 `onToolCall` 回调**,analytics 能 hook 每次工具调用而不用修改 13 个 tool 的 handler。向后兼容;npm CLI 不传这个回调。
|
|
215
|
+
|
|
216
|
+
#### 文档
|
|
217
|
+
|
|
218
|
+
- **README 打磨**。工具表收紧(13 个工具动词开头统一语气,第 13 个现在一行放得下)。FAQ 新增 4 条:远程 vs 本地服务端、1688 授权、店铺币种、headless token。新增 Troubleshooting 小节涵盖 `persist_failed`、定价规则冲突、1688 来源不支持、OAuth 端口冲突、远程 401、`npx command-not-found` 退出码 127。
|
|
219
|
+
- **DSers affiliate 链接** 放到 Hero、Prerequisites("A DSers account")、FAQ "Is it free?" 三处。老用户无感知;从 npm / GitHub 新流量会带 referral。
|
|
220
|
+
- **Accio.com 链接** 更新为 referral URL。
|
|
221
|
+
- **"What's Next" 刷新** —— 订单级工具和远程 MCP refresh-token 支持放到首位。
|
|
222
|
+
- **Python 版本定位澄清** —— 功能对齐的精简子集,TypeScript 版是主维护。
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
148
226
|
### 1.5.1 — 2026-04-10
|
|
149
227
|
|
|
150
228
|
安全加固 + npm 测试发现的 7 个 bugfix。没有新工具,没有算法改动,纯防御性更新。
|
package/README.md
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
|
|
17
17
|
## English
|
|
18
18
|
|
|
19
|
-
**DSers MCP Product** is an open-source [MCP (Model Context Protocol)](https://modelcontextprotocol.io/) server that lets AI Agents automate the entire DSers import workflow — from product sourcing to Shopify or Wix store listing. Search the DSers product pool, import from AliExpress / Alibaba / [Accio.com](https://www.accio.com/), bulk edit variants, apply pricing rules, and push to multiple stores — all with a single sentence to your AI agent.
|
|
19
|
+
**DSers MCP Product** is an open-source [MCP (Model Context Protocol)](https://modelcontextprotocol.io/) server that lets AI Agents automate the entire [DSers](https://www.dsers.com/partner/2044332769636515840) import workflow — from product sourcing to Shopify or Wix store listing. Search the DSers product pool, import from AliExpress / Alibaba / [Accio.com](https://www.accio.com/login?sId=fsBYirNWqq7FyJFV4GnoXw%3D%3D&ic=IC407236504434&tenant=accio), bulk edit variants, apply pricing rules, and push to multiple stores — all with a single sentence to your AI agent.
|
|
20
20
|
|
|
21
21
|
#### What can it do?
|
|
22
22
|
|
|
@@ -24,11 +24,12 @@
|
|
|
24
24
|
- **One-click import** — paste a product link, your AI agent imports it into DSers automatically
|
|
25
25
|
- **Browse your catalog** — view your import staging list and products already pushed to stores
|
|
26
26
|
- **Clean up titles** — strips the messy keyword-stuffed AliExpress titles into something readable
|
|
27
|
-
- **Pricing rules** — markup multiplier (e.g. 2.
|
|
27
|
+
- **Pricing rules** — markup multiplier (e.g. 2.5×), fixed markup (e.g. +$5), fixed price (e.g. $9.99), compare-at / sale prices, per-variant overrides
|
|
28
28
|
- **Batch import** — import multiple products at once with a list of URLs
|
|
29
29
|
- **Multi-store push** — push one product to all your connected Shopify & Wix stores in one go
|
|
30
|
-
- **Safety checks** —
|
|
30
|
+
- **Safety checks** — blocks pushes that price below supplier cost, at $0, or with all variants out of stock; warns on <10% margin, <5 units per variant, or sell price under $1
|
|
31
31
|
- **SEO optimization** — let AI rewrite the title and description for better search rankings before pushing
|
|
32
|
+
- **Supplier swap (SKU Remap)** — replace an existing store product's supplier at the SKU level, with reverse-image-search to auto-find a cheaper or in-stock replacement
|
|
32
33
|
|
|
33
34
|
The server is hosted on [Vercel](https://ai.silentrillmcp.com/dropshipping/mcp) and published across multiple platforms:
|
|
34
35
|
|
|
@@ -49,15 +50,15 @@ The server is hosted on [Vercel](https://ai.silentrillmcp.com/dropshipping/mcp)
|
|
|
49
50
|
|
|
50
51
|
### Supported product sources
|
|
51
52
|
|
|
52
|
-
Works with product links from **AliExpress**, **Alibaba.com**, and **[Accio.com](https://www.accio.com/)**. Just give your AI agent a product link from any of these platforms, and it will import the product into DSers and push it to your store. (1688.com links are also recognized but require your DSers account to have 1688 source authorization enabled.)
|
|
53
|
+
Works with product links from **AliExpress**, **Alibaba.com**, and **[Accio.com](https://www.accio.com/login?sId=fsBYirNWqq7FyJFV4GnoXw%3D%3D&ic=IC407236504434&tenant=accio)**. Just give your AI agent a product link from any of these platforms, and it will import the product into DSers and push it to your store. (1688.com links are also recognized but require your DSers account to have 1688 source authorization enabled.)
|
|
53
54
|
|
|
54
55
|
### Accio.com — AI-powered product sourcing
|
|
55
56
|
|
|
56
|
-
[Accio.com](https://www.accio.com/) is Alibaba's AI sourcing assistant. You describe what you're looking for (e.g. "wireless earbuds under $5"), and it searches AliExpress & Alibaba for you.
|
|
57
|
+
[Accio.com](https://www.accio.com/login?sId=fsBYirNWqq7FyJFV4GnoXw%3D%3D&ic=IC407236504434&tenant=accio) is Alibaba's AI sourcing assistant. You describe what you're looking for (e.g. "wireless earbuds under $5"), and it searches AliExpress & Alibaba for you.
|
|
57
58
|
|
|
58
59
|
**How to use it with DSers MCP:**
|
|
59
60
|
|
|
60
|
-
1. Go to [accio.com](https://www.accio.com/) and search for products in natural language.
|
|
61
|
+
1. Go to [accio.com](https://www.accio.com/login?sId=fsBYirNWqq7FyJFV4GnoXw%3D%3D&ic=IC407236504434&tenant=accio) and search for products in natural language.
|
|
61
62
|
2. Browse the results. When you find a product you like, **click on it** to open the product detail panel.
|
|
62
63
|
3. **Copy the URL** from your browser address bar — it will look something like:
|
|
63
64
|
`https://www.accio.com/c/xxx?productId=1005009871053792&ds=aliexpress.com`
|
|
@@ -77,7 +78,7 @@ This works for both AliExpress and Alibaba products found on Accio.
|
|
|
77
78
|
### What You Need
|
|
78
79
|
|
|
79
80
|
- **Node.js** >= 20.0.0
|
|
80
|
-
- A [DSers](https://www.dsers.com/) account (free plan works)
|
|
81
|
+
- A [DSers](https://www.dsers.com/partner/2044332769636515840) account (free plan works)
|
|
81
82
|
- A Shopify or Wix store already connected in DSers
|
|
82
83
|
- An MCP-compatible AI client — [Cursor](https://cursor.sh/), [Claude Desktop](https://claude.ai/desktop), [Claude Managed Agents](https://platform.claude.com/docs/en/managed-agents/overview), [Windsurf](https://codeium.com/windsurf), or any client that supports MCP
|
|
83
84
|
|
|
@@ -264,21 +265,19 @@ dsers-mcp-product/
|
|
|
264
265
|
|
|
265
266
|
| # | Tool | What it does |
|
|
266
267
|
|---|------|-------------|
|
|
267
|
-
| 1 | `dsers_store_discover` |
|
|
268
|
-
| 2 | `dsers_rules_validate` |
|
|
269
|
-
| 3 | `dsers_product_import` |
|
|
270
|
-
| 4 | `dsers_product_preview` |
|
|
271
|
-
| 5 | `dsers_product_update_rules` | Edit pricing, content, images, or
|
|
272
|
-
| 6 | `dsers_product_visibility` |
|
|
273
|
-
| 7 | `dsers_store_push` |
|
|
274
|
-
| 8 | `dsers_job_status` |
|
|
275
|
-
| 9 | `dsers_product_delete` |
|
|
276
|
-
| 10 | `dsers_import_list` | Browse
|
|
277
|
-
| 11 | `dsers_my_products` |
|
|
278
|
-
| 12 | `dsers_find_product` | Search the DSers product pool by keyword or image
|
|
279
|
-
| 13 | `dsers_sku_remap` |
|
|
280
|
-
|
|
281
|
-
All tools return clear error messages so your AI agent knows what went wrong and what to do next.
|
|
268
|
+
| 1 | `dsers_store_discover` | List connected stores, shipping methods, pricing rules, and supported capabilities |
|
|
269
|
+
| 2 | `dsers_rules_validate` | Dry-run pricing or content rules without applying them — catches schema mistakes early |
|
|
270
|
+
| 3 | `dsers_product_import` | Import a product URL, optionally apply rules at import time, returns a full preview |
|
|
271
|
+
| 4 | `dsers_product_preview` | Reload preview for an imported product — title, price, variants, stock, active rules |
|
|
272
|
+
| 5 | `dsers_product_update_rules` | Edit pricing, content, images, variants, or option edits on an imported product (incremental merge — no re-import) |
|
|
273
|
+
| 6 | `dsers_product_visibility` | Toggle a draft between "hidden draft" and "published/live" before pushing |
|
|
274
|
+
| 7 | `dsers_store_push` | Push to Shopify / Wix — single product, batch, or fan-out to multiple stores in one call |
|
|
275
|
+
| 8 | `dsers_job_status` | Poll the status of a push (queued / running / completed / failed) |
|
|
276
|
+
| 9 | `dsers_product_delete` | Permanently remove a product from the DSers import list (irreversible, requires confirmation) |
|
|
277
|
+
| 10 | `dsers_import_list` | Browse the import staging list with cost, sell price, stock, markup status, and low-stock warnings |
|
|
278
|
+
| 11 | `dsers_my_products` | List products already pushed to a specific store, with supplier URLs for re-import |
|
|
279
|
+
| 12 | `dsers_find_product` | Search the DSers product pool by keyword or image; results include `import_url` for one-step import |
|
|
280
|
+
| 13 | `dsers_sku_remap` | SKU-level supplier swap on a live store product. Strict mode (`new_supplier_url`) or discover mode (reverse-image search + multi-factor ranking). Run `mode='preview'` before `mode='apply'`. Requires `product:mapping` scope |
|
|
282
281
|
|
|
283
282
|
### Pre-Push Safety Checks
|
|
284
283
|
|
|
@@ -317,10 +316,10 @@ Ready-made workflows your AI client can use directly:
|
|
|
317
316
|
|
|
318
317
|
### What's Next
|
|
319
318
|
|
|
320
|
-
- Product pool search enhancements
|
|
321
|
-
-
|
|
322
|
-
-
|
|
323
|
-
-
|
|
319
|
+
- Product pool search enhancements — category filters, URL-based reverse lookup, product detail view
|
|
320
|
+
- More store platforms — TikTok Shop, Etsy, eBay (whatever DSers already integrates with)
|
|
321
|
+
- Order-level tools — fulfillment status, tracking, order sync
|
|
322
|
+
- Remote MCP refresh-token support — extend OAuth sessions beyond the initial access-token lifetime
|
|
324
323
|
|
|
325
324
|
Got an idea or feature request? [Open an issue](https://github.com/lofder/dsers-mcp-product/issues) — contributions are very welcome.
|
|
326
325
|
|
|
@@ -333,26 +332,55 @@ DSers MCP Product is a free, open-source MCP server that automates dropshipping
|
|
|
333
332
|
You type a command like "Import this product, mark up 2.5x, push to my store" in Cursor or Claude Desktop. The MCP server handles the entire workflow: fetching product data, applying pricing rules, editing variants, and pushing to your connected stores.
|
|
334
333
|
|
|
335
334
|
**Is it free?**
|
|
336
|
-
Yes. The tool is open-source (MIT license) and completely free to use. You only need a free DSers account and a Shopify or Wix store connected in DSers.
|
|
335
|
+
Yes. The tool is open-source (MIT license) and completely free to use. You only need a free [DSers](https://www.dsers.com/partner/2044332769636515840) account and a Shopify or Wix store connected in DSers.
|
|
337
336
|
|
|
338
337
|
**Is it safe? Do I need to share my password?**
|
|
339
338
|
No passwords are stored or transmitted. Authentication uses a zero-password browser login — you log in on DSers's own website, and the tool picks up the session token. Your credentials never touch the MCP server. The project scored 92/100 on [SafeSkill](https://safeskill.dev/scan/@lofder/dsers-mcp-product) security scanning.
|
|
340
339
|
|
|
341
340
|
**What AI clients does it support?**
|
|
342
|
-
Cursor, Claude Desktop, Claude Code, Claude Managed Agents, Windsurf, and any MCP-compatible client
|
|
341
|
+
Cursor, Claude Desktop, Claude Code, Claude Managed Agents, Windsurf, and any MCP-compatible client. Use stdio transport with the npm package, or Streamable HTTP with the hosted remote server.
|
|
342
|
+
|
|
343
|
+
**Should I use the remote server or install locally?**
|
|
344
|
+
Use the **remote server** (`https://ai.silentrillmcp.com/dropshipping/mcp`) if your MCP client supports Streamable HTTP and you want zero install — you skip Node.js setup entirely. Use the **local npm package** if your client only supports stdio (e.g. some Claude Desktop setups), you need custom env vars, or you want to run it fully offline from your own machine.
|
|
343
345
|
|
|
344
346
|
**How is this different from AliDropify, AutoDS, or other dropshipping tools?**
|
|
345
347
|
Most dropshipping tools have their own UI and require you to click through web interfaces. DSers MCP Product takes a fundamentally different approach — it connects directly to your AI agent, so you automate workflows through conversation instead of clicking buttons. It's also open-source and free, with no subscription tiers.
|
|
346
348
|
|
|
347
349
|
**What product sources does it support?**
|
|
348
|
-
AliExpress, Alibaba.com, Accio.com (Alibaba's AI sourcing tool), and 1688
|
|
350
|
+
AliExpress, Alibaba.com, Accio.com (Alibaba's AI sourcing tool), and 1688. For 1688, your DSers account needs the 1688 source authorization enabled — open [DSers → Settings → Suppliers](https://app.dsers.com/) and link your 1688 account there.
|
|
351
|
+
|
|
352
|
+
**What currency does pricing use?**
|
|
353
|
+
The agent displays prices in USD for readability, but pricing is actually applied in your store's native currency. DSers handles the conversion based on the store's configured currency (Shopify / Wix). Per-variant overrides and fixed prices are interpreted in store currency — confirm with the AI if you're not sure.
|
|
349
354
|
|
|
350
355
|
**Can I push to multiple stores at once?**
|
|
351
356
|
Yes. The `dsers_store_push` tool supports pushing a single product to all your connected Shopify and Wix stores in one command, with per-store pricing and visibility options.
|
|
352
357
|
|
|
358
|
+
**Can I skip the browser login and hardcode a token?**
|
|
359
|
+
For headless / CI environments, yes — set `DSERS_ACCESS_TOKEN` (and optionally `DSERS_REFRESH_TOKEN`) as env vars and the tool will skip the OAuth flow. Tokens come from running `login` once on any machine and copying them out of `~/.dsers-mcp/session.json`. Interactive users should stick with `npx @lofder/dsers-mcp-product login` — it's safer and handles refresh automatically.
|
|
360
|
+
|
|
361
|
+
### Troubleshooting
|
|
362
|
+
|
|
363
|
+
**Push returns `persist_failed` or `CODEC` error**
|
|
364
|
+
Fixed in v1.5.7. If you still see it, make sure you're on the latest version: `npm view @lofder/dsers-mcp-product version`. Reinstall with `npx -y @lofder/dsers-mcp-product@latest` to pick up the new release.
|
|
365
|
+
|
|
366
|
+
**Push blocked with "pricing rule conflict"**
|
|
367
|
+
Your DSers store has its own Pricing Rule enabled, and you also set MCP pricing rules. Pick one: either add `pricing_rule_behavior='apply_store_pricing_rule'` to the push options (accepts the store-side rule), or disable the Pricing Rule in DSers settings and let MCP drive pricing. See the [Pricing Rule Conflict Detection](#pricing-rule-conflict-detection) section above.
|
|
368
|
+
|
|
369
|
+
**1688 link imports fail with "unsupported source"**
|
|
370
|
+
Your DSers account needs 1688 source authorization. Open [DSers Settings → Suppliers](https://app.dsers.com/) and link your 1688 seller account. AliExpress works out of the box; 1688 is opt-in.
|
|
371
|
+
|
|
372
|
+
**`npx @lofder/dsers-mcp-product login` opens browser but gets stuck**
|
|
373
|
+
The login flow needs ports 3001–3003 free on localhost for the OAuth callback. If any of those are in use (another MCP server, a dev server), kill them or set `PORT=3004` before running login.
|
|
374
|
+
|
|
375
|
+
**Remote server returns 401 after working for a while**
|
|
376
|
+
OAuth access tokens expire. The remote server currently doesn't auto-refresh — reauthorize via your MCP client (disconnect and reconnect the MCP server). Refresh-token support is on the [What's Next](#whats-next) list.
|
|
377
|
+
|
|
378
|
+
**`npx dsers-mcp-product: command not found` (exit 127)**
|
|
379
|
+
You're working from a local source clone, not the published npm package. Use `node dist/cli.js login` instead — the `npx` binary only resolves after `npm link` or a real install. Run `npm run build` first if `dist/` doesn't exist.
|
|
380
|
+
|
|
353
381
|
### Also Available
|
|
354
382
|
|
|
355
|
-
A [Python version](https://github.com/lofder/dsers-mcp-product-py) is available for local stdio deployments.
|
|
383
|
+
A [Python version](https://github.com/lofder/dsers-mcp-product-py) is available as a feature-parity subset for local stdio deployments. The TypeScript version is the primary maintained release — use it first.
|
|
356
384
|
|
|
357
385
|
### License
|
|
358
386
|
|
|
@@ -364,7 +392,7 @@ MIT
|
|
|
364
392
|
|
|
365
393
|
## 中文
|
|
366
394
|
|
|
367
|
-
**DSers MCP Product** 是一个开源的 [MCP (Model Context Protocol)](https://modelcontextprotocol.io/) 服务器,让 AI Agent 自动完成 DSers 的整个商品流程 —— 从选品搜索到 Shopify 或 Wix 店铺上架。搜索 DSers 商品池、从速卖通 / Alibaba / [Accio.com](https://www.accio.com/) 导入商品、批量编辑变体、应用定价规则、推送到多个店铺 —— 只需一句话给你的 AI agent。
|
|
395
|
+
**DSers MCP Product** 是一个开源的 [MCP (Model Context Protocol)](https://modelcontextprotocol.io/) 服务器,让 AI Agent 自动完成 [DSers](https://www.dsers.com/partner/2044332769636515840) 的整个商品流程 —— 从选品搜索到 Shopify 或 Wix 店铺上架。搜索 DSers 商品池、从速卖通 / Alibaba / [Accio.com](https://www.accio.com/login?sId=fsBYirNWqq7FyJFV4GnoXw%3D%3D&ic=IC407236504434&tenant=accio) 导入商品、批量编辑变体、应用定价规则、推送到多个店铺 —— 只需一句话给你的 AI agent。
|
|
368
396
|
|
|
369
397
|
#### 能做什么?
|
|
370
398
|
|
|
@@ -372,11 +400,12 @@ MIT
|
|
|
372
400
|
- **一句话导入** — 贴个商品链接,AI 助手自动导入到 DSers
|
|
373
401
|
- **浏览商品库** — 查看导入待推送列表和已上架商品,包含成本价、售价、加价状态
|
|
374
402
|
- **标题清理** — 把速卖通那些关键词堆砌的乱标题整理成人话
|
|
375
|
-
- **定价规则** — 加价倍率(比如 2.5 倍)、固定加价(比如 +5
|
|
403
|
+
- **定价规则** — 加价倍率(比如 2.5 倍)、固定加价(比如 +5 美金)、固定售价(比如 9.99 美金)、划线价、按 SKU 单独定价
|
|
376
404
|
- **批量导入** — 一次丢一堆链接,全部导入
|
|
377
405
|
- **多店铺推送** — 一个商品一次推到你所有的 Shopify 和 Wix 店铺
|
|
378
|
-
- **安全校验** —
|
|
406
|
+
- **安全校验** — 推送前自动拦截"低于成本价/零售价为 0/全变体零库存"三种情况;利润率低于 10%、单变体库存少于 5、售价低于 1 美金会弹警告
|
|
379
407
|
- **SEO 优化** — 让 AI 重写标题和描述,提高搜索排名后再推送
|
|
408
|
+
- **供应商替换(SKU Remap)** — SKU 级替换已上架商品的供应商,支持反向图搜自动找更便宜或有货的替代供应商
|
|
380
409
|
|
|
381
410
|
服务已托管在 [Vercel](https://ai.silentrillmcp.com/dropshipping/mcp),并发布到多个平台:
|
|
382
411
|
|
|
@@ -397,15 +426,15 @@ MIT
|
|
|
397
426
|
|
|
398
427
|
### 支持的商品来源
|
|
399
428
|
|
|
400
|
-
支持 **速卖通(AliExpress)**、**Alibaba.com** 和 **[Accio.com](https://www.accio.com/)** 的商品链接。把任意平台的商品链接丢给你的 AI 助手,它就能自动导入 DSers 并上架到你的店铺。(1688 链接也能识别,但需要你的 DSers 账号开通了 1688 来源权限。)
|
|
429
|
+
支持 **速卖通(AliExpress)**、**Alibaba.com** 和 **[Accio.com](https://www.accio.com/login?sId=fsBYirNWqq7FyJFV4GnoXw%3D%3D&ic=IC407236504434&tenant=accio)** 的商品链接。把任意平台的商品链接丢给你的 AI 助手,它就能自动导入 DSers 并上架到你的店铺。(1688 链接也能识别,但需要你的 DSers 账号开通了 1688 来源权限。)
|
|
401
430
|
|
|
402
431
|
### Accio.com — AI 智能找商
|
|
403
432
|
|
|
404
|
-
[Accio.com](https://www.accio.com/) 是阿里巴巴的 AI 选品助手。你用自然语言描述想找的商品(比如"5 美金以下的蓝牙耳机"),它会帮你在速卖通和阿里巴巴上搜索。
|
|
433
|
+
[Accio.com](https://www.accio.com/login?sId=fsBYirNWqq7FyJFV4GnoXw%3D%3D&ic=IC407236504434&tenant=accio) 是阿里巴巴的 AI 选品助手。你用自然语言描述想找的商品(比如"5 美金以下的蓝牙耳机"),它会帮你在速卖通和阿里巴巴上搜索。
|
|
405
434
|
|
|
406
435
|
**怎么配合 DSers MCP 用:**
|
|
407
436
|
|
|
408
|
-
1. 打开 [accio.com](https://www.accio.com/),用自然语言搜索你想要的商品。
|
|
437
|
+
1. 打开 [accio.com](https://www.accio.com/login?sId=fsBYirNWqq7FyJFV4GnoXw%3D%3D&ic=IC407236504434&tenant=accio),用自然语言搜索你想要的商品。
|
|
409
438
|
2. 在搜索结果里浏览,看到感兴趣的商品**点击进去**看详情。
|
|
410
439
|
3. **复制浏览器地址栏的链接**,大概长这样:
|
|
411
440
|
`https://www.accio.com/c/xxx?productId=1005009871053792&ds=aliexpress.com`
|
|
@@ -424,7 +453,7 @@ Accio 上搜出来的速卖通和阿里巴巴商品都能用。
|
|
|
424
453
|
|
|
425
454
|
### 使用前提
|
|
426
455
|
|
|
427
|
-
- 一个 [DSers](https://www.dsers.com/) 账号(免费版就行)
|
|
456
|
+
- 一个 [DSers](https://www.dsers.com/partner/2044332769636515840) 账号(免费版就行)
|
|
428
457
|
- Shopify 或 Wix 店铺已经在 DSers 里绑定好了
|
|
429
458
|
- 一个支持 MCP 的 AI 客户端 — [Cursor](https://cursor.sh/)、[Claude Desktop](https://claude.ai/desktop)、[Claude Managed Agents](https://platform.claude.com/docs/en/managed-agents/overview)、[Windsurf](https://codeium.com/windsurf) 或其他支持 MCP 的工具
|
|
430
459
|
|
|
@@ -554,21 +583,19 @@ npm test
|
|
|
554
583
|
|
|
555
584
|
| # | 工具 | 干什么的 |
|
|
556
585
|
|---|------|---------|
|
|
557
|
-
| 1 | `dsers_store_discover` |
|
|
558
|
-
| 2 | `dsers_rules_validate` |
|
|
559
|
-
| 3 | `dsers_product_import` |
|
|
560
|
-
| 4 | `dsers_product_preview` |
|
|
561
|
-
| 5 | `dsers_product_update_rules` |
|
|
562
|
-
| 6 | `dsers_product_visibility` |
|
|
563
|
-
| 7 | `dsers_store_push` |
|
|
564
|
-
| 8 | `dsers_job_status` |
|
|
565
|
-
| 9 | `dsers_product_delete` | 从 DSers
|
|
566
|
-
| 10 | `dsers_import_list` |
|
|
567
|
-
| 11 | `dsers_my_products` |
|
|
568
|
-
| 12 | `dsers_find_product` |
|
|
569
|
-
| 13 | `dsers_sku_remap` | SKU
|
|
570
|
-
|
|
571
|
-
报错时会返回清晰的消息,AI 助手能看懂出了什么问题、该怎么办。
|
|
586
|
+
| 1 | `dsers_store_discover` | 列出已绑定店铺、配送方式、定价规则及可用能力 |
|
|
587
|
+
| 2 | `dsers_rules_validate` | 空跑定价/内容规则但不真正应用 — 提前抓 schema 错误 |
|
|
588
|
+
| 3 | `dsers_product_import` | 导入商品链接,可顺便应用规则,返回完整预览 |
|
|
589
|
+
| 4 | `dsers_product_preview` | 重新加载已导入商品的预览 — 标题、价格、变体、库存、已生效规则 |
|
|
590
|
+
| 5 | `dsers_product_update_rules` | 对已导入商品修改定价/标题/图片/变体/选项(增量合并,无需重新导入) |
|
|
591
|
+
| 6 | `dsers_product_visibility` | 在"隐藏草稿"和"上架展示"之间切换(推送前) |
|
|
592
|
+
| 7 | `dsers_store_push` | 推到 Shopify / Wix — 单个、批量、或一次扇出到多店铺 |
|
|
593
|
+
| 8 | `dsers_job_status` | 查询推送任务状态(排队 / 进行中 / 完成 / 失败) |
|
|
594
|
+
| 9 | `dsers_product_delete` | 从 DSers 导入列表中永久删除商品(不可恢复,需显式确认) |
|
|
595
|
+
| 10 | `dsers_import_list` | 浏览导入待推送列表,含成本价、售价、库存、加价状态、低库存预警 |
|
|
596
|
+
| 11 | `dsers_my_products` | 列出指定店铺已上架的商品,带供应商 URL 方便重导入 |
|
|
597
|
+
| 12 | `dsers_find_product` | DSers 商品池关键词/图片搜索,结果附带 `import_url` 可一键导入 |
|
|
598
|
+
| 13 | `dsers_sku_remap` | SKU 级替换已上架商品的供应商。精确模式(传 `new_supplier_url`)或发现模式(反向图搜 + 多因子打分)。先 `mode='preview'`,确认后再 `mode='apply'`。需要 `product:mapping` scope |
|
|
572
599
|
|
|
573
600
|
### 推送前安全校验
|
|
574
601
|
|
|
@@ -599,10 +626,10 @@ MCP 客户端可直接展示给用户的工作流模板:
|
|
|
599
626
|
|
|
600
627
|
### 后续计划
|
|
601
628
|
|
|
602
|
-
-
|
|
603
|
-
-
|
|
604
|
-
-
|
|
605
|
-
-
|
|
629
|
+
- 商品池搜索增强 — 分类过滤、URL 反查、商品详情视图
|
|
630
|
+
- 更多店铺平台 — TikTok Shop、Etsy、eBay(凡是 DSers 已接入的)
|
|
631
|
+
- 订单级工具 — 履约状态、物流跟踪、订单同步
|
|
632
|
+
- 远程 MCP refresh-token 支持 — 延长 OAuth 会话有效期,免反复授权
|
|
606
633
|
|
|
607
634
|
有想法或需求?欢迎 [提 issue](https://github.com/lofder/dsers-mcp-product/issues) —— 非常欢迎其他开发者的建议和贡献。
|
|
608
635
|
|
|
@@ -615,23 +642,55 @@ MCP 客户端可直接展示给用户的工作流模板:
|
|
|
615
642
|
在 Cursor 或 Claude Desktop 里输入"导入这个商品,加价 2.5 倍,推送到我的店铺",MCP 服务器自动完成抓取商品数据、应用定价规则、编辑变体、推送到店铺的全部流程。
|
|
616
643
|
|
|
617
644
|
**收费吗?**
|
|
618
|
-
完全免费。项目开源(MIT 协议),你只需要一个免费的 DSers 账号和已连接的 Shopify 或 Wix 店铺。
|
|
645
|
+
完全免费。项目开源(MIT 协议),你只需要一个免费的 [DSers](https://www.dsers.com/partner/2044332769636515840) 账号和已连接的 Shopify 或 Wix 店铺。
|
|
619
646
|
|
|
620
647
|
**安全吗?需要提供密码吗?**
|
|
621
648
|
不需要。登录采用零密码浏览器认证——你在 DSers 官网登录,工具只接收会话令牌,密码永远不会经过 MCP 服务器。项目在 [SafeSkill](https://safeskill.dev/scan/@lofder/dsers-mcp-product) 安全扫描中获得 92/100 分。
|
|
622
649
|
|
|
623
650
|
**支持哪些 AI 客户端?**
|
|
624
|
-
Cursor、Claude Desktop、Claude Code、Windsurf
|
|
651
|
+
Cursor、Claude Desktop、Claude Code、Claude Managed Agents、Windsurf,以及任何 MCP 兼容客户端。npm 包走 stdio transport,托管的远程服务端走 Streamable HTTP。
|
|
652
|
+
|
|
653
|
+
**应该用远程版还是本地装?**
|
|
654
|
+
如果你的 MCP 客户端支持 Streamable HTTP、不想折腾 Node.js,用**远程版**(`https://ai.silentrillmcp.com/dropshipping/mcp`);如果客户端只认 stdio(部分 Claude Desktop 版本)、想完全离线、或者需要传自定义环境变量,就用**本地 npm 包**。
|
|
625
655
|
|
|
626
656
|
**和 AliDropify、AutoDS 等 Dropshipping 工具有什么区别?**
|
|
627
657
|
大多数 Dropshipping 工具有自己的界面,需要点来点去。DSers MCP Product 完全不同——它直接连接你的 AI Agent,用对话代替点击来自动化工作流。而且完全开源免费,没有订阅分级。
|
|
628
658
|
|
|
659
|
+
**支持哪些商品来源?**
|
|
660
|
+
AliExpress、Alibaba.com、Accio.com(阿里的 AI 选品工具),以及 1688。1688 需要你的 DSers 账号开通 1688 供应商权限:打开 [DSers → 设置 → 供应商](https://app.dsers.com/) 绑定 1688 账号。
|
|
661
|
+
|
|
662
|
+
**用什么货币?**
|
|
663
|
+
AI 助手会用美元显示售价便于阅读,但实际定价按你店铺的本币应用。DSers 会按店铺配置的货币(Shopify / Wix)自动换算。按变体单独定价和固定售价都以店铺本币为准——拿不准的话问 AI 确认一下。
|
|
664
|
+
|
|
629
665
|
**能同时推送到多个店铺吗?**
|
|
630
666
|
可以。`dsers_store_push` 支持一条命令将商品推送到所有已连接的 Shopify 和 Wix 店铺,支持按店铺设置不同的定价和可见性。
|
|
631
667
|
|
|
668
|
+
**能不能跳过浏览器登录、直接写死 token?**
|
|
669
|
+
可以,headless / CI 环境设置 `DSERS_ACCESS_TOKEN`(和可选的 `DSERS_REFRESH_TOKEN`)环境变量即可跳过 OAuth。Token 来自任意机器上跑一次 `login` 后从 `~/.dsers-mcp/session.json` 里拷贝。交互式用户还是建议用 `npx @lofder/dsers-mcp-product login`——更安全,token 自动续期。
|
|
670
|
+
|
|
671
|
+
### 疑难排查
|
|
672
|
+
|
|
673
|
+
**推送返回 `persist_failed` 或 `CODEC` 错误**
|
|
674
|
+
v1.5.7 已修。确认版本是最新:`npm view @lofder/dsers-mcp-product version`。必要时用 `npx -y @lofder/dsers-mcp-product@latest` 重装。
|
|
675
|
+
|
|
676
|
+
**推送被拦截,提示"定价规则冲突"**
|
|
677
|
+
DSers 店铺自己开了定价规则,同时你又通过 MCP 设了定价规则。二选一:要么在推送选项里加 `pricing_rule_behavior='apply_store_pricing_rule'`(采纳店铺端规则),要么在 DSers 设置里关掉定价规则、让 MCP 管定价。详见上面[定价规则冲突检测](#定价规则冲突检测)小节。
|
|
678
|
+
|
|
679
|
+
**1688 链接导入失败,提示"不支持的来源"**
|
|
680
|
+
DSers 账号需要开通 1688 来源授权。去 [DSers 设置 → 供应商](https://app.dsers.com/) 绑定 1688 卖家账号。AliExpress 默认就能用,1688 需要手动开。
|
|
681
|
+
|
|
682
|
+
**`npx @lofder/dsers-mcp-product login` 打开浏览器但卡住**
|
|
683
|
+
登录流程需要 localhost 3001–3003 端口可用(OAuth 回调要用)。如果这几个端口被占(其他 MCP 服务、本地 dev server),先关掉,或者先执行 `PORT=3004` 再跑 login。
|
|
684
|
+
|
|
685
|
+
**远程版用一阵后返回 401**
|
|
686
|
+
OAuth access token 到期了。当前远程版还不自动续期——在 MCP 客户端里断开重连、重新授权就行。refresh token 支持在[后续计划](#后续计划)里。
|
|
687
|
+
|
|
688
|
+
**`npx dsers-mcp-product: command not found`(退出码 127)**
|
|
689
|
+
你在本地源码仓库里直接跑 `npx`,但没装过 npm 包。用 `node dist/cli.js login` 代替。`npx` 命令需要 `npm link` 或真的装过 npm 包才能解析到 binary。`dist/` 不存在的话先 `npm run build`。
|
|
690
|
+
|
|
632
691
|
### 其他版本
|
|
633
692
|
|
|
634
|
-
也提供 [Python 版本](https://github.com/lofder/dsers-mcp-product-py)
|
|
693
|
+
也提供 [Python 版本](https://github.com/lofder/dsers-mcp-product-py),作为功能对齐的精简子集,适合本地 stdio 部署。主要维护仍然是 TypeScript 版,优先用 TS。
|
|
635
694
|
|
|
636
695
|
### 许可证
|
|
637
696
|
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Detect MCP client identity from request headers.
|
|
3
|
+
*
|
|
4
|
+
* Canonical clients we explicitly recognise:
|
|
5
|
+
* - "claude-desktop" — Anthropic Claude Desktop app
|
|
6
|
+
* - "cursor" — Cursor IDE
|
|
7
|
+
* - "windsurf" — Codeium Windsurf
|
|
8
|
+
* - "claude-code" — Claude Code CLI
|
|
9
|
+
* - "agent-sdk" — Claude Agent SDK (TS/Python)
|
|
10
|
+
* - "mcp-inspector" — MCP Inspector tool
|
|
11
|
+
* - "browser" — anything that looks like a browser (scanner / testing)
|
|
12
|
+
* - "unknown" — fallback
|
|
13
|
+
*
|
|
14
|
+
* Source of truth is the HTTP User-Agent the MCP client sends on every request.
|
|
15
|
+
* Some clients don't send a distinctive UA; we fall back gracefully.
|
|
16
|
+
*/
|
|
17
|
+
export declare function detectMcpClient(userAgent: string | null | undefined): string;
|
|
18
|
+
//# sourceMappingURL=client-detect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client-detect.d.ts","sourceRoot":"","sources":["../../src/analytics/client-detect.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAuB5E"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Detect MCP client identity from request headers.
|
|
3
|
+
*
|
|
4
|
+
* Canonical clients we explicitly recognise:
|
|
5
|
+
* - "claude-desktop" — Anthropic Claude Desktop app
|
|
6
|
+
* - "cursor" — Cursor IDE
|
|
7
|
+
* - "windsurf" — Codeium Windsurf
|
|
8
|
+
* - "claude-code" — Claude Code CLI
|
|
9
|
+
* - "agent-sdk" — Claude Agent SDK (TS/Python)
|
|
10
|
+
* - "mcp-inspector" — MCP Inspector tool
|
|
11
|
+
* - "browser" — anything that looks like a browser (scanner / testing)
|
|
12
|
+
* - "unknown" — fallback
|
|
13
|
+
*
|
|
14
|
+
* Source of truth is the HTTP User-Agent the MCP client sends on every request.
|
|
15
|
+
* Some clients don't send a distinctive UA; we fall back gracefully.
|
|
16
|
+
*/
|
|
17
|
+
export function detectMcpClient(userAgent) {
|
|
18
|
+
if (!userAgent)
|
|
19
|
+
return "unknown";
|
|
20
|
+
const ua = userAgent.toLowerCase();
|
|
21
|
+
// Order matters — check more specific first
|
|
22
|
+
if (ua.includes("claude-code"))
|
|
23
|
+
return "claude-code";
|
|
24
|
+
if (ua.includes("claude") && ua.includes("desktop"))
|
|
25
|
+
return "claude-desktop";
|
|
26
|
+
if (ua.startsWith("claude/") || ua.includes("claude.ai"))
|
|
27
|
+
return "claude-desktop";
|
|
28
|
+
if (ua.includes("cursor"))
|
|
29
|
+
return "cursor";
|
|
30
|
+
if (ua.includes("windsurf") || ua.includes("codeium"))
|
|
31
|
+
return "windsurf";
|
|
32
|
+
if (ua.includes("agent-sdk") || ua.includes("claude-agent-sdk"))
|
|
33
|
+
return "agent-sdk";
|
|
34
|
+
if (ua.includes("mcp-inspector") || ua.includes("modelcontextprotocol/inspector")) {
|
|
35
|
+
return "mcp-inspector";
|
|
36
|
+
}
|
|
37
|
+
if (ua.includes("postman"))
|
|
38
|
+
return "postman";
|
|
39
|
+
if (ua.includes("curl"))
|
|
40
|
+
return "curl";
|
|
41
|
+
if (ua.includes("mozilla") || ua.includes("webkit") || ua.includes("chrome")) {
|
|
42
|
+
return "browser";
|
|
43
|
+
}
|
|
44
|
+
if (ua.includes("node-fetch") || ua.includes("undici"))
|
|
45
|
+
return "node-fetch";
|
|
46
|
+
if (ua.includes("mcp"))
|
|
47
|
+
return "mcp-other";
|
|
48
|
+
return "unknown";
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=client-detect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client-detect.js","sourceRoot":"","sources":["../../src/analytics/client-detect.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,eAAe,CAAC,SAAoC;IAClE,IAAI,CAAC,SAAS;QAAE,OAAO,SAAS,CAAC;IACjC,MAAM,EAAE,GAAG,SAAS,CAAC,WAAW,EAAE,CAAC;IAEnC,4CAA4C;IAC5C,IAAI,EAAE,CAAC,QAAQ,CAAC,aAAa,CAAC;QAAE,OAAO,aAAa,CAAC;IACrD,IAAI,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC;QAAE,OAAO,gBAAgB,CAAC;IAC7E,IAAI,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC;QAAE,OAAO,gBAAgB,CAAC;IAClF,IAAI,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAAE,OAAO,QAAQ,CAAC;IAC3C,IAAI,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC;QAAE,OAAO,UAAU,CAAC;IACzE,IAAI,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,QAAQ,CAAC,kBAAkB,CAAC;QAAE,OAAO,WAAW,CAAC;IACpF,IAAI,EAAE,CAAC,QAAQ,CAAC,eAAe,CAAC,IAAI,EAAE,CAAC,QAAQ,CAAC,gCAAgC,CAAC,EAAE,CAAC;QAClF,OAAO,eAAe,CAAC;IACzB,CAAC;IACD,IAAI,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC;QAAE,OAAO,SAAS,CAAC;IAC7C,IAAI,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC;QAAE,OAAO,MAAM,CAAC;IACvC,IAAI,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC7E,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,IAAI,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAAE,OAAO,YAAY,CAAC;IAC5E,IAAI,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,WAAW,CAAC;IAE3C,OAAO,SAAS,CAAC;AACnB,CAAC"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Analytics reader — consumed by the /admin/stats route.
|
|
3
|
+
*
|
|
4
|
+
* Reads the same Redis schema that tracker.ts writes. Everything is
|
|
5
|
+
* read-only — no state is mutated here.
|
|
6
|
+
*
|
|
7
|
+
* The dashboard asks for a "Last N days" window (default 7) and we
|
|
8
|
+
* fan out reads into one big pipeline so rendering is snappy even with
|
|
9
|
+
* Upstash's per-command HTTP cost.
|
|
10
|
+
*/
|
|
11
|
+
export interface Stats {
|
|
12
|
+
configured: boolean;
|
|
13
|
+
errorMessage?: string;
|
|
14
|
+
generatedAt: string;
|
|
15
|
+
window: {
|
|
16
|
+
days: number;
|
|
17
|
+
};
|
|
18
|
+
pv: {
|
|
19
|
+
total: number;
|
|
20
|
+
today: number;
|
|
21
|
+
byDay: {
|
|
22
|
+
date: string;
|
|
23
|
+
count: number;
|
|
24
|
+
}[];
|
|
25
|
+
};
|
|
26
|
+
uv: {
|
|
27
|
+
total: number;
|
|
28
|
+
today: number;
|
|
29
|
+
byDay: {
|
|
30
|
+
date: string;
|
|
31
|
+
count: number;
|
|
32
|
+
}[];
|
|
33
|
+
};
|
|
34
|
+
hourly: {
|
|
35
|
+
hour: string;
|
|
36
|
+
pv: number;
|
|
37
|
+
uv: number;
|
|
38
|
+
}[];
|
|
39
|
+
tools: {
|
|
40
|
+
name: string;
|
|
41
|
+
calls: number;
|
|
42
|
+
ok: number;
|
|
43
|
+
fail: number;
|
|
44
|
+
successRate: number;
|
|
45
|
+
}[];
|
|
46
|
+
clients: {
|
|
47
|
+
name: string;
|
|
48
|
+
count: number;
|
|
49
|
+
}[];
|
|
50
|
+
countries: {
|
|
51
|
+
code: string;
|
|
52
|
+
count: number;
|
|
53
|
+
}[];
|
|
54
|
+
}
|
|
55
|
+
export declare function getStats(days?: number): Promise<Stats>;
|
|
56
|
+
//# sourceMappingURL=stats.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stats.d.ts","sourceRoot":"","sources":["../../src/analytics/stats.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAuEH,MAAM,WAAW,KAAK;IACpB,UAAU,EAAE,OAAO,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACzB,EAAE,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,EAAE,CAAA;KAAE,CAAC;IAC/E,EAAE,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,EAAE,CAAA;KAAE,CAAC;IAC/E,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACnD,KAAK,EAAE;QACL,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;QACd,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;KACrB,EAAE,CAAC;IACJ,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC3C,SAAS,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAC9C;AAED,wBAAsB,QAAQ,CAAC,IAAI,SAAI,GAAG,OAAO,CAAC,KAAK,CAAC,CA+GvD"}
|