beacon-mfg-mcp 1.12.1 → 1.12.3
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 +15 -1
- package/package.json +3 -2
- package/server.py +176 -44
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
> 只记「怎么绕开」,不评数据对错;repo 模式存 `<repo>/mcp/notes/` 由操作员托管,
|
|
11
11
|
> 联网模式存本机 `~/.beacon-mfg/notes/` 不上传云端)。
|
|
12
12
|
|
|
13
|
-
## 提供的 tool
|
|
13
|
+
## 提供的 tool(共 12 个:8 个只读检索 + 1 个身份自助 + 1 个入驻入口 + 2 个留言区读写)
|
|
14
14
|
|
|
15
15
|
| tool | 用途 | 关键参数 |
|
|
16
16
|
|------|------|----------|
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
| `answer_sourcing` | 续接澄清轮次:写回客户答案,返回下一轮澄清问题或初选供应商列表 | `session_id`(必填) `answers` |
|
|
24
24
|
| `refine_sourcing` | 推荐轮次交互:`details`(看详情与 RFQ 入口) / `more`(看更多) / `best`(看最匹配一家) | `session_id`(必填) `action` `value` |
|
|
25
25
|
| `account` | 查看档位/剩余额度;`request`+`confirm` 绑手机号升 `verified`;`logout` 回匿名 | `action` `phone` `code` |
|
|
26
|
+
| `vendor_onboarding` | 给供应商开通「入驻 / 认领」入口:返回可直接点开的控制台链接与步骤,并附 `agent_channel`(契约 v3.0,非 App 的 HTTP/JSON 自助通道)。**只给入口不代办**:该通道需手机验证码登录,认领前还须通过「登录手机号 = 工商登记法人手机号」一致性核查;验证码由用户本人输入,本工具不发写请求、不持有密钥 | `supplier_id` `company` `intent`(claim/register/status/agent) |
|
|
26
27
|
| `read_notes` | 读踩坑留言区:其他 agent 踩过的坑与绕行(429 语义、无区级过滤、批量取数姿势…)。检索前先读一眼省试错成本 | `topic`(默认 mcp) |
|
|
27
28
|
| `report_note` | 写踩坑留言区:把自己**实测踩到**的坑(现象 + 绕行)回写给后来的 agent。必须真实踩到才写,不当反馈箱/评分区用 | `issue`(必填) `workaround` `agent` `topic` |
|
|
28
29
|
|
|
@@ -59,6 +60,19 @@ linked_entity 温州市亿鸿装饰工程有限公司 ← 营业执照
|
|
|
59
60
|
登记机关),只有政府公开数据来源的主体才有,且**只读不改**;`linked_entity` 是**场所与主体的
|
|
60
61
|
关联边**,可撤销、可人工修正。
|
|
61
62
|
|
|
63
|
+
## 工艺证据等级(search_vendors 的 `process_evidence`)
|
|
64
|
+
|
|
65
|
+
工艺码有**三种来源**,混为一谈会把「这一类大概都做」当成「这家确实做」:
|
|
66
|
+
|
|
67
|
+
| 值 | 含义 | 该不该当事实 |
|
|
68
|
+
|----|------|--------------|
|
|
69
|
+
| `null` | 能力卡 / 企业自述登记的事实工艺(或类默认但只有 1~3 个码) | 可当事实,仍建议 `get_capability_card` 复核 |
|
|
70
|
+
| `inferred:A1` ~ `inferred:B0` | 零采集推断,字母是证据分档(A1 三路一致 … B0 单路有信号) | 推断不是核实,严苛场景要追问 |
|
|
71
|
+
| `class_default` | 该记录挂了 ≥4 个「国标小类默认工艺码」,是同类企业的众数,**不是这家企业的工艺事实** | ❌ 必须降权,不要据此下单 |
|
|
72
|
+
|
|
73
|
+
`class_default` 覆盖约 1.3 万条。工艺码一个没删(按工艺检索的召回不受影响),
|
|
74
|
+
只是把证据等级如实标出来 —— 让 Agent 少做一轮二次筛选。
|
|
75
|
+
|
|
62
76
|
## 身份与额度(不需要注册)
|
|
63
77
|
|
|
64
78
|
首次运行会在 `~/.beacon-mfg/` 生成一个匿名身份(机器本地 UUID → 单向哈希),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "beacon-mfg-mcp",
|
|
3
|
-
"version": "1.12.
|
|
3
|
+
"version": "1.12.3",
|
|
4
4
|
"mcpName": "io.github.eiry16/beacon-mfg-mcp",
|
|
5
5
|
"description": "Read-only MCP server exposing the BeaconMFG灯塔 directory of business entities across ALL GB/T 4754 industry divisions (manufacturing, services, retail, logistics, catering, IT, and more) to any MCP-compatible agent. No signup and no API key: an anonymous identity is generated on first run, phone binding is optional (only needed for L2 capability cards).",
|
|
6
6
|
"keywords": [
|
|
@@ -43,7 +43,8 @@
|
|
|
43
43
|
"README.md"
|
|
44
44
|
],
|
|
45
45
|
"scripts": {
|
|
46
|
-
"prepack": "node copy-rfk.js"
|
|
46
|
+
"prepack": "node copy-rfk.js",
|
|
47
|
+
"prepublishOnly": "node -e \"const{execSync}=require('child_process');const py=process.platform==='win32'?'python':'python3';execSync(py+' check_release.py',{stdio:'inherit'})\""
|
|
47
48
|
},
|
|
48
49
|
"engines": {
|
|
49
50
|
"node": ">=16"
|
package/server.py
CHANGED
|
@@ -341,7 +341,7 @@ def _recall_for_sourcing(text: str, top_k: int = 200, pack_id: str | None = None
|
|
|
341
341
|
# 都对齐到这个值,`scripts/check_version.py` 在发布前校验它们没有漂移。
|
|
342
342
|
# 读不到 package.json 时的兜底值 —— 改版本时**必须**和 package.json 一起改,
|
|
343
343
|
# 否则 check_version.py 会报错(这就是它的用途)。
|
|
344
|
-
VERSION_FALLBACK = "1.12.
|
|
344
|
+
VERSION_FALLBACK = "1.12.3"
|
|
345
345
|
|
|
346
346
|
|
|
347
347
|
def _pkg_version() -> str:
|
|
@@ -3275,12 +3275,20 @@ def _rec_summary(rec: Dict[str, Any]) -> Dict[str, Any]:
|
|
|
3275
3275
|
"score": rec.get("sc"),
|
|
3276
3276
|
"has_phone": bool(rec.get("tel")),
|
|
3277
3277
|
"process": rec.get("proc", []),
|
|
3278
|
-
# 工艺来源(2026-11-06
|
|
3279
|
-
#
|
|
3280
|
-
#
|
|
3281
|
-
#
|
|
3282
|
-
#
|
|
3283
|
-
|
|
3278
|
+
# 工艺来源(2026-11-06,2026-11-13 补第三档):
|
|
3279
|
+
# None = 能力卡 / 企业自述 / 类默认但工艺码少于 4 个
|
|
3280
|
+
# "inferred:A1" = 零采集推断,字母是分档(A1 三路一致 99.3% / A2 97.4% /
|
|
3281
|
+
# A3 94.3% / B0 单路 96.0%,见 docs/PROCESS_INFERENCE.md)
|
|
3282
|
+
# "class_default" = 该记录挂了 ≥4 个「国标小类默认工艺码」,不是这家企业
|
|
3283
|
+
# 的事实工艺,只是同类众数。全库 12,988 条属此类(其中
|
|
3284
|
+
# 12,970 条 pv=derived)。必须让 Agent 看得见:否则它会把
|
|
3285
|
+
# 「这一类大概都做」当成「这家确实做」,严苛场景直接下单。
|
|
3286
|
+
# 红线:工艺码一个不动(召回不变),只加证据标签 —— 不编造也不减召回。
|
|
3287
|
+
# 12,988 条里只有 838 条有推断候选,其余 12,150 条没有任何强证据可换。
|
|
3288
|
+
"process_evidence": (
|
|
3289
|
+
"inferred:" + rec["pinf"] if rec.get("pinf")
|
|
3290
|
+
else ("class_default" if (rec.get("pv") == "derived"
|
|
3291
|
+
and len(rec.get("proc") or []) >= 4) else None)),
|
|
3284
3292
|
# 业务能力码(2026-11-06):非制造业门类的「能干什么」,如 fmt_bar 酒吧 /
|
|
3285
3293
|
# edu_vocational 职业技能培训 / con_steel 钢结构。此前它只参与匹配不返回,
|
|
3286
3294
|
# 于是「搜酒吧」的结果里看不出哪家真是酒吧。现在一并返回,agent 可据此
|
|
@@ -4486,11 +4494,27 @@ def search_vendors(query: str = "", city: str = "", gb: str = "",
|
|
|
4486
4494
|
# `alias_scanned` 仍按**记录数**计,与改前口径一致。
|
|
4487
4495
|
if _via_server:
|
|
4488
4496
|
def _alias_recs():
|
|
4489
|
-
|
|
4490
|
-
|
|
4491
|
-
|
|
4492
|
-
|
|
4493
|
-
|
|
4497
|
+
codes = list(alias_by_code)[:6]
|
|
4498
|
+
if not codes:
|
|
4499
|
+
return
|
|
4500
|
+
# 2026-11-13 多码列举:一次请求把全部国标码交给 worker。
|
|
4501
|
+
# 旧 worker 不认 gbs:它只按首码 gb 应答、且不回 gbs_supported,
|
|
4502
|
+
# 于是这里退回逐码补发其余码 —— 绝不出现「取首个码漏掉另外两类」。
|
|
4503
|
+
_r = _server_search(q="", city=city, gb=codes, et=et_want,
|
|
4504
|
+
limit=SERVER_SEARCH_WINDOW)
|
|
4505
|
+
done = set()
|
|
4506
|
+
if _r:
|
|
4507
|
+
yield from _r["records"]
|
|
4508
|
+
if _r.get("gbs_supported") and len(codes) > 1:
|
|
4509
|
+
return
|
|
4510
|
+
done.add(codes[0])
|
|
4511
|
+
for _code in codes:
|
|
4512
|
+
if _code in done:
|
|
4513
|
+
continue
|
|
4514
|
+
_r2 = _server_search(q="", city=city, gb=_code, et=et_want,
|
|
4515
|
+
limit=SERVER_SEARCH_WINDOW)
|
|
4516
|
+
if _r2:
|
|
4517
|
+
yield from _r2["records"]
|
|
4494
4518
|
_alias_iter = _alias_recs()
|
|
4495
4519
|
else:
|
|
4496
4520
|
_alias_iter = _records_from_paths(alias_paths or [])
|
|
@@ -4832,7 +4856,7 @@ _SEARCH_PROBE_UNTIL = [0.0]
|
|
|
4832
4856
|
SERVER_SEARCH_WINDOW = 200
|
|
4833
4857
|
|
|
4834
4858
|
|
|
4835
|
-
def _server_search(q: str = "", city: str = "", gb:
|
|
4859
|
+
def _server_search(q: str = "", city: str = "", gb: Any = "", et: int = 0,
|
|
4836
4860
|
limit: int = SERVER_SEARCH_WINDOW,
|
|
4837
4861
|
cap: Optional[List[str]] = None) -> Optional[Dict[str, Any]]:
|
|
4838
4862
|
"""POST /v1/search —— 服务端检索(「按条来拉」的检索面,2026-11-03)。
|
|
@@ -4849,8 +4873,13 @@ def _server_search(q: str = "", city: str = "", gb: str = "", et: int = 0,
|
|
|
4849
4873
|
return None
|
|
4850
4874
|
if time.time() < _SEARCH_PROBE_UNTIL[0]:
|
|
4851
4875
|
return None
|
|
4852
|
-
|
|
4853
|
-
|
|
4876
|
+
# 2026-11-13:gb 可为多个国标码(别名「注塑」→2929/3525/3399)。
|
|
4877
|
+
# 一次请求全交给 worker,别再逐码各发一次 —— 额度与 RTT 都按请求数翻。
|
|
4878
|
+
if isinstance(gb, (list, tuple, set)):
|
|
4879
|
+
gb_list = [str(x).strip() for x in gb if str(x).strip()][:6]
|
|
4880
|
+
else:
|
|
4881
|
+
gb_list = [str(gb).strip()] if str(gb or "").strip() else []
|
|
4882
|
+
if not (str(q or "").strip() or str(city or "").strip() or gb_list or cap):
|
|
4854
4883
|
return None
|
|
4855
4884
|
try:
|
|
4856
4885
|
import identity as _idn
|
|
@@ -4860,8 +4889,11 @@ def _server_search(q: str = "", city: str = "", gb: str = "", et: int = 0,
|
|
|
4860
4889
|
payload: Dict[str, Any] = {"q": str(q or ""), "limit": int(limit), "offset": 0}
|
|
4861
4890
|
if str(city or "").strip():
|
|
4862
4891
|
payload["city"] = str(city).strip()
|
|
4863
|
-
if
|
|
4864
|
-
|
|
4892
|
+
if gb_list:
|
|
4893
|
+
# 旧 worker 只认单码 gb:首码照传,保证线上还没部署新 worker 时
|
|
4894
|
+
# 至少这一个码仍生效;新 worker 见到 gbs 数组会改用多码列举。
|
|
4895
|
+
payload["gb"] = gb_list[0]
|
|
4896
|
+
payload["gbs"] = gb_list
|
|
4865
4897
|
if et:
|
|
4866
4898
|
payload["et"] = int(et)
|
|
4867
4899
|
if cap:
|
|
@@ -4893,7 +4925,8 @@ def _server_search(q: str = "", city: str = "", gb: str = "", et: int = 0,
|
|
|
4893
4925
|
if isinstance(hits, list):
|
|
4894
4926
|
return {"total": int(o.get("total_matched") or 0),
|
|
4895
4927
|
"cap_matched": int(o.get("cap_matched") or 0),
|
|
4896
|
-
"records": hits
|
|
4928
|
+
"records": hits,
|
|
4929
|
+
"gbs_supported": bool(o.get("gbs_supported"))}
|
|
4897
4930
|
continue
|
|
4898
4931
|
except _ue.HTTPError as e:
|
|
4899
4932
|
st[0] = e.code
|
|
@@ -4904,7 +4937,8 @@ def _server_search(q: str = "", city: str = "", gb: str = "", et: int = 0,
|
|
|
4904
4937
|
try:
|
|
4905
4938
|
_o = json.loads(e.read().decode("utf-8"))
|
|
4906
4939
|
if _o.get("error") == "bad_gb":
|
|
4907
|
-
return {"total": 0, "records": []
|
|
4940
|
+
return {"total": 0, "records": [],
|
|
4941
|
+
"gbs_supported": False}
|
|
4908
4942
|
except Exception:
|
|
4909
4943
|
pass
|
|
4910
4944
|
continue
|
|
@@ -5478,6 +5512,9 @@ TOOLS = [
|
|
|
5478
5512
|
"加 radius_km 只留圈内(地标名需调用方先解析成坐标)。"
|
|
5479
5513
|
"返回精简档案(id/名称/城市/区县/国标码/认证等级/"
|
|
5480
5514
|
"工艺/材料/认证/是否含电话/连锁门店数/距离)。"
|
|
5515
|
+
"每条带 process_evidence:null=有事实工艺;inferred:A1~B0=零采集"
|
|
5516
|
+
"推断(分档非核实);class_default=挂的是国标小类默认工艺码(≥4个),"
|
|
5517
|
+
"不是这家企业的事实工艺,严苛场景请降权或追问核实。"
|
|
5481
5518
|
"⚠ 关键词是**字面子串**匹配:用户的口语词若与名录写法不同(如「机加工」"
|
|
5482
5519
|
"vs 归档用的「机械零部件加工」、「面馆」vs「苏式面馆」),命中会偏少。"
|
|
5483
5520
|
"此时不要直接报「没有」——看返回体里的 hint / suggested_gb,"
|
|
@@ -5665,15 +5702,19 @@ TOOLS = [
|
|
|
5665
5702
|
"在自己的浏览器里输入 —— 让他把验证码念给你,等于把「证明他是这家企业」"
|
|
5666
5703
|
"的凭证交给第三方,还会进入对话上下文与日志。"
|
|
5667
5704
|
"⚠ 不要替用户编造企业信息,不要承诺审核结果或时效,"
|
|
5668
|
-
"
|
|
5705
|
+
"也不要把未认领的企业说成「已经属于你」。\n"
|
|
5706
|
+
"返回体另带 agent_channel(契约 v3.0):一条**非手机 App** 的 HTTP/JSON 自助通道,"
|
|
5707
|
+
"供供应商自己的 Agent 认领并上传资料(intent=agent 看完整说明)。"
|
|
5708
|
+
"该通道必须手机验证码登录,且认领前还要求「登录手机号 = 工商登记法人手机号」"
|
|
5709
|
+
"一致性核查通过。本工具仍然只读指路,不发任何写请求、不持有密钥。",
|
|
5669
5710
|
"inputSchema": {
|
|
5670
5711
|
"type": "object",
|
|
5671
5712
|
"properties": {
|
|
5672
5713
|
"supplier_id": {"type": "string",
|
|
5673
5714
|
"description": "可选。已在检索结果里拿到的企业 ID(如 CN-MFG-0020317),用于生成直达深链,省得用户再搜一遍公司名"},
|
|
5674
5715
|
"company": {"type": "string", "description": "可选。企业名称,用于把步骤说得更具体"},
|
|
5675
|
-
"intent": {"type": "string", "enum": ["claim", "register", "status"],
|
|
5676
|
-
"description": "claim=认领库里已收录的企业(默认);register=库里没有、要新建档;status
|
|
5716
|
+
"intent": {"type": "string", "enum": ["claim", "register", "status", "agent"],
|
|
5717
|
+
"description": "claim=认领库里已收录的企业(默认);register=库里没有、要新建档;status=查自己申请的审核进度;agent=看非 App 的 Agent HTTP 自助通道(端点契约 + 用法)"},
|
|
5677
5718
|
},
|
|
5678
5719
|
},
|
|
5679
5720
|
},
|
|
@@ -5716,21 +5757,33 @@ TOOLS = [
|
|
|
5716
5757
|
|
|
5717
5758
|
|
|
5718
5759
|
CONSOLE_BASE = "https://beacon-mfg.pages.dev/console/"
|
|
5760
|
+
AGENT_API_BASE = "https://beacon-mfg.pages.dev/api"
|
|
5761
|
+
AGENT_CONTRACT_URL = "https://beacon-mfg.pages.dev/agent-onboard.json"
|
|
5719
5762
|
|
|
5720
5763
|
|
|
5721
5764
|
def vendor_onboarding(supplier_id: str = "", company: str = "",
|
|
5722
5765
|
intent: str = "claim") -> Dict[str, Any]:
|
|
5723
|
-
"""
|
|
5766
|
+
"""给供应商两个**能自己走完**的入驻入口:浏览器控制台,以及非 App 的 Agent HTTP 通道。
|
|
5724
5767
|
|
|
5725
|
-
为什么 MCP
|
|
5768
|
+
为什么 MCP 本身只做到「指路」
|
|
5726
5769
|
------------------------------
|
|
5727
|
-
|
|
5728
|
-
|
|
5729
|
-
|
|
5730
|
-
|
|
5731
|
-
|
|
5732
|
-
|
|
5733
|
-
|
|
5770
|
+
公开 MCP 包是只读的(文件头红线):任何匿名 Agent 都能调用检索工具,
|
|
5771
|
+
在里面塞写工具等于让检索方顺手改别人的企业档案。所以写能力放在**独立
|
|
5772
|
+
HTTP 通道**,由企业自己的 Agent 持「手机验证码登录签发的用户 JWT」调用,
|
|
5773
|
+
且认领一律以 pending 申请结束,交人工复核。
|
|
5774
|
+
|
|
5775
|
+
认领的两段身份证明(v3.0)
|
|
5776
|
+
--------------------------
|
|
5777
|
+
① 手机验证码登录(腾讯云短信)→ JWT,证明「持有这个手机号」;
|
|
5778
|
+
② 该手机号必须与「平台已核验的工商登记法人手机号基准」一致,
|
|
5779
|
+
证明「这个号是这家企业工商登记的法人手机号」。
|
|
5780
|
+
两者都成立才允许提交认领。工商登记法人手机号不是公开可查数据,
|
|
5781
|
+
基准由平台依据营业执照/工商档案人工核实后登记,可信级别
|
|
5782
|
+
platform_manual_verified,不冒充政府接口核验。
|
|
5783
|
+
|
|
5784
|
+
凭证边界仍然成立:短信验证码这类「证明我是这家企业」的东西由企业本人
|
|
5785
|
+
在浏览器输入,Agent 不得索取、转述或编造;USCC 由企业自己提供,
|
|
5786
|
+
且它只是公开信息,不足以单独构成认领依据。
|
|
5734
5787
|
"""
|
|
5735
5788
|
from urllib.parse import quote as _q
|
|
5736
5789
|
|
|
@@ -5753,25 +5806,94 @@ def vendor_onboarding(supplier_id: str = "", company: str = "",
|
|
|
5753
5806
|
url = CONSOLE_BASE + ("?id=" + _q(sid, safe="") if sid else "")
|
|
5754
5807
|
intent = (intent or "claim").strip().lower()
|
|
5755
5808
|
|
|
5756
|
-
|
|
5809
|
+
# 非手机 App 的写入通道。只描述契约,不代发请求、不持有任何密钥。
|
|
5810
|
+
agent_channel = {
|
|
5811
|
+
"kind": "http-json",
|
|
5812
|
+
"no_app_required": True,
|
|
5813
|
+
"auth_required": True,
|
|
5814
|
+
"contract_url": AGENT_CONTRACT_URL,
|
|
5815
|
+
"api_base": AGENT_API_BASE,
|
|
5816
|
+
"docs": "契约 JSON 本身即完整文档;平台本地工作副本另有 docs/AGENT_ONBOARD.md"
|
|
5817
|
+
"(非分发面,不在公开 GitHub 仓库)",
|
|
5818
|
+
"client": "按契约用任意 HTTP 客户端 / curl 实现即可;平台工作副本另有 scripts/agent_onboard.py "
|
|
5819
|
+
"CLI(同样不在公开仓库)",
|
|
5820
|
+
"contract_version": "3.1",
|
|
5821
|
+
"auth": {
|
|
5822
|
+
"login": "POST /auth/sms/send → /auth/sms/verify(腾讯云短信真实下发,"
|
|
5823
|
+
"验证码由企业本人输入)→ 用户 JWT(30 天)",
|
|
5824
|
+
"required": "所有 /agent/* 端点必须带 Authorization: Bearer <JWT>;匿名与伪造 token 均 401,"
|
|
5825
|
+
"后端 get_current_user 真校验,Worker 层再做一次前置拒绝",
|
|
5826
|
+
"operator": "仅平台人工复核使用 BEACON_OPERATOR_TOKEN,外部 Agent 不持有",
|
|
5827
|
+
},
|
|
5828
|
+
"legal_phone_gate": {
|
|
5829
|
+
"rule": "提交认领前,登录手机号必须等于该企业工商登记法人手机号;"
|
|
5830
|
+
"不一致 / 无基准 / 未登录一律拒绝且不落申请",
|
|
5831
|
+
"why": "短信验证码只证明持有号码;平台已核验的法人手机号基准才证明该号属于这家企业",
|
|
5832
|
+
"data_source": "工商登记法人手机号不是公开可查数据(公示系统只公开法人姓名);"
|
|
5833
|
+
"基准由 operator 依据营业执照/工商档案人工核实后登记,"
|
|
5834
|
+
"只存 HMAC 哈希,可信级别 platform_manual_verified",
|
|
5835
|
+
"check": "GET /agent/legal-phone/check?supplier_id=... → status: match 才放行",
|
|
5836
|
+
"bootstrap": "no_baseline 时 POST /agent/legal-phone/request 发起核验申请;"
|
|
5837
|
+
"平台建立基准后用同一手机号登录即可通过",
|
|
5838
|
+
"denials": "LOGIN_REQUIRED / LEGAL_PHONE_NOT_VERIFIED / LEGAL_PHONE_MISMATCH / TOO_MANY_CHECKS",
|
|
5839
|
+
"also_applies_to": "/claim/confirm(App 三步认领链路,后端同一道闸门)",
|
|
5840
|
+
},
|
|
5841
|
+
"flows": {
|
|
5842
|
+
"identity_check": "GET /agent/me(确认这次连接确实带着登录过的账号)",
|
|
5843
|
+
"legal_phone_check": "GET /agent/legal-phone/check(认领前必做,须返回 match)",
|
|
5844
|
+
"legal_phone_request": "POST /agent/legal-phone/request(基准为空时的冷启动)",
|
|
5845
|
+
"claim": "POST /agent/claim(supplier_id 必填;USCC 可选资料;先过 legal_phone_gate)→ pending 申请",
|
|
5846
|
+
"profile_upload": "POST /agent/profile(结构化资料一次提交)→ pending 申请",
|
|
5847
|
+
"self_register": "POST /agent/register(公司名 / 地址 / 门类)→ pending 申请;"
|
|
5848
|
+
"人审通过后由 operator 分配 supplier_id 并建档",
|
|
5849
|
+
"status": "GET /agent/applications(只按 JWT 的 user_id 查自己提交的)",
|
|
5850
|
+
},
|
|
5851
|
+
"not_for_agents": "/claim/verify-start、/claim/submit-uscc 与 /v1/collect/* 是手机 App 内部链路;"
|
|
5852
|
+
"/claim/confirm 现已要求用户 JWT 并走同一道法人手机号闸门。"
|
|
5853
|
+
"外部 Agent 一律走 /agent/*。",
|
|
5854
|
+
"result": "所有提交只落 vendor_application(status=pending, channel=agent),"
|
|
5855
|
+
"带登录账号 user_id;只有 operator 批准后才写 claimed / 上架",
|
|
5856
|
+
"boundary": "本工具只读指路。短信验证码由企业本人在自己设备上输入,"
|
|
5857
|
+
"Agent 不得索取、转述或代填;USCC 由企业自己提供,且只是资料字段、不是身份凭证。"
|
|
5858
|
+
"不要对外宣称「政府接口实时核验法人手机号」。",
|
|
5859
|
+
}
|
|
5860
|
+
|
|
5861
|
+
if intent == "agent":
|
|
5862
|
+
steps = [
|
|
5863
|
+
f"取契约:GET {AGENT_CONTRACT_URL}(v3.0,含 legal_phone_gate)",
|
|
5864
|
+
f"写接口基址固定为 {AGENT_API_BASE};**这条通道需要身份认证,不是免身份的**",
|
|
5865
|
+
"先登录:POST /auth/sms/send {phone} → /auth/sms/verify {phone, code} 换用户 JWT。"
|
|
5866
|
+
"腾讯云短信真实下发;验证码须由企业本人在自己设备上读取并输入,Agent 不得索取或转述",
|
|
5867
|
+
"身份自检:GET /agent/me,带 Authorization: Bearer <JWT>;200 才继续",
|
|
5868
|
+
"**认领前必做**:GET /agent/legal-phone/check?supplier_id=... 须返回 status=match"
|
|
5869
|
+
"(登录手机号 = 工商登记法人手机号)。no_baseline 走 /agent/legal-phone/request,"
|
|
5870
|
+
"mismatch 改用工商登记法人手机号重新登录",
|
|
5871
|
+
"认领 POST /agent/claim | 上传资料 POST /agent/profile | 新建档 POST /agent/register | "
|
|
5872
|
+
"查进度 GET /agent/applications,全部带同一个 JWT",
|
|
5873
|
+
"⚠ 所有提交只落 pending,人审批准后才生效;基准是平台人工核验结果,"
|
|
5874
|
+
"不要对外宣称「政府接口实时核验」",
|
|
5875
|
+
]
|
|
5876
|
+
elif intent == "register":
|
|
5757
5877
|
steps = [
|
|
5758
|
-
"
|
|
5878
|
+
"打开控制台链接,用手机号收验证码登录(同一个号在 App 与网页是同一账号)",
|
|
5759
5879
|
"在「找到我的企业」里搜公司名;搜不到就走「新建档」",
|
|
5760
5880
|
"填主体 / 联系 / 产能 / 质量 / 服务与产品条目(单价可不填,对外显示「面议」)",
|
|
5761
5881
|
"提交后进入人工审核;不通过会带**逐字段理由**退回,改完可重新提交",
|
|
5882
|
+
"若让 Agent 代办新建档:同样先手机验证码登录,再 POST /agent/register "
|
|
5883
|
+
"(company / claimed_address / gate),人审通过后由平台分配正式 ID",
|
|
5762
5884
|
]
|
|
5763
5885
|
elif intent == "status":
|
|
5764
5886
|
steps = [
|
|
5765
|
-
"
|
|
5887
|
+
"打开控制台链接,用提交时那个手机号登录",
|
|
5766
5888
|
"页面会列出「我的申请」:待审核 / 已通过 / 已驳回(驳回带理由)",
|
|
5767
5889
|
]
|
|
5768
5890
|
else:
|
|
5769
5891
|
steps = [
|
|
5770
|
-
"
|
|
5892
|
+
"打开控制台链接,用手机号收验证码登录(或让企业自己的 Agent 走 agent_channel HTTP 通道)",
|
|
5771
5893
|
"搜到自己的企业并选中(已在库里的话,公开信息会自动带成底稿,不用重填)",
|
|
5772
|
-
"
|
|
5773
|
-
"
|
|
5774
|
-
"提交认领申请 →
|
|
5894
|
+
"填 18 位统一社会信用代码(按 GB 32100-2015 校验位当场验);USCC 是公开信息,只是资料字段",
|
|
5895
|
+
"登录手机号还须与该企业工商登记法人手机号一致(平台已核验基准)才可提交认领",
|
|
5896
|
+
"提交认领申请 → 状态 pending,**人工复核通过后**才算认领成功",
|
|
5775
5897
|
]
|
|
5776
5898
|
|
|
5777
5899
|
return {
|
|
@@ -5780,17 +5902,27 @@ def vendor_onboarding(supplier_id: str = "", company: str = "",
|
|
|
5780
5902
|
"supplier_id": sid or None,
|
|
5781
5903
|
"intent": intent,
|
|
5782
5904
|
"steps": steps,
|
|
5783
|
-
"
|
|
5784
|
-
|
|
5905
|
+
"agent_channel": agent_channel,
|
|
5906
|
+
"boundary": "两条路径都需要身份认证:浏览器控制台与 Agent HTTP 通道都以手机验证码登录为前提,"
|
|
5907
|
+
"且认领还要求登录手机号与工商登记法人手机号一致,没有匿名写入。"
|
|
5908
|
+
"**不要让用户把验证码念给你**,Agent 不得索取、转述或代填;"
|
|
5909
|
+
"USCC 由企业自己提供,Agent 不编造、不代替企业确认。",
|
|
5785
5910
|
"what_not_to_do": [
|
|
5786
|
-
"
|
|
5911
|
+
"不要代替用户完成认领或注册(本工具不发写请求)",
|
|
5787
5912
|
"不要索取、转述或回显任何验证码",
|
|
5788
5913
|
"不要承诺审核结果或时效",
|
|
5789
5914
|
"不要把未认领的企业说成「已经属于该用户」",
|
|
5915
|
+
"不要把 claim_token 贴进公开日志或对话记录",
|
|
5916
|
+
"不要宣称「政府接口实时核验法人手机号」;基准是平台人工核验结果",
|
|
5917
|
+
"不要在 legal-phone/check 返回 no_baseline 或 mismatch 时继续提交认领",
|
|
5790
5918
|
],
|
|
5791
|
-
"why_not_here": "USCC
|
|
5792
|
-
"
|
|
5793
|
-
|
|
5919
|
+
"why_not_here": "USCC 是企业公开信息,单凭它认领等于把企业送人;"
|
|
5920
|
+
"能收短信也不等于代表这家公司。所以 Agent 通道要过"
|
|
5921
|
+
"「手机验证码登录 + 法人手机号一致性」两道证明,"
|
|
5922
|
+
"认领提交后只落 pending、由人工复核批准;公开 MCP 包保持只读。",
|
|
5923
|
+
"next": ("把 url 原样给用户,让他在浏览器里走完;"
|
|
5924
|
+
"若他是让 Agent 代办,把 agent_channel.contract_url 与 api_base 交给他的 Agent。"
|
|
5925
|
+
"完成后可以回来让你查他企业的能力卡。"),
|
|
5794
5926
|
}
|
|
5795
5927
|
|
|
5796
5928
|
|