beacon-mfg-mcp 1.12.7 → 1.12.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/MCP_HTTP.md CHANGED
@@ -91,7 +91,13 @@ Cloudflare 直接拒(403 / error code 1000),所以这条闸没有「客户
91
91
  | `start_sourcing` | `handleSearch` + D1 会话 | 含糊需求 → 宽召回 + 1~2 个澄清问题,返回 `session_id` |
92
92
  | `answer_sourcing` | 会话续接 + 重检 | 把澄清答案写回,**重新检索**(不是在旧结果里二次过滤) |
93
93
  | `refine_sourcing` | 会话快照 | `best` / `more` / `filter` / `details` |
94
- | `vendor_onboarding` | 纯静态文案 | 入驻/认领指路(控制台深链 + Agent HTTP 契约) |
94
+ | `get_onboarding_guide` | 纯静态文案 | 入驻/认领指路(控制台深链 + Agent HTTP 契约) |
95
+
96
+ > **命名一致性(1.12.8)**:7 个工具前 6 个都是 `verb_noun`(search_/get_/start_/answer_/refine_),
97
+ > 第 7 个原名 `vendor_onboarding` 是名词短语 —— Glama 评审把这算作一致性扣分项。
98
+ > 改成 `get_onboarding_guide` 后与 `get_vendor` / `get_capability_card` 同构:都是「取一份已有的东西」,
99
+ > 而它确实是纯静态文案、不发写请求。**旧名留作隐藏别名**(`tools/call` 能命中、`tools/list` 不出现),
100
+ > 已按旧名配好白名单的客户端不会突然拿到 `unknown tool`;等审计里旧名归零再删。
95
101
 
96
102
  **复用而不是重写**:检索打分、脱敏、逐条计量都在原 handler 里。在这里重写一份必然与 stdio 版分叉,
97
103
  而分叉的检索结果比慢一点糟得多。实现方式见 `pages/_worker.js` 的 `mcpInnerRequest()`。
@@ -209,7 +215,46 @@ npx @modelcontextprotocol/inspector
209
215
  # Transport: Streamable HTTP URL: https://beacon-mfg.pages.dev/mcp
210
216
  ```
211
217
 
212
- ## 6. 已知边界
218
+ ## 6. 被发现:服务卡(SEP-2127)
219
+
220
+ 端点存在,不等于 agent 知道它存在。**MCP 没有服务搜索引擎**:客户端启动时读的是本地
221
+ 配置里已经写好的连接列表,不会联网去找有什么服务。注册到 Registry 的作用是让**人**在
222
+ 目录站/客户端面板里看到条目,再点一下写进配置 —— 链条上永远有一个人。
223
+
224
+ 唯一不靠人转述的机制是服务卡:
225
+
226
+ ```bash
227
+ curl -s https://beacon-mfg.pages.dev/.well-known/mcp.json | jq '{name, version, remotes}'
228
+ ```
229
+
230
+ ```json
231
+ {
232
+ "name": "io.github.eiry16/beacon-mfg-mcp",
233
+ "version": "1.12.7",
234
+ "remotes": [{ "type": "streamable-http", "url": "https://beacon-mfg.pages.dev/mcp" }]
235
+ }
236
+ ```
237
+
238
+ | 项 | 值 |
239
+ |---|---|
240
+ | 路径 | `/.well-known/mcp.json`;别名 `/.well-known/mcp/server-card.json`(同一份 body) |
241
+ | 生成方式 | **由 `_worker.js` 生成**,不是静态文件;`version` / `protocolVersion` 直接引用端点常量 |
242
+ | 字段集 | SEP-2127 收敛后的范围:身份 + 远端端点。**不列工具、不声明 auth**(工具是运行时 `server/discover` 拿的) |
243
+ | 配额 | 不消耗。路由在门禁**之前** —— 发现阶段被自己的闸拦一次,等于把这条路堵死 |
244
+
245
+ **为什么两个路径都发**:草案期从 `/.well-known/mcp.json` 换到
246
+ `/.well-known/mcp/server-card.json`,目前仍在 Extensions Track 里演进。只发一个等于
247
+ 赌客户端读哪个,赌错的症状是「什么都对,就是没人连」—— 没有任何报错。
248
+
249
+ **为什么不用静态文件**:① 点开头的目录在 Pages 上行为不保证(Workers Sites 明确忽略
250
+ hidden files);② 静态文件的 version 迟早与端点漂移,而这张卡正是给「不会来问的人」看的,
251
+ 编错了也没人报错。`scripts/deploy_pages.py --verify` 会把卡片版本与 `initialize` 自报
252
+ 版本对比,不一致即红。
253
+
254
+ `llms.txt` 里同时给出了端点 URL 与卡片地址 —— 那是「会读本站的 agent」唯一会看的一份说明。
255
+ 在补之前它只写了 `npx` 安装,于是「不想装东西」的 agent 读完也不知道该怎么连。
256
+
257
+ ## 7. 已知边界
213
258
 
214
259
  1. **无状态 = 无推送**。需要 sampling / elicitation / 服务端通知的客户端功能用不了。
215
260
  2. **一次性工具调用没做去重**。客户端重试 = 重复计量(与 `/v1` 同口径,不为重试开豁免)。
package/README.md CHANGED
@@ -13,13 +13,16 @@
13
13
  > **两种接入形态,工具数不同**:
14
14
  > - **远程端点**(`https://beacon-mfg.pages.dev/mcp`,Streamable HTTP,无需安装)——
