beacon-mfg-mcp 1.5.0 → 1.5.1

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.
Files changed (3) hide show
  1. package/RELEASE.md +162 -143
  2. package/package.json +1 -1
  3. package/server.py +25 -3
package/RELEASE.md CHANGED
@@ -1,143 +1,162 @@
1
- # Beacon-MFG 只读 MCP 服务 · v1.5.0
2
-
3
- 让任意支持 MCP 的主流 agent(Claude Desktop / Cline / Continue / WorkBuddy 等)能够
4
- **检索与调用**已发布到 Cloudflare Pages(或 GitHub)的灯塔工厂供应商数据,
5
- **无需 clone 整个仓库、无需任何密钥**。
6
-
7
- ## 设计边界
8
- MCP 只做**只读检索**。后端数据采集、英文翻译、库维护等流水线**不进 MCP、不暴露、不持密钥**,
9
- 也不会落在任何写路径上。对 Android App 与 cron/GUI 流水线**零影响**(详见 `mcp/README.md`)。
10
-
11
- ## 六个只读 tool
12
- | tool | 用途 | 关键参数 |
13
- |------|------|----------|
14
- | `search_vendors` | 按 关键词 / 城市 / 国标码 检索,返回精简档案 | `query` `city` `gb` `limit` `offset` |
15
- | `get_vendor` | 按 id(+国标码)取完整中文档案 | `id`(必填) `gb`(可选) |
16
- | `get_capability_card` | 按 id 取能力卡(工艺/设备/产能/认证) | `id`(必填) |
17
- | `start_sourcing` | 【客户 agent 自动触发】识别找厂/代工/采购意图 → 品类识别→宽召回→澄清,返回 `session_id` | `demand_text`(必填) `audience_id` |
18
- | `answer_sourcing` | 续接澄清轮次:写回客户答案,返回下一轮澄清或初选列表 | `session_id`(必填) `answers` |
19
- | `refine_sourcing` | 推荐轮次交互:`details`/`more`/`best` | `session_id`(必填) `action` `value` |
20
-
21
- 后三个构成「采购寻源」多轮会话链路 `start_sourcing → answer_sourcing → refine_sourcing`,
22
- 依赖仓库平级的 `skills/rfq-kernel` 桥接模块。
23
-
24
- ## 本次更新(v1.5.0)
25
- **`get_vendor` 从 4.5 分钟降到 6 秒(45×)。** 起因是外部实测反馈「HTTP 模式比本地 git 模式慢约 100 倍,
26
- 按 id 取一家企业要 270 秒」。定位结论:慢不在计算,而在**为了找一个 id 而下载整张 18.4 MB 的
27
- `name-index.jsonl`**——id 只是其中一行。
28
-
29
- - **idmap 定址分片**:新增 `skills/registry/index/idmap/`,`id → 国标码` 按 id 千位切片(183 片 × 1000 id,
30
- 命中那片约 20 KB)。片名由 id 直接算出(`CN-MFG-0093680` → `93680 // 1000` → `093.jsonl`),
31
- **不需要目录表、不需要额外请求**。
32
- - **零 404 的开关设计**:idmap 的元信息放在 `manifest.metadata.idmap` 里——清单本来就要拉,所以是零额外请求。
33
- 清单里**没有**这个块 = 该快照尚未发布 idmap → 整体走老路径。这样「MCP 先升级、数据后发布」的窗口期
34
- 不会变成满屏 404(实测过:一次 404 的冷启动兜底要 44 秒)。
35
- - **按内容哈希缓存分片**:清单里每片都登记了内容 sha1,用它当缓存键——内容不变则**完全不走网络**,
36
- 取到后顺手校验,不符就不写缓存。
37
- - **zh 详情分片改并发取**;**HTTP 超时 15→30 s**;**显式声明 gzip 并手动解压**
38
- (urllib 不会自动解压,JSON 压缩 6~20×,此前一直是裸传)。
39
- - **实测**(`scripts/bench_get_vendor.py`,缓存目录强制隔离):
40
-
41
- | 场景 | 冷启动 | 复用缓存 |
42
- |------|--------|----------|
43
- | 线上 CDN(本次前) | 270.6 s | — |
44
- | 线上 CDN(本次后) | **5.95 s** | **1.22 s** |
45
- | 本地快照 | 1.77 s | 0.80 s |
46
-
47
- - **恢复 `mcp/test_protocol.py`**:上一个提交误删了发布前必跑的协议回归测试,本次还原(313 行)。
48
- 发布前实测三条链路 **16/16 通过**(HTTP / stdio / 标准分帧适配层 + 死代理容错)。
49
- - 数据侧(`skills/registry/index/idmap/**` 与含 `metadata.idmap` 的 `data/manifest.json`)已同步发布到 Pages,
50
- 旧版 MCP 不受影响(读不到 idmap 块就走老路径)。
51
-
52
- ## 本次更新(v1.4.2,已发布)
53
- - **自动升级(自更新)**:新增 `bin/selfupdate.js`,MCP 启动时以**独立 detached 子进程**拉起(绝不阻塞 MCP 启动),
54
- 节流查 npm registry `latest`(默认 24h 一次,可用 `BEACON_MCP_UPDATE_INTERVAL_H` 调),发现新版本即执行
55
- `npm i -g beacon-mfg-mcp@<新版本>`(Windows 上正确走 `npm.cmd + shell`)。
56
- - **跳过条件**:设 `BEACON_MCP_NO_UPDATE=1`、或已设 `BEACON_SOURCE` / `BEACON_REPO`(离线 / 本地仓库用户)时**不联网升级**,避免对本地仓库用户添乱。
57
- - **并发保护**:原子目录锁 + 残留锁 10 分钟过期自愈(踩过死锁坑——残留锁会让之后所有启动永久跳过自更新)。
58
- - **测试**:`test_update.js` 单元测试 23/23 通过,并以 fake-npm 拦截验证安装命令形态正确(`npm.cmd i -g beacon-mfg-mcp@1.4.2`)。
59
- - **前向生效说明**:自更新是「向前生效」的——已装的 ≤1.4.1 旧版代码里没有 `selfupdate.js`,需**一次性手动** `npm i -g beacon-mfg-mcp@latest` 进入自动升级基线;之后永久自动。`npx beacon-mfg-mcp` 用户天然永远最新。
60
-
61
- ## 本次更新(v1.4.1,已发布)
62
- - **直连优先 + 死代理容错**:修复「失效代理导致检索归零」——默认源不可达时直连兜底镜像,且报错信息直指真因(是代理挂了而非数据问题),`npm i -g` 装一次即享受(无需重启客户端)。
63
-
64
- ## 本次更新(v1.4.0,已发布)
65
- - **标准分帧适配层 `mcp_adapter.py`**:补齐「严格分帧」客户端接入路径,与「换行 stdio」「Streamable HTTP」三条传输链路统一。
66
- - **协议回归测试 `test_protocol.py`**:一条命令覆盖三条链路(握手 + 6 工具齐全 + 三城市真实检索 `via_index`),发版前必跑。
67
-
68
- ## 本次更新(v1.3.3,已发布)
69
- - **本地检索免提交、免重启即时可见**:这是 v1.3.1「worktree 兜底」的收尾。v1.3.1 只让**单文件读**走了工作树,
70
- 但关键词/城市检索的**召回**走的是**批量读** `_read_many_text()`——它在 git 模式下恒走 `git archive HEAD`
71
- (已提交快照),于是**改完数据、重建索引后,关键词检索仍读旧索引、必须 commit 才可见**。
72
- 本次把批量读也改为「**工作树优先 → `git archive HEAD` 兜底 → HTTP**」。
73
- - **进程内 + 磁盘缓存按文件新鲜度失效**:新增 `_wt_mtime` / `_cache_stale`,各 loader
74
- (manifest / 别名 / 国标名表 / cap 索引 / city / 索引桶 / fp 分片 / 能力词)改为
75
- **按工作树文件 mtime 判新**——派生层一重建,MCP 立刻重读,**无需重启进程**;
76
- 磁盘索引缓存(`idx-*`)加 **mtime 印记**(`repr` 精确往返),同秒重写也能识别。
77
- - **可选 TTL**:`BEACON_CACHE_TTL`(秒,默认 `0`=关闭)可让进程内缓存周期性刷新;
78
- 非工作树模式(`BEACON_WORKTREE=0`)保持旧的「提交后 / 重启后生效」行为不变。
79
- - 已用**真实注入实验**验证:单进程、不 commit、只 sleep,`data/gb` 新记录经本地重建后
80
- 关键词检索由 `0` 命中变 `1` 命中。
81
-
82
- ## 本次更新(v1.3.2,已发布)
83
- - **npm 启动器锁定 UTF-8**:`bin/beacon-mfg-mcp.js` 拉起 python 时注入 `PYTHONUTF8=1` / `PYTHONIOENCODING=utf-8`,
84
- 修复中文 Windows 上 python 按 GBK 写 stdout、被客户端按 UTF-8 解码导致的工具描述/结果乱码。
85
- - **HTTP 兜底镜像**:默认源 `beacon-mfg.pages.dev` 不可达时,自动回退到 GitHub 镜像
86
- `cdn.jsdelivr.net/gh/eiry16/beacon-mfg@main` 与 `raw.githubusercontent.com/eiry16/beacon-mfg/main`
87
- (与 Android App 同策略),保证「免 clone 检索」在单一 CDN 失效时仍可工作;可用 `BEACON_MIRRORS` 追加。
88
- - **serverInfo 版本对齐**:服务端自报版本改为读 `package.json`,不再硬编码,消除与 npm 包版本漂移。
89
-
90
- ## 本次更新(v1.3.1,已发布)
91
- - **npm 包自带 rfq-kernel**:`prepack` 会把 `skills/rfq-kernel` 打进包内,因此 `npm i -g beacon-mfg-mcp`
92
- 安装后 6 个 tool 全部可用(早于此版本的 npm 包不含该桥接,3 个寻源 tool 会降级)。
93
- GitHub Release tarball 同步包含 `rfq-kernel/`。
94
- - **闭合检索缺口**:本地 git 模式默认 `BEACON_WORKTREE=1`,优先读工作树文件(含未提交/刚修改的数据),
95
- 仅在文件缺失或单对象 JSON 解析失败(半成品)时退回 `git show HEAD`,再否则走 HTTP。
96
- 设 `BEACON_WORKTREE=0` 可恢复「只读已提交快照」的严格行为。
97
-
98
- ## 安装(三选一)
99
-
100
- ### 1. 从 GitHub Release 下载(推荐,零依赖)
101
- 下载本 Release 的 `beacon-mfg-mcp-mcp-v1.5.0.tar.gz`,解压后:
102
- ```jsonc
103
- {
104
- "mcpServers": {
105
- "beacon-mfg": {
106
- "command": "python",
107
- "args": ["/解压目录/server.py"],
108
- "env": { "BEACON_REPO": "/你的/beacon-mfg仓库路径" } // 可选:离线 + 隐私安全
109
- }
110
- }
111
- }
112
- ```
113
-
114
- ### 2. npm(需先 `npm login`,仓库已配 `NPM_TOKEN` 后自动发布)
115
- ```bash
116
- npm install -g beacon-mfg-mcp
117
- # 或一次性运行:
118
- npx beacon-mfg-mcp
119
- ```
120
- 装好后客户端配置:
121
- ```jsonc
122
- {
123
- "mcpServers": {
124
- "beacon-mfg": { "command": "beacon-mfg-mcp", "args": [], "env": { "PYTHONUTF8": "1", "PYTHONIOENCODING": "utf-8" } }
125
- }
126
- }
127
- ```
128
-
129
- ### 3. 从源码(git clone)
130
- ```bash
131
- git clone https://github.com/eiry16/beacon-mfg.git
132
- # 客户端 command 指向 beacon-mfg/mcp/server.py
133
- ```
134
-
135
- ## 环境变量
136
- - `BEACON_REPO`:本地 git 仓库路径;设了就用 `git show HEAD:` + 工作树 读(推荐:离线 + 掩码态隐私安全)。
137
- - `BEACON_SOURCE`:HTTP 基址,默认 `https://beacon-mfg.pages.dev`(可改自定义域名)。
138
- - `BEACON_WORKTREE`:本地模式是否优先读工作树(默认 `1`;设 `0` 恢复「只读已提交快照」)。
139
- - `BEACON_MIRRORS`:HTTP 模式追加的兜底镜像基址(逗号分隔);默认源不可达时除内置的 jsDelivr/raw 外,可在此追加自有镜像。
140
- - `HTTPS_PROXY` / `HTTP_PROXY`:python 子进程的代理;在中国大陆等直连 GitHub 困难的网络,设 `HTTPS_PROXY=http://127.0.0.1:7890` 可让镜像链路走代理。
141
-
142
- ## 许可
143
- MIT
1
+ # Beacon-MFG 只读 MCP 服务 · v1.5.1
2
+
3
+ 让任意支持 MCP 的主流 agent(Claude Desktop / Cline / Continue / WorkBuddy 等)能够
4
+ **检索与调用**已发布到 Cloudflare Pages(或 GitHub)的灯塔工厂供应商数据,
5
+ **无需 clone 整个仓库、无需任何密钥**。
6
+
7
+ ## 设计边界
8
+ MCP 只做**只读检索**。后端数据采集、英文翻译、库维护等流水线**不进 MCP、不暴露、不持密钥**,
9
+ 也不会落在任何写路径上。对 Android App 与 cron/GUI 流水线**零影响**(详见 `mcp/README.md`)。
10
+
11
+ ## 六个只读 tool
12
+ | tool | 用途 | 关键参数 |
13
+ |------|------|----------|
14
+ | `search_vendors` | 按 关键词 / 城市 / 国标码 检索,返回精简档案 | `query` `city` `gb` `limit` `offset` |
15
+ | `get_vendor` | 按 id(+国标码)取完整中文档案 | `id`(必填) `gb`(可选) |
16
+ | `get_capability_card` | 按 id 取能力卡(工艺/设备/产能/认证) | `id`(必填) |
17
+ | `start_sourcing` | 【客户 agent 自动触发】识别找厂/代工/采购意图 → 品类识别→宽召回→澄清,返回 `session_id` | `demand_text`(必填) `audience_id` |
18
+ | `answer_sourcing` | 续接澄清轮次:写回客户答案,返回下一轮澄清或初选列表 | `session_id`(必填) `answers` |
19
+ | `refine_sourcing` | 推荐轮次交互:`details`/`more`/`best` | `session_id`(必填) `action` `value` |
20
+
21
+ 后三个构成「采购寻源」多轮会话链路 `start_sourcing → answer_sourcing → refine_sourcing`,
22
+ 依赖仓库平级的 `skills/rfq-kernel` 桥接模块。
23
+
24
+ ## 本次更新(v1.5.1)
25
+ **修「刚导入的企业在 MCP 上查不到」——idmap 新号守卫。**
26
+
27
+ v1.5.0 的 idmap 有个致命假设:片存在但片里没这条 id ⇒ 判「不存在」(这样才能省掉
28
+ 18.4 MB 的 name-index 兜底)。但**抓取流水线与政府信源导入每天都在发新号**,
29
+ 而 idmap 只在 manifest 步重算、只在 pages 步上云 —— 于是「刚导入、还没发布」的新 id
30
+ 天然不在已发布快照里,会被这条判定**静默误杀**(政府名录一次能进上千家,症状是查不到、不报错)。
31
+
32
+ - `idmap/meta.json` 与 `manifest.metadata.idmap` 新增 **`max_id`**(已发布的最大 id 数字)。
33
+ 客户端据此区分:`id <= max_id` 且片里没有 ⇒ 真不存在(照样省掉兜底);
34
+ `id > max_id` ⇒ 尚未发布的新号,老老实实走兜底。**正确性优先于那点延迟。**
35
+ - 两个守卫的**顺序不能反**:`max_id` 比 `buckets` 精确(后者只到千位)。
36
+ 实测踩过:buckets=183 / max_id=182302 时,id=0187302 的 bucket=187 已越界,
37
+ 但它只是「比最大号大 5000」的新号 —— 先走 buckets 守卫就被误杀了。
38
+ - 生成器侧加了**条数对账**(`n_rec + other != len(rows)` 直接抛错)——
39
+ 少一条就是一个 id 永远查不到,这种丢失是静默的,必须在生成时拦住。
40
+ - 顺带加了 idmap 残留片清理(dedup 真删实体 id 时,旧的高位片会被 manifest 哈希并上传,
41
+ 白占流量与仓库体积)。
42
+
43
+ ## 本次更新(v1.5.0,已发布)
44
+ **`get_vendor` 从 4.5 分钟降到 6 秒(45×)。** 起因是外部实测反馈「HTTP 模式比本地 git 模式慢约 100 倍,
45
+ 按 id 取一家企业要 270 秒」。定位结论:慢不在计算,而在**为了找一个 id 而下载整张 18.4 MB 的
46
+ `name-index.jsonl`**——id 只是其中一行。
47
+
48
+ - **idmap 定址分片**:新增 `skills/registry/index/idmap/`,`id → 国标码` 按 id 千位切片(183 片 × 1000 id,
49
+ 命中那片约 20 KB)。片名由 id 直接算出(`CN-MFG-0093680` → `93680 // 1000` → `093.jsonl`),
50
+ **不需要目录表、不需要额外请求**。
51
+ - **零 404 的开关设计**:idmap 的元信息放在 `manifest.metadata.idmap` 里——清单本来就要拉,所以是零额外请求。
52
+ 清单里**没有**这个块 = 该快照尚未发布 idmap → 整体走老路径。这样「MCP 先升级、数据后发布」的窗口期
53
+ 不会变成满屏 404(实测过:一次 404 的冷启动兜底要 44 秒)。
54
+ - **按内容哈希缓存分片**:清单里每片都登记了内容 sha1,用它当缓存键——内容不变则**完全不走网络**,
55
+ 取到后顺手校验,不符就不写缓存。
56
+ - **zh 详情分片改并发取**;**HTTP 超时 15→30 s**;**显式声明 gzip 并手动解压**
57
+ (urllib 不会自动解压,JSON 压缩 6~20×,此前一直是裸传)。
58
+ - **实测**(`scripts/bench_get_vendor.py`,缓存目录强制隔离):
59
+
60
+ | 场景 | 冷启动 | 复用缓存 |
61
+ |------|--------|----------|
62
+ | 线上 CDN(本次前) | 270.6 s | — |
63
+ | 线上 CDN(本次后) | **5.95 s** | **1.22 s** |
64
+ | 本地快照 | 1.77 s | 0.80 s |
65
+
66
+ - **恢复 `mcp/test_protocol.py`**:上一个提交误删了发布前必跑的协议回归测试,本次还原(313 行)。
67
+ 发布前实测三条链路 **16/16 通过**(HTTP / stdio / 标准分帧适配层 + 死代理容错)。
68
+ - 数据侧(`skills/registry/index/idmap/**` 与含 `metadata.idmap` 的 `data/manifest.json`)已同步发布到 Pages,
69
+ 旧版 MCP 不受影响(读不到 idmap 块就走老路径)。
70
+
71
+ ## 本次更新(v1.4.2,已发布)
72
+ - **自动升级(自更新)**:新增 `bin/selfupdate.js`,MCP 启动时以**独立 detached 子进程**拉起(绝不阻塞 MCP 启动),
73
+ 节流查 npm registry `latest`(默认 24h 一次,可用 `BEACON_MCP_UPDATE_INTERVAL_H` 调),发现新版本即执行
74
+ `npm i -g beacon-mfg-mcp@<新版本>`(Windows 上正确走 `npm.cmd + shell`)。
75
+ - **跳过条件**:设 `BEACON_MCP_NO_UPDATE=1`、或已设 `BEACON_SOURCE` / `BEACON_REPO`(离线 / 本地仓库用户)时**不联网升级**,避免对本地仓库用户添乱。
76
+ - **并发保护**:原子目录锁 + 残留锁 10 分钟过期自愈(踩过死锁坑——残留锁会让之后所有启动永久跳过自更新)。
77
+ - **测试**:`test_update.js` 单元测试 23/23 通过,并以 fake-npm 拦截验证安装命令形态正确(`npm.cmd i -g beacon-mfg-mcp@1.4.2`)。
78
+ - **前向生效说明**:自更新是「向前生效」的——已装的 ≤1.4.1 旧版代码里没有 `selfupdate.js`,需**一次性手动** `npm i -g beacon-mfg-mcp@latest` 进入自动升级基线;之后永久自动。`npx beacon-mfg-mcp` 用户天然永远最新。
79
+
80
+ ## 本次更新(v1.4.1,已发布)
81
+ - **直连优先 + 死代理容错**:修复「失效代理导致检索归零」——默认源不可达时直连兜底镜像,且报错信息直指真因(是代理挂了而非数据问题),`npm i -g` 装一次即享受(无需重启客户端)。
82
+
83
+ ## 本次更新(v1.4.0,已发布)
84
+ - **标准分帧适配层 `mcp_adapter.py`**:补齐「严格分帧」客户端接入路径,与「换行 stdio」「Streamable HTTP」三条传输链路统一。
85
+ - **协议回归测试 `test_protocol.py`**:一条命令覆盖三条链路(握手 + 6 工具齐全 + 三城市真实检索 `via_index`),发版前必跑。
86
+
87
+ ## 本次更新(v1.3.3,已发布)
88
+ - **本地检索免提交、免重启即时可见**:这是 v1.3.1「worktree 兜底」的收尾。v1.3.1 只让**单文件读**走了工作树,
89
+ 但关键词/城市检索的**召回**走的是**批量读** `_read_many_text()`——它在 git 模式下恒走 `git archive HEAD`
90
+ (已提交快照),于是**改完数据、重建索引后,关键词检索仍读旧索引、必须 commit 才可见**。
91
+ 本次把批量读也改为「**工作树优先 → `git archive HEAD` 兜底 → HTTP**」。
92
+ - **进程内 + 磁盘缓存按文件新鲜度失效**:新增 `_wt_mtime` / `_cache_stale`,各 loader
93
+ (manifest / 别名 / 国标名表 / cap 索引 / city / 索引桶 / fp 分片 / 能力词)改为
94
+ **按工作树文件 mtime 判新**——派生层一重建,MCP 立刻重读,**无需重启进程**;
95
+ 磁盘索引缓存(`idx-*`)加 **mtime 印记**(`repr` 精确往返),同秒重写也能识别。
96
+ - **可选 TTL**:`BEACON_CACHE_TTL`(秒,默认 `0`=关闭)可让进程内缓存周期性刷新;
97
+ 非工作树模式(`BEACON_WORKTREE=0`)保持旧的「提交后 / 重启后生效」行为不变。
98
+ - 已用**真实注入实验**验证:单进程、不 commit、只 sleep,`data/gb` 新记录经本地重建后
99
+ 关键词检索由 `0` 命中变 `1` 命中。
100
+
101
+ ## 本次更新(v1.3.2,已发布)
102
+ - **npm 启动器锁定 UTF-8**:`bin/beacon-mfg-mcp.js` 拉起 python 时注入 `PYTHONUTF8=1` / `PYTHONIOENCODING=utf-8`,
103
+ 修复中文 Windows 上 python 按 GBK 写 stdout、被客户端按 UTF-8 解码导致的工具描述/结果乱码。
104
+ - **HTTP 兜底镜像**:默认源 `beacon-mfg.pages.dev` 不可达时,自动回退到 GitHub 镜像
105
+ `cdn.jsdelivr.net/gh/eiry16/beacon-mfg@main` 与 `raw.githubusercontent.com/eiry16/beacon-mfg/main`
106
+ (与 Android App 同策略),保证「免 clone 检索」在单一 CDN 失效时仍可工作;可用 `BEACON_MIRRORS` 追加。
107
+ - **serverInfo 版本对齐**:服务端自报版本改为读 `package.json`,不再硬编码,消除与 npm 包版本漂移。
108
+
109
+ ## 本次更新(v1.3.1,已发布)
110
+ - **npm 包自带 rfq-kernel**:`prepack` 会把 `skills/rfq-kernel` 打进包内,因此 `npm i -g beacon-mfg-mcp`
111
+ 安装后 6 个 tool 全部可用(早于此版本的 npm 包不含该桥接,3 个寻源 tool 会降级)。
112
+ GitHub Release tarball 同步包含 `rfq-kernel/`。
113
+ - **闭合检索缺口**:本地 git 模式默认 `BEACON_WORKTREE=1`,优先读工作树文件(含未提交/刚修改的数据),
114
+ 仅在文件缺失或单对象 JSON 解析失败(半成品)时退回 `git show HEAD`,再否则走 HTTP。
115
+ 设 `BEACON_WORKTREE=0` 可恢复「只读已提交快照」的严格行为。
116
+
117
+ ## 安装(三选一)
118
+
119
+ ### 1. 从 GitHub Release 下载(推荐,零依赖)
120
+ 下载本 Release 的 `beacon-mfg-mcp-mcp-v1.5.1.tar.gz`,解压后:
121
+ ```jsonc
122
+ {
123
+ "mcpServers": {
124
+ "beacon-mfg": {
125
+ "command": "python",
126
+ "args": ["/解压目录/server.py"],
127
+ "env": { "BEACON_REPO": "/你的/beacon-mfg仓库路径" } // 可选:离线 + 隐私安全
128
+ }
129
+ }
130
+ }
131
+ ```
132
+
133
+ ### 2. npm(需先 `npm login`,仓库已配 `NPM_TOKEN` 后自动发布)
134
+ ```bash
135
+ npm install -g beacon-mfg-mcp
136
+ # 或一次性运行:
137
+ npx beacon-mfg-mcp
138
+ ```
139
+ 装好后客户端配置:
140
+ ```jsonc
141
+ {
142
+ "mcpServers": {
143
+ "beacon-mfg": { "command": "beacon-mfg-mcp", "args": [], "env": { "PYTHONUTF8": "1", "PYTHONIOENCODING": "utf-8" } }
144
+ }
145
+ }
146
+ ```
147
+
148
+ ### 3. 从源码(git clone)
149
+ ```bash
150
+ git clone https://github.com/eiry16/beacon-mfg.git
151
+ # 客户端 command 指向 beacon-mfg/mcp/server.py
152
+ ```
153
+
154
+ ## 环境变量
155
+ - `BEACON_REPO`:本地 git 仓库路径;设了就用 `git show HEAD:` + 工作树 读(推荐:离线 + 掩码态隐私安全)。
156
+ - `BEACON_SOURCE`:HTTP 基址,默认 `https://beacon-mfg.pages.dev`(可改自定义域名)。
157
+ - `BEACON_WORKTREE`:本地模式是否优先读工作树(默认 `1`;设 `0` 恢复「只读已提交快照」)。
158
+ - `BEACON_MIRRORS`:HTTP 模式追加的兜底镜像基址(逗号分隔);默认源不可达时除内置的 jsDelivr/raw 外,可在此追加自有镜像。
159
+ - `HTTPS_PROXY` / `HTTP_PROXY`:python 子进程的代理;在中国大陆等直连 GitHub 困难的网络,设 `HTTPS_PROXY=http://127.0.0.1:7890` 可让镜像链路走代理。
160
+
161
+ ## 许可
162
+ MIT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "beacon-mfg-mcp",
3
- "version": "1.5.0",
3
+ "version": "1.5.1",
4
4
  "description": "Read-only MCP server exposing the BeaconMFG灯塔工厂 supplier directory (search vendors, get vendor detail, get capability card, multi-turn sourcing) to any MCP-compatible agent. No API key required.",
