new-erp-mcp 0.3.1 → 0.4.0
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/README.md +45 -179
- package/docs/api.md +15 -6
- package/docs/erp-asin-contract.md +3 -1
- package/docs/mcp.md +23 -17
- package/package.json +3 -4
- package/scripts/catalog-list.js +0 -11
- package/scripts/category-summary.js +0 -11
- package/scripts/erp-options.js +0 -3
- package/scripts/game-product-batch.js +3 -13
- package/scripts/game-product-list.js +0 -11
- package/scripts/inventory-list.js +1 -3
- package/scripts/local-session.js +2 -2
- package/scripts/login-browser.js +1 -1
- package/scripts/logistics-channel-list.js +0 -3
- package/scripts/market-order-list.js +1 -5
- package/scripts/mcp-catalog.js +26 -12
- package/scripts/mcp.js +8 -7
- package/scripts/outer-package-list.js +1 -3
- package/scripts/packing-batch-detail.js +1 -3
- package/scripts/packing-batch-list.js +1 -3
- package/scripts/packing-detail-export.js +1 -6
- package/scripts/packing-detail.js +1 -3
- package/scripts/packing-order-list.js +1 -5
- package/scripts/plan-delivery-order-list.js +1 -3
- package/scripts/product-declaration-list.js +1 -3
- package/scripts/product-detail.js +0 -11
- package/scripts/sales-volume-export.js +21 -24
- package/scripts/sales-volume-ranking.js +2 -12
- package/scripts/shared.js +10 -103
- package/scripts/stocking-assembly-inbound.js +0 -6
- package/scripts/supply-evidence.js +0 -6
- package/scripts/login.js +0 -74
- package/scripts/logout.js +0 -9
- package/scripts/new-erp.js +0 -92
- package/scripts/packing-order-pages.js +0 -25
- package/scripts/setup.js +0 -33
- package/skills/new-erp-scripts/SKILL.md +0 -66
- package/skills/new-erp-scripts/agents/openai.yaml +0 -3
- package/skills/new-erp-scripts/references/query-guide.md +0 -111
package/README.md
CHANGED
|
@@ -1,219 +1,85 @@
|
|
|
1
1
|
# new-erp-mcp
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
本地 stdio MCP 服务与 JavaScript API,用于查询 ERP 商品、销量、订单、库存、装箱、配货及物流数据。需要 Node.js 20+。
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## MCP 安装与启动
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
## 快速开始
|
|
10
|
-
|
|
11
|
-
以下 SKU、ID、项目及仓库均为脱敏示例;使用时替换为有权限访问的真实值。项目和仓库代码可通过 `new-erp options` 查询。
|
|
12
|
-
|
|
13
|
-
### 1. 安装命令行工具
|
|
14
|
-
|
|
15
|
-
需要 Node.js 20+。npm 包名为 `new-erp-mcp`,安装后使用 `new-erp` 命令。也支持 `npm install -g ./new-erp-mcp-0.3.1.tgz` 安装下载的 npm 包。
|
|
7
|
+
全局安装后可用 Codex 注册:
|
|
16
8
|
|
|
17
9
|
```sh
|
|
18
|
-
node --version
|
|
19
10
|
npm install -g new-erp-mcp
|
|
20
|
-
new-erp
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
也可以通过 `npx` 直接运行,替换末尾命令和选项即可:
|
|
24
|
-
|
|
25
|
-
```sh
|
|
26
|
-
npx --package=new-erp-mcp new-erp game-product-list --help
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
需要固定版本时使用 `new-erp-mcp@0.3.1`。
|
|
30
|
-
|
|
31
|
-
### 2. 配置 ERP
|
|
32
|
-
|
|
33
|
-
推荐打开本机临时网页登录,一次填写 ERP 网址、账号和密码:
|
|
34
|
-
|
|
35
|
-
```sh
|
|
36
|
-
new-erp login --browser
|
|
11
|
+
codex mcp add new-erp -- new-erp-mcp
|
|
37
12
|
```
|
|
38
13
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
网页登录成功后自动关闭临时服务。MCP 未登录时才返回详细引导,让 Agent 打开登录页并在完成后重试查询;初始化只加载两个入口,业务参数按需发现。也支持 `new-erp login --baseUrl https://your-erp.example.com` 在终端隐藏输入密码,或使用客户端私密输入卡。
|
|
42
|
-
|
|
43
|
-
已有 token 时,也可在运行命令的目录创建不提交到版本库的 `config.json`:
|
|
14
|
+
其他 stdio 客户端可配置:
|
|
44
15
|
|
|
45
16
|
```json
|
|
46
17
|
{
|
|
47
|
-
"
|
|
48
|
-
|
|
18
|
+
"mcpServers": {
|
|
19
|
+
"new-erp": {
|
|
20
|
+
"command": "new-erp-mcp",
|
|
21
|
+
"args": []
|
|
22
|
+
}
|
|
23
|
+
}
|
|
49
24
|
}
|
|
50
25
|
```
|
|
51
26
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
### 3. 执行查询
|
|
55
|
-
|
|
56
|
-
```sh
|
|
57
|
-
new-erp game-product-list --sku DEMO-SKU-001
|
|
58
|
-
new-erp product-detail --id 12345
|
|
59
|
-
new-erp product-detail --asin B012345678
|
|
60
|
-
new-erp sales-volume-ranking --startDate 2026-01-01 --endDate 2026-01-31
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
## 命令行使用
|
|
64
|
-
|
|
65
|
-
所有已安装命令统一通过 `new-erp <subcommand>` 调用。运行 `new-erp --help` 查看可用命令和简要说明,运行 `new-erp <subcommand> --help` 查看具体参数。迁移提示:原来独立调用 `new-erp-foo` 的方式改为 `new-erp foo`;安装包仅提供统一入口。
|
|
66
|
-
|
|
67
|
-
每个命令都支持 `--help`、`--option value` 和 `--option=value`。先查看帮助确认所需参数。
|
|
68
|
-
|
|
69
|
-
```sh
|
|
70
|
-
# 批量查商品
|
|
71
|
-
new-erp game-product-batch --skus 'SKU-A,SKU-B'
|
|
72
|
-
|
|
73
|
-
# 查市场订单:默认搜索系统单号;searchType 6 按 SKU 搜索
|
|
74
|
-
new-erp market-order-list --searchValue DEMO-ORDER-ID
|
|
75
|
-
new-erp market-order-list --searchType 6 --searchValue DEMO-SKU-001 --fetchAll
|
|
76
|
-
|
|
77
|
-
# 查国内仓的库存批次与 BOM
|
|
78
|
-
new-erp inventory-list --sku DEMO-SKU-003 --stockCode DEMO-STOCK --fetchAll
|
|
79
|
-
|
|
80
|
-
# 按总单号查询装箱列表
|
|
81
|
-
new-erp packing-order-list --packingNo YOUR-ORDER --stockFrom DEMO-FROM --fetchAll
|
|
82
|
-
|
|
83
|
-
# 导出平台销量,保留 ERP 的 GBK CSV
|
|
84
|
-
new-erp sales-volume-export --startDate 2026-01-01 --endDate 2026-01-31 --aggregateBy platform --output ./platform-2026-01.csv
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
成功结果写入 stdout,通常为 JSON 数组或对象;错误写入 stderr,并以非零状态退出。`new-erp packing-order-pages` 每页输出一行 JSON(NDJSON),需按行处理。
|
|
88
|
-
|
|
89
|
-
市场订单、装箱、配货、库存等列表默认第1页20条,返回 `list/totalCount/fetchedCount/complete/source`。完整查询使用 `--fetchAll` 并从第1页开始;`--pageSize` 最多100,`--maxPages` 默认100、最多1000。分页截断、重复记录或总数变化会报错。
|
|
90
|
-
|
|
91
|
-
大范围装箱历史可逐页读取,按项目和月份拆分:
|
|
92
|
-
|
|
93
|
-
```sh
|
|
94
|
-
new-erp packing-order-pages --project DEMO-PROJECT --warehouses DEMO-DEST --startDate 2026-07-01 --endDate 2026-07-31 --pageSize 100
|
|
95
|
-
new-erp packing-detail-export --project DEMO-PROJECT --warehouses DEMO-DEST --startDate 2026-07-01 --endDate 2026-07-31 --output ./packing-2026-07.xlsx
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
装箱列表支持精确总单号查询;批量明细导出仍需完整的项目、目的仓、开始和结束日期。导出不覆盖已有文件,装箱导出可用 `--taskId` 恢复原任务。范围限制和数据口径见 [查询指南](./skills/new-erp-scripts/references/query-guide.md)。
|
|
99
|
-
|
|
100
|
-
## 按 ASIN 查询 ERP 商品和图片
|
|
27
|
+
也可在客户端配置 `npx -y new-erp-mcp`:
|
|
101
28
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
new-erp
|
|
29
|
+
```json
|
|
30
|
+
{
|
|
31
|
+
"mcpServers": {
|
|
32
|
+
"new-erp": {
|
|
33
|
+
"command": "npx",
|
|
34
|
+
"args": ["-y", "new-erp-mcp"]
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
106
38
|
```
|
|
107
39
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
同一 ASIN 对应多个 SKU 或店铺时保留全部匹配;商品详情附带 `asinListings` 和 `asinSource`。没有匹配、未配对 ERP SKU、权限不足或分页不完整时直接报错。ASIN 和 SKU 搜索默认各自最多100页,每页100条,可用 `--maxPages` 调整,上限1000页。接口和字段见 [ASIN 查询 API](./docs/api.md#按-asin-查询-erp-商品)。
|
|
40
|
+
旧的 `new-erp` 命令行子命令和随包技能已移除。请删除旧 MCP 配置并按上例重新注册、重启客户端;保存在包目录之外的登录会话会保留。唯一安装的可执行入口是 MCP 服务 `new-erp-mcp`,不接受命令行参数。
|
|
111
41
|
|
|
112
|
-
##
|
|
42
|
+
## 发现与执行
|
|
113
43
|
|
|
114
|
-
|
|
44
|
+
服务仅提供 `erp_discover` 与 `erp_execute` 两个 MCP 工具。先发现参数,再执行操作:
|
|
115
45
|
|
|
116
|
-
```
|
|
117
|
-
|
|
46
|
+
```json
|
|
47
|
+
{"query":"商品 ASIN"}
|
|
48
|
+
{"operation":"product_detail"}
|
|
118
49
|
```
|
|
119
50
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
`new-erp mcp` 只注册 `erp_discover` 和 `erp_execute` 两个入口,按需发现并调用现有全部 24 项业务能力。包括商品、ASIN 图片、销量、订单、库存、装箱、配货、物流和导出;`auth.login` 可直接打开本机配置页,不需要 Agent 执行终端命令。业务只使用保存的个人会话,不读取共享 token。
|
|
123
|
-
|
|
124
|
-
导出返回任务编号及本地文件路径,长任务不阻塞客户端;参数与完整能力目录通过 `erp_discover` 获取。MCP 用户无需安装 CLI 技能。0.3 起,原四个直接工具改为 `erp_execute` 的业务能力名称。
|
|
125
|
-
|
|
126
|
-
安装、登录保存位置、手动配置和更新方法见 [本地 MCP 指南](./docs/mcp.md)。
|
|
51
|
+
发现结果包含 24 项业务操作和 7 项本机辅助操作。业务能力覆盖商品与分类、ASIN、销量、市场订单、库存、备货、装箱、配货、物流与导出。辅助操作为 `auth.login`、`auth.status`、`auth.logout`、`jobs.status`、`jobs.list`、`jobs.resume`、`jobs.cancel`。
|
|
127
52
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
MCP 用户无需安装仓库技能。需要让 Agent 直接使用 CLI、处理批量导出或分页时,可选安装:
|
|
131
|
-
|
|
132
|
-
```sh
|
|
133
|
-
npx skills add PIZZAxBOY/new-erp-scripts --skill new-erp-scripts --agent codex
|
|
53
|
+
```json
|
|
54
|
+
{"operation":"product_detail","params":{"asin":"B012345678"}}
|
|
134
55
|
```
|
|
135
56
|
|
|
136
|
-
|
|
57
|
+
首次使用时通过 `erp_execute` 调用 `auth.login`。MCP 返回本机临时网页地址,由用户亲自输入 ERP 地址、账号和密码;Agent 不查看、不填写或传递密码。服务只保存私有本机会话中的 token,不保存密码。若页面过期,再次调用 `auth.login`。使用 `auth.logout` 删除本机会话;不会撤销 ERP 上游 token。
|
|
137
58
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
> 查询 DEMO-SKU-001 的商品信息。
|
|
141
|
-
>
|
|
142
|
-
> 导出 DEMO-PROJECT 项目 DEMO-DEST 仓在 2026 年 7 月扫描出库的装箱明细,保存为 XLSX。
|
|
143
|
-
|
|
144
|
-
技能只包含调用说明,运行代码需独立安装或通过 `npx` 获取。技能入口见 [SKILL.md](./skills/new-erp-scripts/SKILL.md),完整命令及数据口径见 [查询指南](./skills/new-erp-scripts/references/query-guide.md)。
|
|
59
|
+
导出以异步任务运行。使用稳定的 `requestId` 避免重复提交,通过 `jobs.status` 或 `jobs.list` 查询;装箱导出可用 `jobs.resume` 按原范围恢复。导出文件保存在本地受限任务目录,不接受调用方指定路径。
|
|
145
60
|
|
|
146
61
|
## JavaScript API
|
|
147
62
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
```sh
|
|
151
|
-
npm install new-erp-mcp
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
通过 ES module 导入,选项与 CLI 同名:
|
|
63
|
+
自定义消费者可从包导入业务 API:
|
|
155
64
|
|
|
156
65
|
```js
|
|
157
|
-
import { gameProductList,
|
|
66
|
+
import { gameProductList, productDetail } from 'new-erp-mcp';
|
|
158
67
|
|
|
159
68
|
const products = await gameProductList({ sku: 'DEMO-SKU-001' });
|
|
160
|
-
const
|
|
161
|
-
startDate: '2026-01-01',
|
|
162
|
-
endDate: '2026-01-31',
|
|
163
|
-
fetchAll: true,
|
|
164
|
-
});
|
|
69
|
+
const detail = await productDetail({ asin: 'B012345678' });
|
|
165
70
|
```
|
|
166
71
|
|
|
167
|
-
`
|
|
168
|
-
|
|
169
|
-
## 配置与认证
|
|
170
|
-
|
|
171
|
-
| 环境变量 | 配置文件字段 | 用途 |
|
|
172
|
-
| --- | --- | --- |
|
|
173
|
-
| `NEW_ERP_BASE_URL` | `baseUrl` | ERP 地址 |
|
|
174
|
-
| `NEW_ERP_TOKEN` | `token` | 已有 token |
|
|
175
|
-
| `NEW_ERP_USERNAME` | `username` | 登录用户名 |
|
|
176
|
-
| `NEW_ERP_PASSWORD` | `password` | 登录密码 |
|
|
177
|
-
| `NEW_ERP_CONFIG` | 无 | 指定配置文件路径,默认读取当前目录的 `config.json` |
|
|
178
|
-
| `NEW_ERP_SESSION_FILE` | 无 | 指定本机登录会话文件路径;默认位于当前系统用户的配置目录 |
|
|
179
|
-
|
|
180
|
-
环境变量覆盖项目配置文件中的同名值。CLI/API 的 ERP 地址最后回退到本机登录会话;认证先使用显式 token,再使用环境变量或项目配置中的 token,然后使用地址匹配且未过期的本机会话,最后才尝试账号密码登录。MCP 的 ERP 查询始终绑定本机登录会话,不使用上述共享配置回退。
|
|
72
|
+
API 函数名、参数与返回契约保持稳定。底层 `erpClient` 可用于自定义分页查询。配置 `NEW_ERP_BASE_URL`,并按调用场景提供 token 或使用项目配置;MCP 查询只使用本机私有登录会话,不回退到共享配置中的 token 或账号密码。详见 [API 文档](./docs/api.md)。
|
|
181
73
|
|
|
182
|
-
|
|
74
|
+
## 使用边界
|
|
183
75
|
|
|
184
|
-
|
|
76
|
+
- 示例 SKU、订单号、ID、ASIN、项目和仓库均为占位符;先确认访问权限和查询范围。
|
|
77
|
+
- 查询操作只读取 ERP 业务数据;导出会创建 ERP 下载任务及本地文件,但不创建或修改业务单据。
|
|
78
|
+
- ERP 搜索可能模糊匹配。核对返回的 SKU、ASIN、国家、状态与时间范围;不要把不同批次、BOM 或包装版本自动合并。
|
|
79
|
+
- `found` 只表示搜索有返回,不保证 SKU 精确命中;分页结果应检查总数和完整性标记。计划/预计数据不等于实际入库或签收凭证。
|
|
80
|
+
- 重量、尺寸和数量按 ERP 原始字段及单位保留,不猜测或补齐缺失值。原始响应可能含敏感业务信息,分享前应检查并脱敏。
|
|
81
|
+
- 只查询明确授权的数据。不要把密码、token 或会话文件写入对话、日志或版本库。
|
|
185
82
|
|
|
186
|
-
##
|
|
83
|
+
## 市场订单与 ASIN 契约
|
|
187
84
|
|
|
188
|
-
|
|
189
|
-
| --- | --- |
|
|
190
|
-
| 商品与分类 | `new-erp catalog-list`、`new-erp game-product-list`、`new-erp game-product-batch`、`new-erp product-detail --id/--asin` |
|
|
191
|
-
| 登录与本地 MCP | `new-erp login`、`new-erp logout`、`new-erp setup`、`new-erp mcp` |
|
|
192
|
-
| 销量与汇总 | `new-erp sales-volume-ranking`、`new-erp sales-volume-export`、`new-erp category-summary` |
|
|
193
|
-
| 单据与实际入库 | `new-erp supply-evidence`、`new-erp stocking-assembly-inbound` |
|
|
194
|
-
| 装箱历史与导出 | `new-erp packing-order-list`、`new-erp packing-order-pages`、`new-erp packing-detail`、`new-erp packing-detail-export` |
|
|
195
|
-
| 配货批次与历史明细 | `new-erp packing-batch-list`、`new-erp packing-batch-detail`、`new-erp plan-delivery-order-list` |
|
|
196
|
-
| 库存与包装 | `new-erp inventory-list`、`new-erp outer-package-list` |
|
|
197
|
-
| 物流、申报与枚举 | `new-erp logistics-channel-list`、`new-erp product-declaration-list`、`new-erp options` |
|
|
198
|
-
|
|
199
|
-
各命令的必填选项和适用场景见 [查询指南](./skills/new-erp-scripts/references/query-guide.md#命令选择)。库存预测量、计划单据、BOM 版本和重量单位各有不同口径,汇总前请核对来源。
|
|
200
|
-
|
|
201
|
-
## 开发与验证
|
|
202
|
-
|
|
203
|
-
```text
|
|
204
|
-
scripts/ # CLI 与共享客户端
|
|
205
|
-
index.mjs # JavaScript API 导出
|
|
206
|
-
skills/new-erp-scripts/ # Agent 技能与查询指南
|
|
207
|
-
docs/ # API 与数据口径
|
|
208
|
-
test/ # 自动化测试
|
|
209
|
-
```
|
|
210
|
-
|
|
211
|
-
在仓库根目录可用 `node scripts/new-erp.js <command>` 运行,或用 `npm install -g .` 安装本地版本。验证命令:
|
|
212
|
-
|
|
213
|
-
```sh
|
|
214
|
-
npm ci
|
|
215
|
-
npm test
|
|
216
|
-
npm run check:package
|
|
217
|
-
node --check index.mjs
|
|
218
|
-
for file in scripts/*.js; do node --check "$file"; done
|
|
219
|
-
```
|
|
85
|
+
市场订单使用只读 `GET /marketing/market-order/index`;ASIN 搜索流程及证据见 [ASIN 接口契约](./docs/erp-asin-contract.md)。端点与字段依据 ERP 前端及接口文档核对。
|
package/docs/api.md
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
# JavaScript API 与数据口径
|
|
2
2
|
|
|
3
|
-
安装与配置见 [README](../README.md#javascript-api)
|
|
3
|
+
安装与配置见 [README](../README.md#javascript-api)。函数接收选项对象,返回结果或抛出错误;配置从调用时的当前工作目录或环境变量读取。
|
|
4
|
+
|
|
5
|
+
直接调用 API 时可传 `token`,或通过 `username`、`password` 登录;也可使用
|
|
6
|
+
`NEW_ERP_TOKEN`、`NEW_ERP_USERNAME`、`NEW_ERP_PASSWORD`。基础地址优先使用
|
|
7
|
+
`NEW_ERP_BASE_URL`,其次读取 `NEW_ERP_CONFIG` 指定 JSON 文件的 `baseUrl`,最后使用默认配置。
|
|
8
|
+
API 不会把凭据写入返回值、`source` 或错误文本;MCP 客户端应先通过 `auth.login` 建立会话。
|
|
4
9
|
|
|
5
10
|
## 基础查询与客户端
|
|
6
11
|
|
|
@@ -13,6 +18,10 @@
|
|
|
13
18
|
|
|
14
19
|
`exportGameProducts({ disused: true })` 使用游戏类淘汰产品原生导出接口 `/products/game-product-list/disuse-product-export`;返回下载中心任务 ID 和 XLSX,默认字段为 SKU、品名、单价。
|
|
15
20
|
|
|
21
|
+
`gameProductBatch` 在解释空结果为未找到前会校验分页元数据、列表存在性及行数;
|
|
22
|
+
`salesVolumeRanking`(包括 `categorySummary`)会校验页码、页大小、总数、列表形状和本页行数。
|
|
23
|
+
ERP 返回缺失或不一致的分页数据时直接抛错,不把损坏响应当作空结果。
|
|
24
|
+
|
|
16
25
|
## 按 ASIN 查询 ERP 商品
|
|
17
26
|
|
|
18
27
|
`productDetail({ asin, token?, maxPages?, raw? })` 返回 ERP 商品详情数组;也支持原有的 `productDetail({ id })`。`id` 与 `asin` 必须二选一,在认证和网络请求前校验。ASIN 必须为10位字母或数字,去除首尾空白并转大写。
|
|
@@ -26,7 +35,7 @@ for (const product of products) {
|
|
|
26
35
|
}
|
|
27
36
|
```
|
|
28
37
|
|
|
29
|
-
示例 ASIN 需替换为实际值。
|
|
38
|
+
示例 ASIN 需替换为实际值。MCP 为 `erp_execute({ operation: 'product_detail', params: { asin: 'B012345678' } })`,返回任务回执。MCP 覆盖本文件全部业务能力,参数按需发现,详见 [MCP 指南](./mcp.md)。
|
|
30
39
|
|
|
31
40
|
查询仅访问当前配置的 ERP:
|
|
32
41
|
|
|
@@ -57,11 +66,11 @@ ASIN 查询在原商品详情字段之外提供:
|
|
|
57
66
|
|
|
58
67
|
`stockingAssemblyInbound` 按精确 SKU 和入库时间汇总备货拼装实际入库流水,用拼装单号核对生产任务。它只统计备货拼装,不包含采购进货或调库。
|
|
59
68
|
|
|
60
|
-
|
|
69
|
+
销量导出每次调用都会提交新的 ERP 导出请求,只匹配提交前不存在、且路由、完整查询条件和日期范围均完全匹配的新任务;不会复用历史成功或失败任务。MCP 层仍以稳定的 `requestId` 对同一请求去重。商品、外包装和装箱导出同样拒绝多个匹配的新任务,并在识别任务后固定任务 ID,避免后续轮询切换到其他任务。
|
|
61
70
|
|
|
62
71
|
## 市场订单
|
|
63
72
|
|
|
64
|
-
`marketOrderList(options)`
|
|
73
|
+
`marketOrderList(options)` 只读 `GET /index.php?r=/marketing/market-order/index`,不创建、更新或导出订单。路由与响应结构由 ERP 接口文档及前端 `evaluationOrder` 模块交叉确认,搜索字段依据前端请求映射;未使用生产凭据实测。
|
|
65
74
|
|
|
66
75
|
| 选项 | ERP 参数与含义 |
|
|
67
76
|
| --- | --- |
|
|
@@ -115,7 +124,7 @@ const detail = await exportPackingDetails({ ...selection, packingNo: 'YOUR-ORDER
|
|
|
115
124
|
// 用保存的ID恢复:exportPackingDetails({ ...selection, packingNo: 'YOUR-ORDER', stockFrom: 'DEMO-FROM', taskId })
|
|
116
125
|
```
|
|
117
126
|
|
|
118
|
-
|
|
127
|
+
MCP 的 `packing_order_pages` 操作逐页读取并保存为本地 NDJSON 文件,通过 `jobs.status` 获取任务结果和文件路径。装箱导出任务也通过 `jobs.status` 查询,或按文档使用 `taskId` 恢复。导出保持 ERP 原文,包含 SKU、数量、渠道、箱实重kg和尺寸cm,不直接返回四种运输占比或货代最终结算重量。
|
|
119
128
|
|
|
120
129
|
### 请求数验证
|
|
121
130
|
|
|
@@ -123,7 +132,7 @@ const detail = await exportPackingDetails({ ...selection, packingNo: 'YOUR-ORDER
|
|
|
123
132
|
|
|
124
133
|
## 配货、库存与包装
|
|
125
134
|
|
|
126
|
-
以下接口均支持 ES module
|
|
135
|
+
以下接口均支持 ES module 导入。只读取 ERP 数据,不创建或修改业务单据。
|
|
127
136
|
|
|
128
137
|
| API | 必填选项 | 返回内容 |
|
|
129
138
|
| --- | --- | --- |
|
|
@@ -22,4 +22,6 @@ ERP 前端的 `jyAmazon` API 模块声明:
|
|
|
22
22
|
|
|
23
23
|
## 验证边界
|
|
24
24
|
|
|
25
|
-
已核对真实前端的路由、字段映射及使用方式,并以本地接口响应验证
|
|
25
|
+
已核对真实前端的路由、字段映射及使用方式,并以本地接口响应验证 JavaScript API/MCP 的完整调用链、分页、账号隔离、模糊匹配过滤和异常处理。已使用登录账号通过 MCP 实测 ASIN 查询,验证停用商品详情及图片获取;公开文档不记录业务标识和结果。实际账号未开放该菜单或搜索枚举时直接报错,不转接领星外部接口或公开亚马逊商品页。
|
|
26
|
+
|
|
27
|
+
本次 MCP-only 重构沿用上述历史验证证据,并以本地 fixture 和 mock 服务复核调用链;没有新增认证后的 ERP 测试或生产查询。
|
package/docs/mcp.md
CHANGED
|
@@ -1,17 +1,22 @@
|
|
|
1
1
|
# 安装与使用本地 MCP
|
|
2
2
|
|
|
3
|
-
需要 Node.js 20+。MCP 在用户自己的电脑运行,使用各自的 ERP 登录和权限,无需部署服务器。
|
|
3
|
+
需要 Node.js 20+。MCP 在用户自己的电脑运行,使用各自的 ERP 登录和权限,无需部署服务器。
|
|
4
4
|
|
|
5
5
|
## 安装并接入客户端
|
|
6
6
|
|
|
7
7
|
```sh
|
|
8
8
|
npm install -g new-erp-mcp
|
|
9
|
-
new-erp setup --client codex
|
|
10
9
|
```
|
|
11
10
|
|
|
12
|
-
|
|
11
|
+
将启动命令配置为标准 stdio MCP。Codex 可用全局安装包手动注册:
|
|
13
12
|
|
|
14
|
-
|
|
13
|
+
```sh
|
|
14
|
+
codex mcp add new-erp -- new-erp-mcp
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
也可不全局安装,直接配置 `npx -y new-erp-mcp`。其他支持本地 stdio 的客户端将
|
|
18
|
+
`new-erp-mcp`(或 `npx -y new-erp-mcp`)作为启动命令,标准输入和输出仅传输 MCP 协议。
|
|
19
|
+
旧版 `new-erp mcp`、`new-erp setup` 配置需要删除并重新注册;保存的登录会话不会丢失。
|
|
15
20
|
|
|
16
21
|
## 首次在网页完成配置
|
|
17
22
|
|
|
@@ -25,14 +30,8 @@ erp_execute({ operation: 'auth.login', params: {} })
|
|
|
25
30
|
|
|
26
31
|
页面五分钟后失效,成功、取消或过期后关闭临时服务。登录失败可在原页面重试,不会覆盖原会话。Agent 可查询 `auth.status`,登录成功后重试原业务操作,无需重启 MCP。
|
|
27
32
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
```sh
|
|
31
|
-
new-erp login --browser
|
|
32
|
-
new-erp login --browser --open false
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
第二条只输出登录链接。网页不可用时,使用客户端私密输入能力或在自己的终端运行 `new-erp login --baseUrl https://your-erp.example.com`,隐藏输入密码。不要在聊天正文或命令参数中提交密码。
|
|
33
|
+
登录仅通过 MCP 的 `auth.login` 完成。网页不可用时,在返回的本机 URL 中手动打开页面;
|
|
34
|
+
不要在聊天正文、工具参数或任何命令参数中提交密码。
|
|
36
35
|
|
|
37
36
|
## 按需发现能力和参数
|
|
38
37
|
|
|
@@ -53,7 +52,8 @@ erp_execute({ operation: 'product_detail', params: { asin: 'B012345678' } })
|
|
|
53
52
|
|
|
54
53
|
ASIN 是示例值。其他业务参数以对应的 `erp_discover({ operation })` 结果为准;未知参数、错误类型和凭据参数会被拒绝。查询只使用本机保存的个人会话,不回退到环境或项目中的共享 token。
|
|
55
54
|
|
|
56
|
-
0.3 起,原四个直接 MCP 工具改为业务能力名称。例如原 `product_detail({ asin })` 改为上面的 `erp_execute` 调用。
|
|
55
|
+
0.3 起,原四个直接 MCP 工具改为业务能力名称。例如原 `product_detail({ asin })` 改为上面的 `erp_execute` 调用。
|
|
56
|
+
JavaScript API 保留原有入口;旧的终端子命令和随包技能已移除。
|
|
57
57
|
|
|
58
58
|
## 读取任务结果和导出文件
|
|
59
59
|
|
|
@@ -81,7 +81,7 @@ erp_execute({
|
|
|
81
81
|
|
|
82
82
|
文件保存在本机,结果返回 `artifact.path`、类型、字节数等信息;不会把 XLSX、CSV、Base64 或整份大型结果塞进上下文。大型 JSON 完整保存到文件并提供有限预览;逐页装箱读取保存为 NDJSON,分页失败会标记不完整并返回失败,不静默截断。
|
|
83
83
|
|
|
84
|
-
默认导出目录为 `~/Downloads/new-erp`,可用 `NEW_ERP_EXPORT_DIR` 指定专用目录。macOS/Linux 的私有任务目录和文件使用 `0700`、`0600` 权限;Windows 使用当前用户的文件权限。MCP
|
|
84
|
+
默认导出目录为 `~/Downloads/new-erp`,可用 `NEW_ERP_EXPORT_DIR` 指定专用目录。macOS/Linux 的私有任务目录和文件使用 `0700`、`0600` 权限;Windows 使用当前用户的文件权限。MCP 管理输出路径,不接受调用方的 `output` 参数。任务记录不保存 token 或密码;换账号后不能通过 MCP 读取其他账号的任务。
|
|
85
85
|
|
|
86
86
|
## 恢复装箱导出与取消任务
|
|
87
87
|
|
|
@@ -105,10 +105,16 @@ erp_execute({
|
|
|
105
105
|
|
|
106
106
|
```sh
|
|
107
107
|
npm install -g new-erp-mcp@latest
|
|
108
|
-
new-erp
|
|
108
|
+
codex mcp add new-erp -- new-erp-mcp
|
|
109
109
|
```
|
|
110
110
|
|
|
111
|
-
更新后重启客户端以加载新代码。会话文件在包目录之外,有效会话会保留,通常无需重新登录;失效后重新打开登录页。`auth.logout`
|
|
111
|
+
更新后重启客户端以加载新代码。会话文件在包目录之外,有效会话会保留,通常无需重新登录;失效后重新打开登录页。`auth.logout` 删除本机会话,不撤销 ERP 上游 token;已开始的任务继续使用原账号快照,切换账号后不能读取原账号的任务。
|
|
112
|
+
|
|
113
|
+
## 范围与安全
|
|
114
|
+
|
|
115
|
+
业务查询按用户授权与明确范围执行。核对 SKU、ASIN、国家、订单编号、仓库、状态、日期和分页完整性;ERP 模糊搜索可能返回前缀或相似项。计划、预测库存与预计可用量不是实际签收凭证。不同批次、BOM 与包装版本应保留原样;重量和尺寸按 ERP 返回单位解释,不作推断。原始响应可能含敏感数据,复用或分享前先脱敏。
|
|
116
|
+
|
|
117
|
+
本次重构使用本地合成响应和 mock 服务验证,没有进行认证后的生产 ERP 查询。
|
|
112
118
|
|
|
113
119
|
## 打包验证
|
|
114
120
|
|
|
@@ -119,4 +125,4 @@ npm run check:package
|
|
|
119
125
|
npm pack
|
|
120
126
|
```
|
|
121
127
|
|
|
122
|
-
`.tgz` 可通过 `npm install -g ./new-erp-mcp-0.
|
|
128
|
+
`.tgz` 可通过 `npm install -g ./new-erp-mcp-0.4.0.tgz` 安装。发布文件不包含本机会话、项目配置、业务导出或测试数据。使用 `node test/check-package-privacy.js ./new-erp-mcp-0.4.0.tgz` 检查实际归档;检查只报告文件、行号和类别,不输出敏感值。
|
package/package.json
CHANGED
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "new-erp-mcp",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"description": "Local MCP server and JavaScript API for querying new-erp",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public",
|
|
7
7
|
"registry": "https://registry.npmjs.org"
|
|
8
8
|
},
|
|
9
9
|
"exports": "./index.mjs",
|
|
10
10
|
"bin": {
|
|
11
|
-
"new-erp": "scripts/
|
|
11
|
+
"new-erp-mcp": "scripts/mcp.js"
|
|
12
12
|
},
|
|
13
13
|
"files": [
|
|
14
14
|
"index.mjs",
|
|
15
15
|
"scripts/",
|
|
16
|
-
"skills/",
|
|
17
16
|
"docs/"
|
|
18
17
|
],
|
|
19
18
|
"engines": {
|
package/scripts/catalog-list.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
1
|
const {
|
|
3
2
|
asNumberOrNull,
|
|
4
3
|
ArgumentError,
|
|
@@ -6,7 +5,6 @@ const {
|
|
|
6
5
|
getBaseUrl,
|
|
7
6
|
resolveToken,
|
|
8
7
|
requestJson,
|
|
9
|
-
runCli,
|
|
10
8
|
} = require('./shared.js');
|
|
11
9
|
|
|
12
10
|
function parseIdSet(value, label) {
|
|
@@ -119,12 +117,3 @@ async function main(argsValue) {
|
|
|
119
117
|
}
|
|
120
118
|
|
|
121
119
|
module.exports = { main, args };
|
|
122
|
-
|
|
123
|
-
if (require.main === module) {
|
|
124
|
-
runCli({
|
|
125
|
-
name: 'catalog-list',
|
|
126
|
-
description: '获取并展开 new-erp 产品类目。',
|
|
127
|
-
args,
|
|
128
|
-
func: main,
|
|
129
|
-
});
|
|
130
|
-
}
|
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
1
|
const {
|
|
3
2
|
ArgumentError,
|
|
4
3
|
CommandExecutionError,
|
|
5
4
|
EmptyResultError,
|
|
6
5
|
positiveInteger,
|
|
7
|
-
runCli,
|
|
8
6
|
} = require('./shared.js');
|
|
9
7
|
const {
|
|
10
8
|
catalogNamesForIds,
|
|
@@ -154,12 +152,3 @@ async function main(argsValue) {
|
|
|
154
152
|
}
|
|
155
153
|
|
|
156
154
|
module.exports = { main, args };
|
|
157
|
-
|
|
158
|
-
if (require.main === module) {
|
|
159
|
-
runCli({
|
|
160
|
-
name: 'category-summary',
|
|
161
|
-
description: '完整抓取并按 ERP 类目统计 SKU 销量行数。',
|
|
162
|
-
args,
|
|
163
|
-
func: main,
|
|
164
|
-
});
|
|
165
|
-
}
|
package/scripts/erp-options.js
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
const { runCli } = require('./shared.js');
|
|
3
1
|
const { authArgs, enumValue, queryData } = require('./query.js');
|
|
4
2
|
|
|
5
3
|
const sources = {
|
|
@@ -20,4 +18,3 @@ async function main(options = {}) {
|
|
|
20
18
|
}
|
|
21
19
|
|
|
22
20
|
module.exports = { main, args };
|
|
23
|
-
if (require.main === module) runCli({ name: 'options', description: '读取ERP实时仓库、状态等枚举,不推断业务状态含义。', args, func: main });
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
1
|
const {
|
|
3
2
|
asNumberOrNull,
|
|
4
3
|
ArgumentError,
|
|
@@ -10,8 +9,8 @@ const {
|
|
|
10
9
|
positiveInteger,
|
|
11
10
|
requestJson,
|
|
12
11
|
requiredString,
|
|
13
|
-
runCli,
|
|
14
12
|
} = require('./shared.js');
|
|
13
|
+
const { validatePage } = require('./query.js');
|
|
15
14
|
|
|
16
15
|
function parseSkus(value) {
|
|
17
16
|
const raw = requiredString(value, 'skus');
|
|
@@ -48,7 +47,8 @@ async function queryOneSku({ token, querySku, pageSize, productTypeCate, catalog
|
|
|
48
47
|
headers: { token },
|
|
49
48
|
});
|
|
50
49
|
|
|
51
|
-
const
|
|
50
|
+
const totalCount = validatePage(json?.data, 1, pageSize, 'new-erp game-product-batch');
|
|
51
|
+
const rows = json.data.list;
|
|
52
52
|
if (rows.length === 0) {
|
|
53
53
|
return [{
|
|
54
54
|
querySku,
|
|
@@ -70,7 +70,6 @@ async function queryOneSku({ token, querySku, pageSize, productTypeCate, catalog
|
|
|
70
70
|
}];
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
const totalCount = Number(json?.data?.totalCount ?? rows.length);
|
|
74
73
|
return rows.map((row) => {
|
|
75
74
|
const skuInfo = row?.sku_info || {};
|
|
76
75
|
return {
|
|
@@ -124,12 +123,3 @@ async function main(argsValue) {
|
|
|
124
123
|
}
|
|
125
124
|
|
|
126
125
|
module.exports = { main, args };
|
|
127
|
-
|
|
128
|
-
if (require.main === module) {
|
|
129
|
-
runCli({
|
|
130
|
-
name: 'game-product-batch',
|
|
131
|
-
description: '批量查询 new-erp 产品 SKU。',
|
|
132
|
-
args,
|
|
133
|
-
func: main,
|
|
134
|
-
});
|
|
135
|
-
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
1
|
const {
|
|
3
2
|
asNumberOrNull,
|
|
4
3
|
ArgumentError,
|
|
@@ -9,7 +8,6 @@ const {
|
|
|
9
8
|
resolveToken,
|
|
10
9
|
positiveInteger,
|
|
11
10
|
requestJson,
|
|
12
|
-
runCli,
|
|
13
11
|
} = require('./shared.js');
|
|
14
12
|
|
|
15
13
|
const PRODUCT_TYPE_CATE_MAP = {
|
|
@@ -107,12 +105,3 @@ async function main(argsValue) {
|
|
|
107
105
|
}
|
|
108
106
|
|
|
109
107
|
module.exports = { main, args };
|
|
110
|
-
|
|
111
|
-
if (require.main === module) {
|
|
112
|
-
runCli({
|
|
113
|
-
name: 'game-product-list',
|
|
114
|
-
description: '查询 new-erp 产品列表。',
|
|
115
|
-
args,
|
|
116
|
-
func: main,
|
|
117
|
-
});
|
|
118
|
-
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
const { CommandExecutionError, requiredString, runCli } = require('./shared.js');
|
|
1
|
+
const { CommandExecutionError, requiredString } = require('./shared.js');
|
|
3
2
|
const { listArgs, enumValue, queryList } = require('./query.js');
|
|
4
3
|
|
|
5
4
|
const args = [
|
|
@@ -24,4 +23,3 @@ async function main(options = {}) {
|
|
|
24
23
|
}
|
|
25
24
|
|
|
26
25
|
module.exports = { main, args };
|
|
27
|
-
if (require.main === module) runCli({ name: 'inventory-list', description: '读取国内仓即时、占用、在途和预计可用库存;预计可用不等于已签收可装箱。', args, func: main });
|
package/scripts/local-session.js
CHANGED
|
@@ -17,7 +17,7 @@ function readSession() {
|
|
|
17
17
|
descriptor = fs.openSync(sessionFilePath(), fs.constants.O_RDONLY | (fs.constants.O_NOFOLLOW || 0));
|
|
18
18
|
const stat = fs.fstatSync(descriptor);
|
|
19
19
|
if (!stat.isFile() || (process.platform !== 'win32' && (stat.mode & 0o077))) {
|
|
20
|
-
throw new Error('Session file must be a private regular file;
|
|
20
|
+
throw new Error('Session file must be a private regular file; authenticate again with auth.login through erp_execute');
|
|
21
21
|
}
|
|
22
22
|
const session = JSON.parse(fs.readFileSync(descriptor, 'utf8'));
|
|
23
23
|
if (session?.version !== 1 || typeof session.baseUrl !== 'string' || !session.baseUrl
|
|
@@ -27,7 +27,7 @@ function readSession() {
|
|
|
27
27
|
return session;
|
|
28
28
|
} catch (error) {
|
|
29
29
|
if (error.code === 'ENOENT') return null;
|
|
30
|
-
throw new Error('Cannot read local ERP session;
|
|
30
|
+
throw new Error('Cannot read local ERP session; authenticate again with auth.login through erp_execute');
|
|
31
31
|
} finally {
|
|
32
32
|
if (descriptor !== undefined) fs.closeSync(descriptor);
|
|
33
33
|
}
|
package/scripts/login-browser.js
CHANGED
|
@@ -169,7 +169,7 @@ async function runBrowserLogin({ defaults = {}, openBrowser = openLocalBrowser,
|
|
|
169
169
|
signal?.addEventListener('abort', cancel, { once: true });
|
|
170
170
|
process.once('SIGINT', cancel);
|
|
171
171
|
process.once('SIGTERM', cancel);
|
|
172
|
-
timer = setTimeout(() => finish(new CommandExecutionError('
|
|
172
|
+
timer = setTimeout(() => finish(new CommandExecutionError('登录页面已过期,请通过 erp_execute 的 auth.login 重新打开')), timeoutMs);
|
|
173
173
|
server.listen(0, '127.0.0.1', () => {
|
|
174
174
|
if (phase === 'settled') return;
|
|
175
175
|
origin = `http://127.0.0.1:${server.address().port}`;
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
const { runCli } = require('./shared.js');
|
|
3
1
|
const { listArgs, queryList } = require('./query.js');
|
|
4
2
|
|
|
5
3
|
async function main(options = {}) {
|
|
@@ -7,4 +5,3 @@ async function main(options = {}) {
|
|
|
7
5
|
}
|
|
8
6
|
|
|
9
7
|
module.exports = { main, args: listArgs };
|
|
10
|
-
if (require.main === module) runCli({ name: 'logistics-channel-list', description: '查询头程物流渠道、运输方式和材积除数原始配置。', args: listArgs, func: main });
|