15
15
  > 提供 7 个工具:`search_vendors` / `get_vendor` / `get_capability_card`,
16
- > 多轮寻源 `start_sourcing` / `answer_sourcing` / `refine_sourcing`,以及 `vendor_onboarding`。
16
+ > 多轮寻源 `start_sourcing` / `answer_sourcing` / `refine_sourcing`,以及 `get_onboarding_guide`。
17
17
  > 额度按**出口 IP** 计(1,000 条记录/24h),不要注册、不要 API Key;寻源会话 2 小时过期,
18
18
  > 且只能在**同一个出口 IP** 下续接。
19
19
  > - **本地 stdio**(`npx -y beacon-mfg-mcp`)—— 下表全部 12 个,多轮寻源的澄清问题由行业 pack 驱动
20
20
  > (远程版只问「答了能过滤」的城市/工艺/认证,选项取自候选集本身),另有踩坑留言区。
21
21
  >
22
22
  > 远程端点没上的工具**不会出现在 `tools/list` 里**(让 agent 看不到,比让它调了才报错好)。
23
+ >
24
+ > 服务卡(机器可读发现,SEP-2127):`https://beacon-mfg.pages.dev/.well-known/mcp.json`
25
+ > —— **知道域名就能拿到端点、协议版本与文档地址**,不必先读这份 README。
23
26
  > 契约与验收清单见 https://github.com/eiry16/beacon-mfg/blob/main/mcp/MCP_HTTP.md。
24
27
 
25
28
  ## 提供的 tool(共 12 个:8 个只读检索 + 1 个身份自助 + 1 个入驻入口 + 2 个留言区读写)
@@ -35,7 +38,7 @@
35
38
  | `answer_sourcing` | 续接澄清轮次:写回客户答案,返回下一轮澄清问题或初选供应商列表 | `session_id`(必填) `answers` |
36
39
  | `refine_sourcing` | 推荐轮次交互:`details`(看详情与 RFQ 入口) / `more`(看更多) / `best`(看最匹配一家) | `session_id`(必填) `action` `value` |
37
40
  | `account` | 查看档位/剩余额度;`request`+`confirm` 绑手机号升 `verified`;`logout` 回匿名 | `action` `phone` `code` |
38
- | `vendor_onboarding` | 给供应商开通「入驻 / 认领」入口:返回可直接点开的控制台链接与步骤,并附 `agent_channel`(契约 v3.0,非 App 的 HTTP/JSON 自助通道)。**只给入口不代办**:该通道需手机验证码登录,认领前还须通过「登录手机号 = 工商登记法人手机号」一致性核查;验证码由用户本人输入,本工具不发写请求、不持有密钥 | `supplier_id` `company` `intent`(claim/register/status/agent) |
41
+ | `get_onboarding_guide` | 给供应商开通「入驻 / 认领」入口:返回可直接点开的控制台链接与步骤,并附 `agent_channel`(契约 v3.0,非 App 的 HTTP/JSON 自助通道)。**只给入口不代办**:该通道需手机验证码登录,认领前还须通过「登录手机号 = 工商登记法人手机号」一致性核查;验证码由用户本人输入,本工具不发写请求、不持有密钥。旧名 `vendor_onboarding` 保留为隐藏别名(能调、不列) | `supplier_id` `company` `intent`(claim/register/status/agent) |
39
42
  | `read_notes` | 读踩坑留言区:其他 agent 踩过的坑与绕行(429 语义、无区级过滤、批量取数姿势…)。检索前先读一眼省试错成本 | `topic`(默认 mcp) |
40
43
  | `report_note` | 写踩坑留言区:把自己**实测踩到**的坑(现象 + 绕行)回写给后来的 agent。必须真实踩到才写,不当反馈箱/评分区用 | `issue`(必填) `workaround` `agent` `topic` |
41
44
 
@@ -1,58 +1,58 @@
1
1
  #!/usr/bin/env node
2
- 'use strict';
3
- // beacon-mfg-mcp 启动器:本 MCP 服务是纯 Python 标准库实现,这里只负责
4
- // ① 在用户机器上找到 Python 解释器并拉起 server.py(stdio 协议)
5
- // ② 顺手踢一个**独立进程**去做节流的自更新检查
6
- const { spawnSync, spawn } = require('child_process');
7
- const path = require('path');
8
-
9
- const serverPy = path.join(__dirname, '..', 'server.py');
10
- const selfUpdateJs = path.join(__dirname, 'selfupdate.js');
11
-
12
- // 踢起自更新检查:detached + unref,主进程既不等它也不被它拖住。
13
- // 为什么必须是独立进程而不是本进程里的 async 函数:
14
- // 下面 spawnSync 是**同步阻塞**的,会冻结整个事件循环 —— async 的自更新
15
- // 在 server 运行期间推不动,等它能跑时本进程已经 process.exit() 了,
16
- // 更新逻辑永远跑不完。独立进程不受此影响。
17
- // 失败、离线、没权限一律静默:它只影响「下次启动是不是最新版」。
18
- try {
19
- const u = spawn(process.execPath, [selfUpdateJs], {
20
- stdio: 'ignore',
21
- detached: true,
22
- windowsHide: true,
23
- });
24
- u.on('error', () => { /* 没有 node?不可能,自身就是 node 起的 */ });
25
- u.unref();
26
- } catch (_) { /* 自更新是加分项,绝不能影响 MCP 启动 */ }
27
-
28
- // 探测可用的 Python 解释器(优先 python3,兼容 python / py)
29
- const candidates = ['python3', 'python', 'py'];
30
- let chosen = null;
31
- for (const c of candidates) {
32
- const r = spawnSync(c, ['--version'], { stdio: 'ignore' });
33
- if (r.status === 0) {
34
- chosen = c;
35
- break;
36
- }
37
- }
38
- if (!chosen) {
39
- process.stderr.write(
40
- '[beacon-mfg-mcp] 未找到 Python 3。请先安装 Python 3.8+ 并加入 PATH,再重试。\n'
41
- );
42
- process.exit(1);
43
- }
44
-
45
- const child = spawnSync(chosen, [serverPy, ...process.argv.slice(2)], {
46
- stdio: 'inherit',
47
- // 显式锁定 UTF-8:中文 Windows 上 python 默认按 GBK 写 stdout,
48
- // MCP 客户端按 UTF-8 解码会乱码。从启动器层面保证子进程用 UTF-8 输出。
49
- env: Object.assign({}, process.env, {
50
- PYTHONUTF8: '1',
51
- PYTHONIOENCODING: 'utf-8',
52
- // 不写 __pycache__:本服务由 npm 全局安装、跑在任意用户机器上,
53
- // 字节码会落进包目录(或只读盘上 EPERM 报错)。服务是短命进程,
54
- // 字节码缓存无收益,关掉更干净。
55
- PYTHONDONTWRITEBYTECODE: '1',
56
- }),
57
- });
58
- process.exit(child.status === null ? 1 : child.status);
2
+ 'use strict';
3
+ // beacon-mfg-mcp 启动器:本 MCP 服务是纯 Python 标准库实现,这里只负责
4
+ // ① 在用户机器上找到 Python 解释器并拉起 server.py(stdio 协议)
5
+ // ② 顺手踢一个**独立进程**去做节流的自更新检查
6
+ const { spawnSync, spawn } = require('child_process');
7
+ const path = require('path');
8
+
9
+ const serverPy = path.join(__dirname, '..', 'server.py');
10
+ const selfUpdateJs = path.join(__dirname, 'selfupdate.js');
11
+
12
+ // 踢起自更新检查:detached + unref,主进程既不等它也不被它拖住。
13
+ // 为什么必须是独立进程而不是本进程里的 async 函数:
14
+ // 下面 spawnSync 是**同步阻塞**的,会冻结整个事件循环 —— async 的自更新
15
+ // 在 server 运行期间推不动,等它能跑时本进程已经 process.exit() 了,
16
+ // 更新逻辑永远跑不完。独立进程不受此影响。
17
+ // 失败、离线、没权限一律静默:它只影响「下次启动是不是最新版」。
18
+ try {
19
+ const u = spawn(process.execPath, [selfUpdateJs], {
20
+ stdio: 'ignore',
21
+ detached: true,
22
+ windowsHide: true,
23
+ });
24
+ u.on('error', () => { /* 没有 node?不可能,自身就是 node 起的 */ });
25
+ u.unref();
26
+ } catch (_) { /* 自更新是加分项,绝不能影响 MCP 启动 */ }
27
+
28
+ // 探测可用的 Python 解释器(优先 python3,兼容 python / py)
29
+ const candidates = ['python3', 'python', 'py'];
30
+ let chosen = null;
31
+ for (const c of candidates) {
32
+ const r = spawnSync(c, ['--version'], { stdio: 'ignore' });
33
+ if (r.status === 0) {
34
+ chosen = c;
35
+ break;
36
+ }
37
+ }
38
+ if (!chosen) {
39
+ process.stderr.write(
40
+ '[beacon-mfg-mcp] 未找到 Python 3。请先安装 Python 3.8+ 并加入 PATH,再重试。\n'
41
+ );
42
+ process.exit(1);
43
+ }
44
+
45
+ const child = spawnSync(chosen, [serverPy, ...process.argv.slice(2)], {
46
+ stdio: 'inherit',
47
+ // 显式锁定 UTF-8:中文 Windows 上 python 默认按 GBK 写 stdout,
48
+ // MCP 客户端按 UTF-8 解码会乱码。从启动器层面保证子进程用 UTF-8 输出。
49
+ env: Object.assign({}, process.env, {
50
+ PYTHONUTF8: '1',
51
+ PYTHONIOENCODING: 'utf-8',
52
+ // 不写 __pycache__:本服务由 npm 全局安装、跑在任意用户机器上,
53
+ // 字节码会落进包目录(或只读盘上 EPERM 报错)。服务是短命进程,
54
+ // 字节码缓存无收益,关掉更干净。
55
+ PYTHONDONTWRITEBYTECODE: '1',
56
+ }),
57
+ });
58
+ process.exit(child.status === null ? 1 : child.status);