5
5
  "keywords": [
6
6
  "mcp",
package/server.py CHANGED
@@ -271,9 +271,9 @@ def _pkg_version() -> str:
271
271
  try:
272
272
  p = os.path.join(os.path.dirname(os.path.abspath(__file__)), "package.json")
273
273
  with open(p, "r", encoding="utf-8") as f:
274
- return json.load(f).get("version", "1.5.0")
274
+ return json.load(f).get("version", "1.5.1")
275
275
  except Exception:
276
- return "1.5.0"
276
+ return "1.5.1"
277
277
 
278
278
 
279
279
  # HTTP 基址列表(含兜底镜像)。默认部署 Cloudflare Pages 不可达时,自动回退到
@@ -1137,13 +1137,35 @@ def _idmap_lookup(vid: str) -> Tuple[Optional[str], bool]:
1137
1137
  客户端必须照样按空串走 _unclassified 那条路,而不是当成「没找到」)。
1138
1138
  shard_ok = 该片的**范围已被覆盖** → 此时 id 缺席可判定为「不存在」,
1139
1139
  调用方不必再去付 18.4 MB / 320 个分片的兜底代价。
1140
+
1141
+ ⚠ 「片里没有」要**先过 max_id 这道闸**才能判不存在。抓取流水线与政府信源
1142
+ 导入每天都在发新号,而 idmap 只在 manifest 步重算、只在 pages 步上云 ——
1143
+ 于是「刚导入、还没发布」的新 id 天然不在已发布的 idmap 里。
1144
+ 若只看「片存在但片里没这条」就判不存在,等于**把新导入的企业全部误杀**
1145
+ (政府名录一次能进上千家,症状还是静默的:查不到,不报错)。
1146
+ 判据:id 数字 <= meta.max_id 才敢判「真不存在」;超过就退回慢路径兜底。
1140
1147
  """
1141
1148
  meta = _idmap_meta()
1142
1149
  nb = meta.get("buckets")
1143
1150
  if not isinstance(nb, int) or nb <= 0:
1144
1151
  return None, False # 快照里没有 idmap(尚未发布)→ 调用方按老路径走
1145
1152
 
1146
- # 范围守卫:超出范围 = 这条 id 不在已发布快照里,直接判定,
1153
+ # 已发布的最大 id 数字。老版本快照没有这个字段 → 退化成「只能靠 buckets 守卫」,
1154
+ # 此时新 id 会被误判,所以**取不到就整体不走 idmap**(宁可慢,不可错)。
1155
+ mx = meta.get("max_id")
1156
+ if not isinstance(mx, int) or mx < 0:
1157
+ return None, False
1158
+
1159
+ # ⚠ 两个守卫的**顺序不能反**。
1160
+ # max_id 是比 buckets 更精确的上界(buckets 只精确到千位):
1161
+ # 例如 buckets=183 / max_id=182302 时,id=0187302 的 bucket=187 已越界,
1162
+ # 但它其实只是「比已发布最大号大 5000」的新号 —— 若先走 buckets 守卫就会
1163
+ # 被判成不存在(误杀)。所以先用 max_id 收口,再谈 buckets。
1164
+ m_vid = _VENDOR_ID_RE.match(vid or "")
1165
+ if m_vid is not None and int(m_vid.group(1)) > mx:
1166
+ return None, False # 尚未发布的新号 → 交回调用方走兜底
1167
+
1168
+ # 范围守卫:连千位片都还没生成 = 远在未来的号,直接判定,
1147
1169
  # 不去请求那个必定 404 的分片。
1148
1170
  b = _idmap_bucket(vid)
1149
1171
  if b is not None and b >= nb: