@seasonkoh/webaz 0.1.16 → 0.1.17

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 (34) hide show
  1. package/README.md +60 -5
  2. package/dist/layer0-foundation/L0-2-state-machine/engine.js +3 -0
  3. package/dist/layer1-agent/L1-1-mcp-server/server.js +836 -716
  4. package/dist/layer2-business/L2-8-feedback/build-feedback-engine.js +169 -0
  5. package/dist/layer3-trust/L3-1-dispute-engine/dispute-engine.js +16 -0
  6. package/dist/layer4-economics/L4-3-reputation/reputation-engine.js +1 -0
  7. package/dist/mcp.js +7 -3
  8. package/dist/pwa/data/onboarding-cases.js +345 -0
  9. package/dist/pwa/data/onboarding-quiz.js +247 -0
  10. package/dist/pwa/public/app.js +1410 -96
  11. package/dist/pwa/public/i18n.js +280 -2
  12. package/dist/pwa/public/icon-192.png +0 -0
  13. package/dist/pwa/public/icon-512.png +0 -0
  14. package/dist/pwa/public/manifest.json +5 -2
  15. package/dist/pwa/public/openapi.json +1 -1
  16. package/dist/pwa/public/sw.js +1 -1
  17. package/dist/pwa/routes/admin-protocol-params.js +80 -2
  18. package/dist/pwa/routes/admin-reports.js +14 -9
  19. package/dist/pwa/routes/auth-read.js +3 -1
  20. package/dist/pwa/routes/build-feedback.js +67 -0
  21. package/dist/pwa/routes/disputes-write.js +149 -1
  22. package/dist/pwa/routes/governance-auto-deactivate.js +108 -0
  23. package/dist/pwa/routes/governance-onboarding.js +785 -0
  24. package/dist/pwa/routes/leaderboard.js +10 -2
  25. package/dist/pwa/routes/orders-action.js +5 -1
  26. package/dist/pwa/routes/products-meta.js +30 -0
  27. package/dist/pwa/routes/profile-identity.js +1 -1
  28. package/dist/pwa/routes/public-utils.js +44 -0
  29. package/dist/pwa/routes/rewards-apply.js +210 -0
  30. package/dist/pwa/routes/rewards-auto-downgrade.js +65 -0
  31. package/dist/pwa/routes/rewards-escrow-expire.js +48 -0
  32. package/dist/pwa/routes/webauthn.js +1 -1
  33. package/dist/pwa/server.js +570 -63
  34. package/package.json +6 -3
@@ -11,6 +11,11 @@
11
11
  * webaz_update_order L1-6 更新订单状态(发货/揽收/投递/确认/争议)
12
12
  * webaz_get_status L1-4 查询订单状态和历史
13
13
  * webaz_wallet 查看钱包余额
14
+ * …(38 工具,完整定义见下方 TOOLS 数组;数量以 TOOLS.length 为准)
15
+ *
16
+ * 双模(RFC-003):NETWORK(WEBAZ_API_KEY → 调 webaz.xyz)/ SANDBOX(本机库);见 NETWORK_TOOLS / apiCall / toolBackend。
17
+ * 关联 / Related: AGENTS.md · RFC-003(双模) · RFC-004(webaz_feedback) · 元规则 #4 不撒谎(_mode 戳) /
18
+ * #6 不滥用(agent 责任制 + Iron-Rule 真人动作)· 生产端点在 src/pwa(NETWORK 共用)
14
19
  */
15
20
  import { Server } from '@modelcontextprotocol/sdk/server/index.js';
16
21
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
@@ -30,6 +35,86 @@ const TELEMETRY_URL = process.env.WEBAZ_TELEMETRY_URL ?? 'https://webaz.xyz/api/
30
35
  // 2026-06-01: phase A pre-launch 默认 OFF(opt-in)— W8 public launch 时翻回 default ON + 加 README 披露段
31
36
  // Phase A pre-launch: telemetry default OFF (opt-in). Flip to default ON at W8 launch + add README disclosure section.
32
37
  const TELEMETRY_ENABLED = (process.env.WEBAZ_TELEMETRY ?? 'off').toLowerCase() === 'on';
38
+ // ─── RFC-003 P0: 双模(NETWORK / SANDBOX)骨架 ─────────────────────
39
+ // NETWORK = 带 api_key 调 webaz.xyz/api(加入共享生产网络);SANDBOX = 本地 SQLite(离线试玩,与全网隔离)。
40
+ // P0 不迁移任何工具(NETWORK_TOOLS 为空)→ 一切仍走本地 = 零行为变化;P1/P2 逐个把工具名加入集合切到网络。
41
+ const WEBAZ_API_URL = (process.env.WEBAZ_API_URL ?? 'https://webaz.xyz').replace(/\/+$/, '');
42
+ const WEBAZ_API_KEY = process.env.WEBAZ_API_KEY ?? '';
43
+ const WEBAZ_MODE_ENV = (process.env.WEBAZ_MODE ?? '').toLowerCase();
44
+ // 模式:显式 WEBAZ_MODE 优先;否则有 api_key → network,无 → sandbox
45
+ const MODE = WEBAZ_MODE_ENV === 'network' ? 'network'
46
+ : WEBAZ_MODE_ENV === 'sandbox' ? 'sandbox'
47
+ : (WEBAZ_API_KEY ? 'network' : 'sandbox');
48
+ // 已迁移到 NETWORK 的工具名。P1/P2 逐个加入;未在集合里的工具仍走 sandbox(本地)。
49
+ // P1(读工具): 纯公开读,无写无 Passkey,作"MCP 连得上生产网络"的首验证。
50
+ const NETWORK_TOOLS = new Set([
51
+ 'webaz_price_history',
52
+ 'webaz_leaderboard',
53
+ 'webaz_verify_price',
54
+ 'webaz_place_order',
55
+ 'webaz_list_product',
56
+ 'webaz_update_order',
57
+ 'webaz_search',
58
+ 'webaz_get_status',
59
+ 'webaz_feedback',
60
+ ]);
61
+ const recentCalls = [];
62
+ function pushRecentCall(c) {
63
+ recentCalls.push(c);
64
+ if (recentCalls.length > 8)
65
+ recentCalls.shift(); // 只留最近 8 条
66
+ }
67
+ // 单个工具实际后端:仅当全局 network 且该工具已迁移,才走网络;否则 sandbox。
68
+ function toolBackend(tool) {
69
+ return (MODE === 'network' && NETWORK_TOOLS.has(tool)) ? 'network' : 'sandbox';
70
+ }
71
+ // 统一 API helper(P1/P2 迁移工具时使用)。Bearer api_key + 15s 超时 + 错误映射。
72
+ async function apiCall(path, opts = {}) {
73
+ const { method = 'GET', body } = opts;
74
+ const key = opts.apiKey || WEBAZ_API_KEY; // 每次调用可覆盖(工具 args.api_key 优先);否则用全局配置 key
75
+ const url = WEBAZ_API_URL + (path.startsWith('/') ? path : '/' + path);
76
+ try {
77
+ const resp = await fetch(url, {
78
+ method,
79
+ headers: {
80
+ ...(key ? { authorization: `Bearer ${key}` } : {}),
81
+ ...(body != null ? { 'content-type': 'application/json' } : {}),
82
+ },
83
+ ...(body != null ? { body: JSON.stringify(body) } : {}),
84
+ signal: AbortSignal.timeout(15_000),
85
+ });
86
+ let json = null;
87
+ try {
88
+ json = await resp.json();
89
+ }
90
+ catch {
91
+ json = null;
92
+ }
93
+ if (!resp.ok) {
94
+ const map = {
95
+ 401: 'api_key 无效或未注册 — 请在 https://webaz.xyz 注册并把 api_key 填入 WEBAZ_API_KEY',
96
+ 403: '权限不足 / 需邀请码 / 该动作需真人 Passkey(请到 webaz.xyz 用 Passkey 操作)',
97
+ 429: '调用过于频繁,请稍后再试',
98
+ 503: '服务暂不可用,请稍后重试',
99
+ };
100
+ return { error: json?.error ?? map[resp.status] ?? `HTTP ${resp.status}`, error_code: json?.error_code, http_status: resp.status };
101
+ }
102
+ return json ?? {};
103
+ }
104
+ catch (e) {
105
+ const msg = e.name === 'TimeoutError' ? '请求超时(15s)' : e.message;
106
+ return { error: `网络错误:${msg}`, network_error: true };
107
+ }
108
+ }
109
+ // 启动 banner(stderr)+ status 声明用 —— 让用户/agent 一眼知道现在是真网络还是沙盒
110
+ function modeBanner() {
111
+ if (MODE === 'network') {
112
+ return `🟢 NETWORK mode — webaz.xyz (${WEBAZ_API_URL}). Migrated tools: ${NETWORK_TOOLS.size}/${TOOLS.length}`
113
+ + (NETWORK_TOOLS.size === 0 ? ' ⚠️ network client not active yet (P0 scaffold) — all tools still SANDBOX/local.' : '');
114
+ }
115
+ return `🟡 SANDBOX mode — local-only (~/.webaz/webaz.db), NOT the live network. Data is private to this machine.`
116
+ + (WEBAZ_API_KEY ? '' : ' Set WEBAZ_API_KEY (register at webaz.xyz) to join the network.');
117
+ }
33
118
  // ─── 初始化 ──────────────────────────────────────────────────
34
119
  const db = initDatabase();
35
120
  initSystemUser(db);
@@ -167,46 +252,31 @@ No auth required, no parameters needed.
167
252
  },
168
253
  {
169
254
  name: 'webaz_register',
170
- description: `Register a new WebAZ account. Returns:
171
- - api_key (credential, 36 chars, 128-bit crypto randomstore securely)
172
- - permanent_code (6-char recovery code — use with handle via webaz_mykey to recover lost api_key)
173
- - handle (URL-safe unique ID derived from name; if requested handle is taken, system auto-appends numeric suffix — check handle_modified flag)
174
- - created_at (ISO timestamp)
175
-
176
- ⚠️ Consent required: WebAZ is pre-launch and contains a 3-tier commission + binary PV pairing structure (see webaz_info.commission_model.compliance_notice — may overlap with MLM legal definitions). An agent acting for a human user MUST get the user's explicit, informed consent BEFORE creating an account on their behalf. Do NOT auto-register users just because they asked a generic shopping question.
255
+ // was ~1732 chars, now ~780 chars
256
+ description: `Register a new WebAZ account. Returns: api_key (36-char 128-bit credential, store securely) + permanent_code (6-char recovery code, pair with handle in webaz_mykey to recover lost api_key) + handle (URL-safe ID; if taken, system appends numeric suffix check handle_modified flag) + created_at.
177
257
 
178
- Roles:
179
- - buyer: browse, order, confirm receipt
180
- - seller: list products, accept orders, ship
181
- - logistics: pickup, transit updates, delivery confirm
182
- - reviewer: structured product reviews
183
- - arbitrator: handle disputes, issue rulings
258
+ ⚠️ **Consent required (MLM disclosure)**: WebAZ is pre-launch with 3-tier commission + binary PV pairing structure (may overlap with MLM legal definitions; see webaz_info.commission_model.compliance_notice). Agent acting on behalf of human user **MUST get explicit informed consent BEFORE creating account**. Do NOT auto-register from generic shopping questions.
184
259
 
185
- ⚠️ MCP register limitations (by-design anti-bot):
186
- - Does NOT set placement_id / sponsor_id (binary tree + referral chain not built) — MCP registration does NOT enroll the user into the multi-tier structure
187
- - To build a referral chain: user must arrive via webaz_share_link ?ref=<uid> URL clicked in browser (PWA flow) — explicit user action required
188
- - region defaults to 'global' if omitted; valid: singapore, china, usa, malaysia, indonesia, thailand, vietnam, taiwan, hk, global
260
+ Roles: buyer (browse/order/confirm) | seller (list/accept/ship) | logistics (pickup/transit/deliver) | reviewer (reviews) | arbitrator (disputes/rulings).
189
261
 
190
- ──
191
- 中文:注册 WebAZ 账户。返回 api_key(128-bit 凭证)+ permanent_code(恢复码)+ handle(唯一标识,冲突自动加后缀,看 handle_modified)+ created_at。可选角色:买家/卖家/物流/测评员/仲裁员。
192
- 注意:MCP register 不建立 placement/sponsor 链(防 bot),需要建链时用 webaz_share_link + PWA 浏览器注册。`,
262
+ ⚠️ **MCP register limitations (anti-bot, by design)**: does NOT set placement_id/sponsor_id — referral/PV chain NOT built via MCP. To build chain: user must arrive via webaz_share_link \`?ref=<uid>\` URL clicked in browser (PWA flow). region defaults 'global'; valid: singapore/china/usa/malaysia/indonesia/thailand/vietnam/taiwan/hk/global.`,
193
263
  inputSchema: {
194
264
  type: 'object',
195
265
  properties: {
196
- name: { type: 'string', description: '你的名字或店铺名称' },
266
+ name: { type: 'string', description: 'Your name or shop name' },
197
267
  role: {
198
268
  type: 'string',
199
269
  enum: ['buyer', 'seller', 'logistics', 'reviewer', 'arbitrator'],
200
- description: '你在协议中的角色',
270
+ description: 'Your role in the protocol',
201
271
  },
202
272
  initial_balance: {
203
273
  type: 'number',
204
- description: '初始模拟余额(测试用,默认 1000 WAZ',
274
+ description: 'Initial mock balance (for testing, default 1000 WAZ)',
205
275
  },
206
276
  region: {
207
277
  type: 'string',
208
278
  enum: ['global', 'singapore', 'china', 'usa', 'malaysia', 'indonesia', 'thailand', 'vietnam', 'taiwan', 'hk'],
209
- description: '账号所在地区(默认 global;影响 referral region cap 与佣金 redirect_region_cap 规则)',
279
+ description: 'Account region (default global; affects referral region cap + commission redirect_region_cap rules)',
210
280
  },
211
281
  },
212
282
  required: ['name', 'role'],
@@ -214,184 +284,133 @@ Roles:
214
284
  },
215
285
  {
216
286
  name: 'webaz_search',
287
+ // was ~2607 chars, now ~1050 chars
217
288
  description: `Search WebAZ marketplace + cross-platform anchor lookup. No auth required.
218
289
 
219
- ⚠️ **STRICT MATCH ONLY** query 永远是精准匹配(等于 title / 等于 external_title / 包含 ≥6 字符 alias)
220
- 不做 fuzzy LIKE 模糊降级。短查询(如 "钱包" "iphone")很大概率 0 命中,这是设计如此,不是 bug。
221
- 0 命中时,**不要**自己拼短词 retry,也**不要**调别的工具假装搜索;应**引导用户访问 https://webaz.xyz/#discover**
222
- 在搜索框输入关键词浏览(那里有 fuzzy LIKE)。模糊搜索是用户主动行为,不是 agent 代办。
290
+ ⚠️ **STRICT MATCH ONLY** (no fuzzy fallback). query matches = exact title OR exact external_title OR alias ≥6 chars contained in user text. Short queries (e.g. "iphone") likely return 0 — **this is by design, NOT a bug**. On 0 results: do NOT retry with shorter terms, do NOT call other tools to fake search. Direct user to https://webaz.xyz/#discover for fuzzy browse (user action, not agent's job).
223
291
 
224
292
  USE THIS when:
225
- - 用户给出 **完整商品标题 / SKU / 精准描述**(典型 strict match,如 "AirPods Pro 2 USB-C 港行"), OR
226
- - 用户给出 **筛选条件**(category / max_price / min_return_days / max_handling_hours / sort), OR
227
- - 用户粘贴 ANY external product URL/share-text from Taobao / Tmall / JD / PDD / 1688 / Douyin / Xiaohongshu
228
- → WebAZ exact-matches against its anchor registry (canonical product fingerprints across
229
- platforms). matched_by='none' means truly not indexed — do NOT silently fall back to keyword,
230
- and do NOT guess similar products.
231
-
232
- ⚠️ Do not skip this tool just because user gave you a URL — URL-paste is a first-class mode here,
233
- NOT a separate browser-fetch capability. Returns structured specs + logistics + after-sales +
234
- agent_summary (one-line decision hint).
235
-
236
- 【Keyword search — STRICT】Pass query / category / max_price / min_return_days / max_handling_hours.
237
- query 命中 = (1) 完全等于 product.title OR (2) 完全等于任一 external_title OR (3) 用户文本包含任一卖家声明 alias_value (≥6 字符)。模糊关键词请引导用户去 PWA #discover。
293
+ - User gives **full product title / SKU / precise description** (strict-match candidate), OR
294
+ - User gives **filters** (category / max_price / min_return_days / max_handling_hours / sort), OR
295
+ - User pastes **external URL / share-text** from Taobao / Tmall / JD / PDD / 1688 / Douyin / Xiaohongshu
296
+ URL-paste is a first-class mode of THIS tool, NOT a separate browser-fetch. WebAZ exact-matches against its cross-platform anchor registry.
238
297
 
239
- 【External-link paste searchWhen user pastes share text from Taobao/Tmall/JD/Pinduoduo/1688/Douyin/Xiaohongshu
240
- (e.g. '【淘宝】「Product Name」 https://e.tb.cn/xxx ...'), do:
241
- 1) Prefer your own LLM parsing → pass external_link object with:
242
- - platform: 'taobao'|'tmall'|'jd'|'pdd'|'1688'|'douyin'|'xhs'
243
- - external_id: canonical product ID (if resolvable from short URL; else omit)
244
- - external_title: the title text inside 「」 brackets verbatim
245
- 2) If you can't parse, drop the raw text into paste_text — WebAZ server does light regex parsing (no outbound calls)
298
+ 【External-link paste】Prefer LLM-parse into \`external_link\` { platform, external_id?, external_title } (title = verbatim text inside 「」). If unparseable, drop raw into \`paste_text\` (server does light regex). Match: L1 external_id exact → L2 external_title exact → else \`matched_by:'none'\`. **No fuzzy fallback, no keyword degradation, no similar-product guessing.** matched_by='none' = tell user honestly "no exact match"; trust premise is precise not "looks similar".
246
299
 
247
- Match rules (STRICT, no guessing):
248
- - Level 1: external_id exact match
249
- - Level 2: external_title string exact match
250
- - Neither hit → matched_by: 'none', **NO fuzzy fallback, NO keyword degradation**
251
-
252
- IMPORTANT: matched_by='none' is an honest signal — tell the user "no exact match found".
253
- Do NOT silently fall back to keyword search (that's a separate tool's job).
254
- Do NOT guess similar products from title impressions.
255
- WebAZ's trust premise is that match results are TRULY precise, not "looks similar".
256
-
257
- Note: paste-link matching hits webaz.xyz production data, not your local webaz.db.
258
-
259
- ──
260
- 中文:商品搜索(无需登录)。两种模式:关键词搜索 + 粘贴外链精准匹配。外链匹配强制精准(仅 external_id 或 external_title 完全相等命中),不命中返回 matched_by:'none',不做模糊降级。`,
300
+ Returns: structured specs + logistics + after-sales + agent_summary (one-line decision hint). Paste-link hits webaz.xyz prod data, not local webaz.db.`,
261
301
  inputSchema: {
262
302
  type: 'object',
263
303
  properties: {
264
- query: { type: 'string', description: '搜索关键词(商品名称或描述)' },
265
- category: { type: 'string', description: '商品分类过滤(可选)' },
266
- max_price: { type: 'number', description: '最高价格过滤(可选)' },
267
- min_return_days: { type: 'number', description: '最少退货天数(可选,如 7 表示只看支持7天退货的商品)' },
268
- max_handling_hours: { type: 'number', description: '最长发货时效小时数(可选,如 24 表示只看24h内发货的)' },
269
- paste_text: { type: 'string', description: '用户粘贴的分享文本/外链原文(可选,服务端做轻量解析)' },
304
+ query: { type: 'string', description: 'Search keyword (product name or description)' },
305
+ category: { type: 'string', description: 'Category filter (optional)' },
306
+ max_price: { type: 'number', description: 'Max price filter (optional)' },
307
+ min_return_days: { type: 'number', description: 'Min return days (optional, e.g. 7 = only ≥7-day return)' },
308
+ max_handling_hours: { type: 'number', description: 'Max handling hours (optional, e.g. 24 = only ≤24h dispatch)' },
309
+ paste_text: { type: 'string', description: 'Raw paste text / external link (optional; server does light regex parse)' },
270
310
  external_link: {
271
311
  type: 'object',
272
- description: '外链结构化匹配(可选,由 agent 解析得到)',
312
+ description: 'Structured external link match (optional, agent-parsed)',
273
313
  properties: {
274
314
  platform: { type: 'string', description: "'taobao'|'tmall'|'jd'|'pdd'|'1688'|'douyin'|'xhs'" },
275
- external_id: { type: 'string', description: '平台商品 canonical ID(可选)' },
276
- external_title: { type: 'string', description: '平台商品标题全文(可选)' },
277
- canonical_url: { type: 'string', description: '规范 URL(可选)' },
315
+ external_id: { type: 'string', description: 'Platform product canonical ID (optional)' },
316
+ external_title: { type: 'string', description: 'Platform product title verbatim (optional)' },
317
+ canonical_url: { type: 'string', description: 'Canonical URL (optional)' },
278
318
  },
279
319
  },
280
- limit: { type: 'number', description: '返回数量上限,默认 10agent 模式可调到 200' },
281
- sort: { type: 'string', enum: ['trending', 'newest', 'rating', 'price_asc', 'price_desc', 'random'], description: '排序:trending=综合分(默认),newest=最新,rating=信誉,price_asc/price_desc=价格,random=随机探索' },
282
- has_sales: { type: 'string', enum: ['true', 'false'], description: 'true=只看已成交,false=只看新品' },
283
- ship_to: { type: 'string', description: '配送目的地(省/市),自动过滤不可派送商品' },
284
- seller_id: { type: 'string', description: '只看某卖家的商品' },
285
- cursor: { type: 'string', description: '分页 cursor(上次返回的 next_cursor' },
320
+ limit: { type: 'number', description: 'Result limit, default 10; agent mode up to 200' },
321
+ sort: { type: 'string', enum: ['trending', 'newest', 'rating', 'price_asc', 'price_desc', 'random'], description: 'Sort: trending=composite (default) / newest / rating / price_asc / price_desc / random' },
322
+ has_sales: { type: 'string', enum: ['true', 'false'], description: 'true=only sold; false=only new' },
323
+ ship_to: { type: 'string', description: 'Ship-to (province/city); auto-filters unshippable' },
324
+ seller_id: { type: 'string', description: 'Filter to one seller' },
325
+ cursor: { type: 'string', description: 'Pagination cursor (from previous next_cursor)' },
286
326
  },
287
327
  },
288
328
  },
289
329
  {
290
330
  name: 'webaz_verify_price',
291
- description: `Lock product price + reserve stock window BEFORE webaz_place_order — returns session_token.
292
-
293
- USE THIS for EVERY purchase, not just price-sensitive ones. Reasons:
294
- (1) order price matches displayed (defeats flash-sale / hidden-fee races)
295
- (2) caller is alerted if price changed between view and order
296
- (3) protocol only liable for T0 price
297
- (4) reduces stock-depletion race on hot items (session_token is single-use within 10min)
331
+ // was ~647 chars, now ~370 chars
332
+ description: `Lock price + reserve stock BEFORE webaz_place_order — returns \`session_token\` (10-min TTL, single-use, pass to place_order).
298
333
 
299
- Skipping this is allowed but the agent then carries the price/stock-race risk itself. session_token: 10-minute TTL, single-use, pass it to webaz_place_order.
334
+ USE THIS for **EVERY purchase**: (1) defeats flash-sale / hidden-fee race (2) alerts if price drifted (3) protocol only liable for T0 price (4) reduces stock-depletion race on hot items.
300
335
 
301
- ──
302
- 中文:下单前锁价 — 10 分钟一次性 session_token;agent 应先调此再调 place_order。`,
336
+ Skipping is allowed but agent then carries price/stock-race risk itself.`,
303
337
  inputSchema: {
304
338
  type: 'object',
305
339
  properties: {
306
- api_key: { type: 'string', description: '买家的 api_key' },
307
- product_id: { type: 'string', description: '商品 ID(从 webaz_search 获得)' },
308
- quantity: { type: 'number', description: '购买数量,默认 1' },
340
+ api_key: { type: 'string', description: "Buyer's api_key" },
341
+ product_id: { type: 'string', description: 'Product ID (from webaz_search)' },
342
+ quantity: { type: 'number', description: 'Quantity, default 1' },
309
343
  },
310
344
  required: ['api_key', 'product_id'],
311
345
  },
312
346
  },
313
347
  {
314
348
  name: 'webaz_list_product',
315
- description: `⚠️ "list" = PUBLISH (verb), NOT "list out" (noun). Seller-only product catalog publishing & management.
349
+ // was ~1336 chars, now ~650 chars
350
+ description: `⚠️ **"list" = PUBLISH** (verb), NOT "list out". Seller-only catalog publish + manage.
316
351
 
317
- USE THIS when SELLER wants to:
318
- - publish a NEW product to their catalog, OR
319
- - update / delist / relist / trash / delete an existing product they own, OR
320
- - view their OWN listings (action=mine)
352
+ USE THIS when seller wants to publish / update / delist / relist / trash / delete own product, OR view own listings (action=mine). NOT for browsing marketplace — use webaz_search (anyone, no auth). Requires seller api_key. On create: system auto-suggests stake ~15% of price (buyer protection).
321
353
 
322
- NOT for browsing the marketplacefor that use webaz_search (anyone, no auth). Requires seller-role api_key. On create, system auto-suggests stake (~15% of price) to secure buyer protection.
354
+ Fill agent_summary fields completely (brand/return/handling/warranty)helps buyer agents compare. For "exclusive-price vs external-link" listing PWA Web only (link claim needs crowd-verify).
323
355
 
324
- Fill fields completely better agent_summary helps buyer agents make comparison decisions (brand / return / handling / warranty).
325
- Note: for "exclusive price vs external link" listing, use PWA Web only — link claim needs crowd-verification.
326
-
327
- Actions:
328
- - create list a new product (default; needs title/description/price)
329
- - mine list all my products (no product_id needed)
330
- - update modify fields (needs product_id; only changed fields)
331
- - delist move to warehouse (status: warehouse; needs product_id)
332
- - relist re-shelve from warehouse (status: active; needs product_id)
333
- - trash move to trash (status: deleted; needs product_id)
334
- - delete permanent delete (only trash items with no active orders; needs product_id)
335
-
336
- ──
337
- 中文:卖家商品目录管理(上架/更新/下架/回收/删除/查询)。Actions: create / mine / update / delist / relist / trash / delete。上架时系统自动建议 15% 价格的质押金。`,
356
+ Actions: create (title/description/price) | mine | update (product_id + changed fields) | delist (→ warehouse) | relist (warehouse active) | trash ( deleted) | delete (only trash, no active orders).`,
338
357
  inputSchema: {
339
358
  type: 'object',
340
359
  properties: {
341
- api_key: { type: 'string', description: '卖家的 api_key' },
360
+ api_key: { type: 'string', description: "Seller's api_key" },
342
361
  action: {
343
362
  type: 'string',
344
363
  enum: ['create', 'mine', 'update', 'delist', 'relist', 'trash', 'delete'],
345
- description: '要执行的操作(缺省 = create',
364
+ description: 'Action (default: create)',
346
365
  },
347
- product_id: { type: 'string', description: '商品 ID(update / delist / relist / trash / delete 时必填)' },
348
- title: { type: 'string', description: '商品名称(create 必填;update 可选)' },
349
- description: { type: 'string', description: '商品详细描述(create 必填;update 可选)' },
350
- price: { type: 'number', description: '商品价格 WAZcreate 必填;update 可选)' },
351
- stock: { type: 'number', description: '库存数量,默认 1' },
352
- category: { type: 'string', description: '商品分类(可选)' },
366
+ product_id: { type: 'string', description: 'Product ID (required for update/delist/relist/trash/delete)' },
367
+ title: { type: 'string', description: 'Product name (required for create; optional for update)' },
368
+ description: { type: 'string', description: 'Product description (required for create; optional for update)' },
369
+ price: { type: 'number', description: 'Price in WAZ (required for create; optional for update)' },
370
+ stock: { type: 'number', description: 'Stock, default 1' },
371
+ category: { type: 'string', description: 'Category (optional)' },
353
372
  specs: {
354
373
  type: 'object',
355
- description: '结构化规格键值对,如 {"颜色":"黑色","内存":"16GB","存储":"512GB"}(可选)',
374
+ description: 'Structured specs k/v, e.g. {"color":"black","ram":"16GB","storage":"512GB"} (optional)',
356
375
  },
357
- brand: { type: 'string', description: '品牌(可选)' },
358
- model: { type: 'string', description: '型号(可选)' },
376
+ brand: { type: 'string', description: 'Brand (optional)' },
377
+ model: { type: 'string', description: 'Model (optional)' },
359
378
  source_price: {
360
379
  type: 'number',
361
- description: '同款商品的外部参考价(可选,仅作展示,不参与独家价认证——需通过 PWA 完成链接认领)',
380
+ description: 'External reference price (optional, display only; exclusive-price auth needs PWA link-claim)',
362
381
  },
363
- ship_regions: { type: 'string', description: '发货地区,默认"全国"' },
364
- handling_hours: { type: 'number', description: '发货时效(小时),默认 24' },
382
+ ship_regions: { type: 'string', description: 'Ship region, default "all"' },
383
+ handling_hours: { type: 'number', description: 'Handling time (hours), default 24' },
365
384
  estimated_days: {
366
385
  type: 'object',
367
- description: '预计送达天数:数字(如 4)或区域映射(如 {"江浙沪":2,"全国":4}',
386
+ description: 'Estimated delivery days: number (e.g. 4) OR region map (e.g. {"east":2,"all":4})',
368
387
  },
369
- fragile: { type: 'boolean', description: '是否易碎品,默认 false' },
370
- return_days: { type: 'number', description: '支持退货天数,默认 7(填 0 表示不支持退货)' },
371
- return_condition: { type: 'string', description: '退货条件说明(可选)' },
372
- warranty_days: { type: 'number', description: '质保天数,默认 0' },
388
+ fragile: { type: 'boolean', description: 'Fragile flag, default false' },
389
+ return_days: { type: 'number', description: 'Return days, default 7 (0 = no returns)' },
390
+ return_condition: { type: 'string', description: 'Return conditions text (optional)' },
391
+ warranty_days: { type: 'number', description: 'Warranty days, default 0' },
373
392
  // S2 库存预警
374
393
  low_stock_threshold: {
375
394
  type: 'number',
376
- description: 'S2】库存预警阈值(≤ 此数时通知卖家;填 0 = 关闭预警)',
395
+ description: '[S2] Low-stock alert threshold (notify seller when ≤; 0 = disabled)',
377
396
  },
378
397
  auto_delist_on_zero: {
379
398
  type: 'boolean',
380
- description: 'S2】库存归零时自动下架到仓库(防超卖)',
399
+ description: '[S2] Auto-delist to warehouse when stock=0 (anti-oversell)',
381
400
  },
382
401
  // S3 跨境上架多语言
383
402
  i18n_titles: {
384
403
  type: 'object',
385
- description: 'S3】多语言标题,key 是语言码(en/ja/ko/fr/de/es/pt/ru/ar),value 是该语言标题(≤500 字)。zh title 字段,无需填这里。例: {"en":"Wireless Earbuds","ja":"ワイヤレスイヤホン"}',
404
+ description: '[S3] Multilingual titles, keys = en/ja/ko/fr/de/es/pt/ru/ar, values ≤500 chars. zh uses title field. E.g. {"en":"Wireless Earbuds","ja":"ワイヤレスイヤホン"}',
386
405
  },
387
406
  i18n_descs: {
388
407
  type: 'object',
389
- description: 'S3】多语言描述,结构同 i18n_titles',
408
+ description: '[S3] Multilingual descs, same structure as i18n_titles',
390
409
  },
391
410
  // S4 商品溯源(origin_claims)— 协议级可挑战
392
411
  origin_claims: {
393
412
  type: 'object',
394
- description: 'S4】商品溯源声明(可挑战)。例: {"made_in":"日本京都","material":"100% GOTS 认证","certs":[{"name":"GOTS","sha256":"<64hex>"}]}。整体 JSON ≤ 4KB;任一证书 sha256 必须是 64 hex。任何买家可发起 claim 验证。',
413
+ description: '[S4] Product-origin claims (challengeable). E.g. {"made_in":"Kyoto JP","material":"100% cotton GOTS-cert","certs":[{"name":"GOTS","sha256":"<64-hex>"}]}. Total JSON ≤4KB; any cert sha256 must be 64-hex. Any buyer can challenge.',
395
414
  },
396
415
  },
397
416
  required: ['api_key'],
@@ -399,49 +418,46 @@ Actions:
399
418
  },
400
419
  {
401
420
  name: 'webaz_place_order',
402
- description: `Buyer places an order. Requires buyer-role api_key.
421
+ // was ~1117 chars, now ~580 chars
422
+ description: `Buyer places order. Buyer api_key required. Funds auto-enter protocol escrow.
403
423
 
404
- On order, funds auto-enter protocol escrow. Order deadlines (all stored as absolute ISO timestamps in the response):
405
- - accept_deadline: T+48h (i.e., seller has 24h after the buyer's payment which is itself T+24h)
406
- - ship_deadline: T+120h (72h after accept)
407
- - pickup_deadline: T+168h (48h after ship)
408
- - delivery_deadline: T+336h (7d after pickup)
409
- - confirm_deadline: T+408h (72h after delivery)
424
+ Order deadlines (absolute ISO timestamps in response):
425
+ - accept T+48h | ship T+120h (72h after accept)
426
+ - pickup T+168h (48h after ship) | delivery T+336h (7d after pickup)
427
+ - confirm T+408h (72h after delivery)
410
428
 
411
- Missing any deadline auto-judges fault against the responsible party and triggers compensation per protocol economics.
429
+ Missing any auto-judge fault against responsible party + compensation per protocol.
412
430
 
413
- 【B1 Cross-border tax】For cross-border orders, server auto-estimates import duty (seller's est_import_duty_pct × price) and returns it in the response.
414
- 【B2 Privacy mode】Pass anonymous_recipient=true system generates a PR-XXXXX alias instead of real name on shipping label.
415
- 【B5 Donation】Optional donation_pct (0 / 0.5% / 1% / 2% / 5%) — sends that fraction of order amount to charity_fund.
416
-
417
- ──
418
- 中文:买家下单 — 资金进托管。订单 6 个 deadline 都是绝对时间戳,每个相对前一步的允许时长:accept 24h→ship 72h→pickup 48h→deliver 7d→confirm 72h。任何一个超时由对应责任方违约。可选:跨境关税估算 / 匿名收件 / 慈善捐赠。`,
431
+ Options:
432
+ - **B1 cross-border tax**: server auto-estimates duty (seller's est_import_duty_pct × price)
433
+ - **B2 privacy**: \`anonymous_recipient=true\` PR-XXXXX alias on shipping label
434
+ - **B5 donation**: \`donation_pct\` 0 / 0.5 / 1 / 2 / 5% → charity_fund`,
419
435
  inputSchema: {
420
436
  type: 'object',
421
437
  properties: {
422
- api_key: { type: 'string', description: '买家的 api_key' },
423
- product_id: { type: 'string', description: '要购买的商品 ID(从 webaz_search 获得)' },
424
- quantity: { type: 'number', description: '购买数量,默认 1' },
425
- shipping_address: { type: 'string', description: '收货地址' },
426
- notes: { type: 'string', description: '给卖家的备注(可选)' },
438
+ api_key: { type: 'string', description: "Buyer's api_key" },
439
+ product_id: { type: 'string', description: 'Product ID to buy (from webaz_search)' },
440
+ quantity: { type: 'number', description: 'Quantity, default 1' },
441
+ shipping_address: { type: 'string', description: 'Shipping address' },
442
+ notes: { type: 'string', description: 'Note to seller (optional)' },
427
443
  session_token: {
428
444
  type: 'string',
429
- description: '价格锁定 token(推荐):由 webaz_verify_price 返回,确保下单价格与展示价格一致',
445
+ description: 'Price-lock session_token (recommended): from webaz_verify_price; guarantees order price = displayed price',
430
446
  },
431
447
  promoter_api_key: {
432
448
  type: 'string',
433
- description: '推荐人的 api_key(可选)。⚠️ 仅记 L1(直接推荐人,70% commission);L2/L3 无法经 MCP 推断,会按 region 规则 redirect(singapore 等高 max_levels → charity chain_gapglobal max_levels=1 → global_fund region cap)。完整 7:2:1 三级链需买家经 webaz_share_link 生成的 ?ref= URL 浏览器点击(建 product_share_attribution)。',
449
+ description: "Referrer api_key (optional). ⚠️ Only L1 recorded (direct referrer, 70% commission); L2/L3 can't be inferred via MCP, redirects per region rule (singapore-like high max_levels → charity chain_gap; global max_levels=1 → global_fund region cap). Full 7:2:1 three-tier chain requires buyer clicking ?ref= URL from webaz_share_link (creates product_share_attribution).",
434
450
  },
435
451
  // B2 隐私购物
436
452
  anonymous_recipient: {
437
453
  type: 'boolean',
438
- description: 'B2】匿名收件:系统生成 PR-XXXXX 代号代替真实姓名(卖家面单只见代号 + 地址)',
454
+ description: '[B2] Anonymous recipient: system generates PR-XXXXX alias instead of real name (seller label shows alias + address only)',
439
455
  },
440
456
  // B5 公益捐赠(按订单总额百分比,定额选项防机器人滥用)
441
457
  donation_pct: {
442
458
  type: 'number',
443
459
  enum: [0, 0.005, 0.01, 0.02, 0.05],
444
- description: 'B5】随单捐赠占订单金额的比例(0 / 0.5% / 1% / 2% / 5%)。捐赠金额另行计算并入 charity_fund,订单完成后落账。',
460
+ description: '[B5] Per-order donation pct (0 / 0.5 / 1 / 2 / 5). Computed separately + into charity_fund, posted on order complete.',
445
461
  },
446
462
  },
447
463
  required: ['api_key', 'product_id', 'shipping_address'],
@@ -449,41 +465,28 @@ Missing any deadline auto-judges fault against the responsible party and trigger
449
465
  },
450
466
  {
451
467
  name: 'webaz_update_order',
452
- description: `STATUS TRANSITIONS on an order (accept / ship / pickup / deliver / confirm / dispute) — NOT for editing order content (price/quantity/address are immutable after creation).
468
+ // was ~927 chars, now ~430 chars
469
+ description: `STATUS TRANSITIONS on an order — NOT for editing order content (price/qty/address immutable after creation). Each role can only perform their own actions.
453
470
 
454
- USE THIS to advance an order through its lifecycle. Each role can only perform their own actions (see action list).
471
+ - **Seller**: accept (24h after payment) | ship (needs tracking, within handling time)
472
+ - **Logistics**: pickup (48h after ship) | transit | deliver (needs proof description)
473
+ - **Buyer**: confirm (→ fund settlement) | dispute (needs reason; freezes funds → arbitration)
455
474
 
456
- Seller actions:
457
- - accept: accept order (within 24h of payment)
458
- - ship: confirm dispatch (needs tracking number, within promised handling time)
459
-
460
- Logistics actions:
461
- - pickup: confirm parcel pickup (within 48h of ship)
462
- - transit: update to in-transit
463
- - deliver: confirm delivery (needs delivery proof description)
464
-
465
- Buyer actions:
466
- - confirm: confirm receipt → triggers fund settlement
467
- - dispute: raise dispute (needs reason; freezes funds pending arbitration)
468
-
469
- If a deadline is missed, protocol auto-marks that party as in default.
470
-
471
- ──
472
- 中文:更新订单状态 — 角色专属 action(卖家 accept/ship · 物流 pickup/transit/deliver · 买家 confirm/dispute)。截止超时自动判违约。`,
475
+ Missing deadline → protocol auto-marks party in default.`,
473
476
  inputSchema: {
474
477
  type: 'object',
475
478
  properties: {
476
- api_key: { type: 'string', description: '操作者的 api_key' },
477
- order_id: { type: 'string', description: '订单 ID' },
479
+ api_key: { type: 'string', description: "Operator's api_key" },
480
+ order_id: { type: 'string', description: 'Order ID' },
478
481
  action: {
479
482
  type: 'string',
480
483
  enum: ['accept', 'ship', 'pickup', 'transit', 'deliver', 'confirm', 'dispute'],
481
- description: '要执行的操作',
484
+ description: 'Action to execute',
482
485
  },
483
- notes: { type: 'string', description: '操作说明(如物流单号、争议原因等)' },
486
+ notes: { type: 'string', description: 'Action note (e.g. tracking number, dispute reason)' },
484
487
  evidence_description: {
485
488
  type: 'string',
486
- description: '证据描述(发货/揽收/投递时建议提供,争议时必须提供)',
489
+ description: 'Evidence description (recommended for ship/pickup/deliver; required for dispute)',
487
490
  },
488
491
  },
489
492
  required: ['api_key', 'order_id', 'action'],
@@ -491,43 +494,37 @@ If a deadline is missed, protocol auto-marks that party as in default.
491
494
  },
492
495
  {
493
496
  name: 'webaz_get_status',
494
- description: `Query order status, full history, and current responsible party.
495
- Requires api_key of an order participant (buyer / seller / logistics may all query).
496
- Returns: current status, status history (who did what when), next responsible actor, deadline.
497
-
498
- ──
499
- 中文:查订单状态 + 历史 + 当前责任方 + 截止时间。任一参与方可查。`,
497
+ // was ~286 chars, now ~200 chars
498
+ description: `Query order status + full history + current responsible party + deadline. Requires api_key of order participant (buyer/seller/logistics all OK). Returns: status / status_history (who did what when) / next_actor / deadline.`,
500
499
  inputSchema: {
501
500
  type: 'object',
502
501
  properties: {
503
- api_key: { type: 'string', description: '查询者的 api_key' },
504
- order_id: { type: 'string', description: '订单 ID' },
502
+ api_key: { type: 'string', description: "Querier's api_key" },
503
+ order_id: { type: 'string', description: 'Order ID' },
505
504
  },
506
505
  required: ['api_key', 'order_id'],
507
506
  },
508
507
  },
509
508
  {
510
509
  name: 'webaz_wallet',
511
- description: `Wallet READ-ONLY query (balance + earnings stats + deposit/withdrawal/income history).
510
+ // was ~788 chars, now ~440 chars
511
+ description: `Wallet **READ-ONLY** query (balance / earnings / deposit/withdrawal/income history).
512
512
 
513
- ⚠️ Iron-Rule (must read before use): actual withdrawals / deposits / whitelist management require Passkey + email OTP via PWA Web only. This tool CANNOT move money — only query state. If user asks "send/withdraw/deposit WAZ", do NOT promise it via MCP; instead direct them to PWA Web.
513
+ ⚠️ **Iron-Rule**: actual withdrawals / deposits / whitelist mgmt need **PWA Web + Passkey + email OTP**. This tool CANNOT move money — only query. User asks "send/withdraw/deposit WAZ"? Do NOT promise via MCP direct to PWA Web.
514
514
 
515
515
  Actions:
516
- - view available balance + staked + in-escrow + total earnings + reputation tier (default)
517
- - deposits last 10 on-chain deposit records (tx_hash / amount / block_number)
518
- - withdrawals last 10 withdrawal requests (with status / tx_hash)
519
- - income income breakdown: referral L1/L2/L3 + binary PV matching + sales net
520
-
521
- ──
522
- 中文:钱包查询(余额/收益/充提历史)。仅查询用,实际充提需 PWA Web + Passkey + 邮件 OTP,agent 不可绕过。`,
516
+ - view (default) — balance + staked + in-escrow + earnings + reputation tier
517
+ - depositslast 10 on-chain (tx_hash / amount / block)
518
+ - withdrawalslast 10 (status / tx_hash)
519
+ - income breakdown: referral L1/L2/L3 + binary PV matching + sales net`,
523
520
  inputSchema: {
524
521
  type: 'object',
525
522
  properties: {
526
- api_key: { type: 'string', description: '你的 api_key' },
523
+ api_key: { type: 'string', description: 'Your api_key' },
527
524
  action: {
528
525
  type: 'string',
529
526
  enum: ['view', 'deposits', 'withdrawals', 'income'],
530
- description: '操作类型(缺省 = view',
527
+ description: 'Action type (default: view)',
531
528
  },
532
529
  },
533
530
  required: ['api_key'],
@@ -535,255 +532,185 @@ Actions:
535
532
  },
536
533
  {
537
534
  name: 'webaz_notifications',
538
- description: `Query user notifications (L2-6 notification system).
539
- Agents should poll this periodically to check for pending order events.
540
- Every status change (new order / ship / dispute / etc.) notifies relevant participants.
541
-
542
- ⚠️ Scope: 此工具只查 L2-6 system notifications。不含 / Does NOT include:
543
- - chat unread(私信)→ 用 webaz_chat action=list
544
- - announcements unread(管理员公告)→ 暂无 MCP 工具(PWA #me/announcements)
545
- - feedback replies unread(用户反馈回复)→ 暂无 MCP 工具
546
- PWA 顶部红点是 4 项合计;此工具仅返回第 1 项 → 数字可能 < PWA 显示。
547
- PWA top badge aggregates all 4; this returns only 1 → may be < PWA shows.
535
+ // was ~608 chars, now ~330 chars
536
+ description: `Query user notifications (L2-6 system). Agents should poll periodically for pending order events (new order / ship / dispute → notifies relevant participants).
548
537
 
549
- ──
550
- 中文:查通知 — agent 定期调用检查待处理事件(新订单/发货/争议等会通知所有相关方)。`,
538
+ ⚠️ **Scope**: only L2-6 system notifications. Does NOT include: chat unread (use webaz_chat list) | announcements | feedback replies. PWA top badge aggregates 4; this returns 1 → may be **<** PWA shows.`,
551
539
  inputSchema: {
552
540
  type: 'object',
553
541
  properties: {
554
- api_key: { type: 'string', description: '你的 api_key' },
555
- unread: { type: 'boolean', description: '只返回未读通知(默认 false' },
556
- mark_read: { type: 'boolean', description: '调用后自动标为已读(默认 false' },
542
+ api_key: { type: 'string', description: 'Your api_key' },
543
+ unread: { type: 'boolean', description: 'Return only unread (default false)' },
544
+ mark_read: { type: 'boolean', description: 'Auto-mark read after call (default false)' },
557
545
  },
558
546
  required: ['api_key'],
559
547
  },
560
548
  },
561
549
  {
562
550
  name: 'webaz_dispute',
563
- description: `Manage ORDER-DELIVERY dispute lifecycle (L3 dispute system, central arbitrator).
564
-
565
- ⚠️ Different from webaz_claim_verify:
566
- - webaz_dispute = order delivery problem (didn't arrive / wrong / damaged in transit / seller fraud) → central arbitrator + 120h ruling
567
- - webaz_claim_verify = challenge a product CLAIM (brand / spec / ship time) → 3 crowd verifiers vote
568
- Pick based on the actual problem: delivery/receiving = dispute; marketing-claim accuracy = claim_verify.
569
-
570
- When buyer claims item-not-as-described / damaged / seller fraud, first raise dispute via webaz_update_order action=dispute,
571
- then use this tool for follow-ups.
572
-
573
- Protocol guarantees (no human intervention):
574
- - Respondent has 48h to submit rebuttal evidence, else protocol auto-judges in initiator's favor
575
- - Arbitrator has 120h to issue ruling, else protocol defaults to refund-buyer
576
- - Once executed, ruling fund movement is instant and irreversible
551
+ // was ~2277 chars, now ~900 chars
552
+ description: `Manage ORDER-DELIVERY dispute lifecycle (L3, central arbitrator). For order delivery problems (not arrived / wrong / damaged / seller fraud). **NOT for challenging product marketing claims → use webaz_claim_verify.** Quick rule: did buyer receive item? Yes + item-itself issue → claim_verify. No / damaged-transit → dispute. Initial raise via webaz_update_order action=dispute, then this tool for follow-ups.
577
553
 
578
554
  Actions:
579
- - view: view dispute details (any participant)
580
- - list_open: list all pending disputes (arbitrators only)
581
- - respond: respondent submits rebuttal evidence (before 48h deadline)
582
- - add_evidence: any participant (incl. logistics) submits supplementary evidence (Wave 3)
583
- - arbitrate: arbitrator issues ruling + executes fund disposition (must be assigned arbitrator)
555
+ - view dispute details (any participant)
556
+ - list_open pending disputes (arbitrators only)
557
+ - respond respondent rebuttal (before 48h deadline)
558
+ - add_evidence any participant supplements
559
+ - arbitrate ruling + fund disposition (assigned arbitrator only)
584
560
 
585
- Ruling options (when arbitrate):
586
- - refund_buyer: full refund to buyer + partial stake forfeit from seller
587
- - release_seller: release funds to seller (seller wins)
588
- - partial_refund: partial refund (needs refund_amount); if third-party fault, set liable_party (user_id) → seller settled full, compensation deducted from liable party
589
- - liability_split: distributed liability (Wave 3) — needs liability_parties: [{user_id, amount}] for proportional stake deductions
561
+ Ruling options: refund_buyer | release_seller | partial_refund (needs refund_amount; optional liable_party → 3rd-party fault, seller settled full + deducted from liable) | liability_split (needs liability_parties[]={user_id,amount}).
590
562
 
591
- ─────────────────────
592
- ⚠️ Iron-Rule boundary (spec §4): arbitrate is a protocol iron-rule node requiring arbitrator to complete Passkey re-confirmation via PWA Web UI.
593
- Direct agent calls return 412 HUMAN_PRESENCE_REQUIRED — DO NOT retry; instead, guide the user to the browser.
594
- view / list_open / respond / add_evidence can be agent-proxied; only arbitrate needs human.
563
+ Protocol auto-judges (no human): respondent silent 48h → favor initiator; arbitrator silent 120h → refund_buyer. Executed rulings are instant + irreversible.
595
564
 
596
- ──
597
- 中文:管理争议(L3)。Actions: view / list_open / respond / add_evidence (agent 可代) · arbitrate (需 PWA + Passkey 人工)。被诉方 48h 反驳,仲裁员 120h 裁定,超时自动判。`,
565
+ ⚠️ **Iron-Rule (spec §4)**: \`arbitrate\` needs PWA + Passkey real-human re-confirm. Direct agent call returns 412 HUMAN_PRESENCE_REQUIRED — **do NOT retry**, guide user to browser. view / list_open / respond / add_evidence are agent-proxyable.`,
598
566
  inputSchema: {
599
567
  type: 'object',
600
568
  properties: {
601
- api_key: { type: 'string', description: '操作者的 api_key' },
569
+ api_key: { type: 'string', description: "Operator's api_key" },
602
570
  action: {
603
571
  type: 'string',
604
572
  enum: ['view', 'list_open', 'respond', 'add_evidence', 'arbitrate'],
605
- description: '要执行的操作',
573
+ description: 'Action to execute',
606
574
  },
607
- dispute_id: { type: 'string', description: '争议 IDrespond/add_evidence/arbitrate 时必填,view 时与 order_id 二选一)' },
608
- order_id: { type: 'string', description: '订单 ID(view 时可替代 dispute_id' },
609
- notes: { type: 'string', description: '回应说明 / 反驳理由(respond 时填写)' },
610
- evidence_description: { type: 'string', description: '证据描述(respond/add_evidence 时填写)' },
575
+ dispute_id: { type: 'string', description: 'Dispute ID (required for respond/add_evidence/arbitrate; for view, dispute_id OR order_id)' },
576
+ order_id: { type: 'string', description: 'Order ID (alternative to dispute_id for view)' },
577
+ notes: { type: 'string', description: 'Response / rebuttal note (for respond)' },
578
+ evidence_description: { type: 'string', description: 'Evidence description (for respond/add_evidence)' },
611
579
  ruling: {
612
580
  type: 'string',
613
581
  enum: ['refund_buyer', 'release_seller', 'partial_refund', 'liability_split'],
614
- description: '裁定结果(arbitrate 时必填)',
582
+ description: 'Ruling (required for arbitrate)',
615
583
  },
616
- refund_amount: { type: 'number', description: '部分退款金额,仅 ruling=partial_refund 时使用' },
617
- liable_party: { type: 'string', description: '第三方责任方 user_idpartial_refund 时可选):指定后赔偿金从该方扣除,卖家全额结算' },
584
+ refund_amount: { type: 'number', description: 'Partial refund amount (only when ruling=partial_refund)' },
585
+ liable_party: { type: 'string', description: '3rd-party liable user_id (optional for partial_refund): refund deducted from this party, seller settled in full' },
618
586
  liability_parties: {
619
587
  type: 'array',
620
- description: '责任分配数组(liability_split 时必填),每项 { user_id: string, amount: number }',
588
+ description: 'Liability allocation array (required for liability_split); each item { user_id, amount }',
621
589
  items: {
622
590
  type: 'object',
623
591
  properties: {
624
- user_id: { type: 'string', description: '责任方 user_id' },
625
- amount: { type: 'number', description: '该责任方需承担的金额(WAZ' },
592
+ user_id: { type: 'string', description: 'Liable user_id' },
593
+ amount: { type: 'number', description: 'Amount this party owes (WAZ)' },
626
594
  },
627
595
  required: ['user_id', 'amount'],
628
596
  },
629
597
  },
630
- ruling_reason: { type: 'string', description: '裁定理由(arbitrate 时必填,将永久记录在链上)' },
598
+ ruling_reason: { type: 'string', description: 'Ruling reason (required for arbitrate; permanently recorded on-chain)' },
631
599
  },
632
600
  required: ['api_key', 'action'],
633
601
  },
634
602
  },
635
603
  {
636
604
  name: 'webaz_claim_verify',
637
- description: `Crowd-sourced PRODUCT-CLAIM verification challenge seller's marketing claims (brand / spec / ship time / authenticity); 3 eligible verifiers reach consensus by vote.
638
-
639
- ⚠️ Different from webaz_dispute:
640
- - webaz_claim_verify = challenge a CLAIM about the product itself ("seller said 24h ship but didn't" / "said brand new but used")
641
- - webaz_dispute = order-delivery problem (didn't arrive / arrived broken / wrong item) → central arbitrator
642
- If unsure: did the buyer GET the item? If yes + problem with item itself → claim_verify. If no/damaged in transit → dispute.
605
+ // was ~2917 chars, now ~1100 chars
606
+ description: `Crowd-sourced PRODUCT-CLAIM verification — challenge seller's marketing claims (brand / spec / ship time / authenticity). 3 eligible verifiers vote → consensus.
643
607
 
644
- When to use:
645
- - Buyer: suspects a seller's product claim (e.g. "brand new sealed", "ships within 24h") → wants decentralized verification
646
- - Seller: defends against an opened verification by submitting counter-evidence → extends task by 24h
647
- - Verifier: browses open tasks, votes on eligible ones (pass/fail/no_fault/abstain), settles on 3rd vote
608
+ **vs webaz_dispute**: dispute = delivery problem (not arrived / damaged / wrong item, central arbitrator). claim_verify = item-itself / claim-accuracy ("said brand new but used", "said 24h ship but didn't"). Quick test: did buyer receive? Yes + item issue → claim_verify; No / transit damage → dispute.
648
609
 
649
610
  Actions:
650
611
  [Buyer]
651
- - create open a verification on your own order's claim (locks 10 WAZ stake; order must be paid/delivered, NOT completed; settles when 3 votes collected)
652
- - view task details (visible to participants + voters + eligible verifiers)
653
- - mine all my tasks (buyer + seller + verifier perspectives)
654
-
612
+ - create open verification (locks 10 WAZ; order must be paid/delivered, NOT completed; settles on 3rd vote)
613
+ - view task details (visible to participants + voters + eligible verifiers)
614
+ - mine all my tasks (buyer/seller/verifier perspectives)
655
615
  [Seller]
656
- - submit_seller_evidence submit rebuttal → +24h extension, task stays open
657
-
658
- [Verifier gated by 7-condition eligibility, NOT just read-only]
659
- - available list open tasks I can take (REQUIRES eligibility: age≥60d / email verified / ≥20 completed orders / 0 arbitration losses / never suspended / wallet ≥200 WAZ / reputation ≥110)
660
- - vote vote on a task (pass / fail / no_fault / abstain)
661
- pass = seller's claim is true / product OK
662
- fail = seller's claim is false / product mismatch
663
- no_fault = neither party clearly at fault (dispute has merit but inconclusive)
664
- abstain = "not my expertise, skipping" — not counted in 3-vote consensus, doesn't affect accuracy (V3 right-to-decline)
665
-
616
+ - submit_seller_evidence rebuttal → +24h extension
617
+ [Verifier]
618
+ - available list takeable tasks (eligibility: age≥60d / email verified / ≥20 completed orders / 0 arbitration losses / never suspended / wallet ≥200 WAZ / reputation ≥110)
619
+ - vote pass (claim true) | fail (claim false) | no_fault (inconclusive) | abstain (not my expertise not counted, no accuracy impact)
666
620
  [Become Verifier]
667
- - eligibility check my qualification status (reputation signals)
668
- - verifier_status my quota / tier / stake
669
- - apply apply to verifier whitelist (needs reputation + stake lock)
670
- - withdraw_application withdraw application, refund stake
671
- - appeal appeal a suspension (only when suspended)
672
-
673
- ─────────────────────
674
- ⚠️ Iron-Rule boundary (spec §4): vote is a protocol iron-rule node requiring verifier to complete Passkey re-confirmation via PWA Web UI.
675
- Direct agent calls to vote return 412 HUMAN_PRESENCE_REQUIRED — DO NOT retry; instead, guide the user to the browser.
676
- Other actions (create / view / mine / available / eligibility / apply / appeal etc.) can be agent-proxied; only vote needs human.
621
+ - eligibility / verifier_status / apply (needs stake) / withdraw_application / appeal (only when suspended)
677
622
 
678
- ──
679
- 中文:众包索赔验证 — 3 verifier 共识投票判定。买家创建、卖家反证、verifier 投票。仅 vote 需 PWA + Passkey 人工,其他 actions agent 可代。`,
623
+ ⚠️ **Iron-Rule (spec §4)**: \`vote\` needs PWA + Passkey real-human re-confirm. Direct agent call returns 412 HUMAN_PRESENCE_REQUIRED — **do NOT retry**, guide user to browser. All other actions agent-proxyable.`,
680
624
  inputSchema: {
681
625
  type: 'object',
682
626
  properties: {
683
- api_key: { type: 'string', description: '你的 api_key' },
627
+ api_key: { type: 'string', description: 'Your api_key' },
684
628
  action: {
685
629
  type: 'string',
686
630
  enum: ['create', 'view', 'mine', 'submit_seller_evidence', 'available', 'vote', 'eligibility', 'verifier_status', 'apply', 'withdraw_application', 'appeal'],
687
- description: '要执行的操作',
631
+ description: 'Action to execute',
688
632
  },
689
633
  // create
690
- order_id: { type: 'string', description: '订单 IDcreate 时必填)。订单状态须在 paid/deliveredcompleted 终态不可发起)' },
634
+ order_id: { type: 'string', description: 'Order ID (required for create). Order status must be paid/delivered (cannot create on completed)' },
691
635
  claim_target: {
692
636
  type: 'string',
693
637
  enum: ['price', 'commission', 'protection', 'return', 'warranty', 'handling', 'other'],
694
- description: '声明对象(create 时必填)。7 类: price(价格争议)/ commission(佣金)/ protection(买家保护)/ return(退货)/ warranty(保修)/ handling(履约时效)/ other',
638
+ description: 'Claim target (required for create). 7 types: price / commission / protection / return / warranty / handling / other',
695
639
  },
696
- claim_text: { type: 'string', description: '声明文本 6-500 字(create 时必填)。create 会锁定 10 WAZ spam(无责败诉退回)' },
697
- evidence_uri: { type: 'string', description: '证据 URIcreate/vote/submit_seller_evidence 可选;buyer 自带 / verifier 附证据 / seller 反驳证据)' },
640
+ claim_text: { type: 'string', description: 'Claim text 6-500 chars (required for create). Locks 10 WAZ anti-spam (refunded if no fault)' },
641
+ evidence_uri: { type: 'string', description: 'Evidence URI (optional for create/vote/submit_seller_evidence; buyer/verifier/seller respective evidence)' },
698
642
  // view / vote / submit_seller_evidence
699
- task_id: { type: 'string', description: '任务 ID(view / vote / submit_seller_evidence 时必填)' },
643
+ task_id: { type: 'string', description: 'Task ID (required for view/vote/submit_seller_evidence)' },
700
644
  // vote
701
- vote: { type: 'string', enum: ['pass', 'fail', 'no_fault', 'abstain'], description: 'vote 时必填;abstain = 不熟悉弃投(V3' },
702
- note: { type: 'string', description: '投票说明(vote 可选,≤500 字)' },
645
+ vote: { type: 'string', enum: ['pass', 'fail', 'no_fault', 'abstain'], description: 'Required for vote; abstain = not my expertise (V3 right-to-decline)' },
646
+ note: { type: 'string', description: 'Vote note (optional for vote, 500 chars)' },
703
647
  // appeal
704
- reason: { type: 'string', description: '申诉理由(appeal 时必填,≤500 字)' },
648
+ reason: { type: 'string', description: 'Appeal reason (required for appeal, 500 chars)' },
705
649
  },
706
650
  required: ['api_key', 'action'],
707
651
  },
708
652
  },
709
653
  {
710
654
  name: 'webaz_skill',
711
- description: `L4-4 Skill marketplace sellers publish reusable seller-side BEHAVIOUR configs; buyer Agents subscribe with one click.
655
+ // was ~2251 chars, now ~920 chars
656
+ description: `L4-4 Skill marketplace — sellers publish reusable seller-side BEHAVIOUR configs; buyer Agents subscribe one-click.
712
657
 
713
- USE THIS when:
714
- - seller wants to install reusable selling behavior (auto-accept / catalog-sync / price-haggling / etc.), OR
715
- - buyer agent wants to subscribe to seller's behaviour to enable priority discovery / auto-deal flows.
658
+ **NOT** a product search (use webaz_search). **NOT** a knowledge/content market (use webaz_skill_market — totally separate, independent revenue flow).
716
659
 
717
- NOT a product search for "find me X" use webaz_search.
718
- NOT a KNOWLEDGE-content marketplace — for buying/selling templates / prompts / guides / checklists use webaz_skill_market (totally separate system, independent revenue flow).
660
+ ⚠️ **Skill executable code distribution**. 5 typed kinds only, each accepts **structured config params** (numbers/enums/amounts). NO path for Agent to download/run arbitrary 3rd-party code. Subscribing = flag + data binding, NOT plugin install. Web2 "plugin marketplace" risk model does NOT apply.
719
661
 
720
- ⚠️ Important — Skill is NOT executable code distribution. There are exactly 5 typed Skill kinds (below), each accepts only **structured config parameters** (numbers / enums / amounts). There is NO path for an Agent to download and run arbitrary third-party code via this marketplace. Subscribing = setting a flag + data binding, not installing a plugin. (Common Web2 "plugin marketplace" risk model does NOT apply here.)
662
+ Cold-start mechanism: Amazon/Shopify sellers integrate zero-cost; buyer agents auto-discover subscribed sellers with priority; publisher earns referral commission on sale.
721
663
 
722
- Skill is WebAZ's cold-start mechanism: existing Amazon/Shopify sellers integrate with zero cost,
723
- buyer agents subscribe and auto-discover those sellers' products with priority; on sale, the Skill publisher earns referral commission.
664
+ Skill types (typed, not free-form):
665
+ - catalog_sync sync external store subscribers see priority
666
+ - auto_accept auto-accept orders (config: min/max_amount, max_daily_orders)
667
+ - price_negotiation agent-side haggling (config: max_discount_pct, min_quantity)
668
+ - quality_guarantee extra stake compensation (config: guarantee_amount, coverage_days)
669
+ - instant_ship guarantee 24h dispatch (config: ship_within_hours)
724
670
 
725
- Skill types (typed, NOT free-form code):
726
- - catalog_sync sync external store (Amazon/Shopify/custom) into WebAZ search → subscribers see priority
727
- - auto_accept auto-accept incoming orders, no wait (config: min_amount, max_amount, max_daily_orders)
728
- - price_negotiation allow Agent-side haggling within limits (config: max_discount_pct, min_quantity)
729
- - quality_guarantee extra stake for issue compensation (config: guarantee_amount, coverage_days)
730
- - instant_ship guarantee 24h dispatch (config: ship_within_hours)
731
-
732
- Actions:
733
- - list browse Skill marketplace (no auth)
734
- - publish publish new Skill (sellers only)
735
- - subscribe subscribe to a Skill (buyer perks)
736
- - unsubscribe cancel subscription
737
- - my_skills my published Skills (seller view)
738
- - my_subs my subscribed Skills (buyer view)
739
-
740
- ──
741
- 中文:Skill 市场 — 卖家发布 agent 能力插件(catalog_sync / auto_accept / price_negotiation / quality_guarantee / instant_ship),买家 agent 订阅。Actions: list / publish / subscribe / unsubscribe / my_skills / my_subs。`,
671
+ Actions: list (no auth) | publish (seller) | subscribe / unsubscribe (buyer) | my_skills | my_subs.`,
742
672
  inputSchema: {
743
673
  type: 'object',
744
674
  properties: {
745
- api_key: { type: 'string', description: '你的 api_keylist 时可省略)' },
675
+ api_key: { type: 'string', description: 'Your api_key (omit for list)' },
746
676
  action: {
747
677
  type: 'string',
748
678
  enum: ['list', 'publish', 'subscribe', 'unsubscribe', 'my_skills', 'my_subs'],
749
- description: '要执行的操作',
679
+ description: 'Action to execute',
750
680
  },
751
681
  // list 过滤参数
752
682
  skill_type: {
753
683
  type: 'string',
754
684
  enum: ['catalog_sync', 'auto_accept', 'price_negotiation', 'quality_guarantee', 'instant_ship'],
755
- description: '过滤 Skill 类型(list 时可选)',
685
+ description: 'Filter Skill type (optional for list)',
756
686
  },
757
- query: { type: 'string', description: '关键词搜索(list 时可选)' },
687
+ query: { type: 'string', description: 'Keyword search (optional for list)' },
758
688
  // publish 参数
759
- name: { type: 'string', description: 'Skill 名称(publish 时必填)' },
760
- description: { type: 'string', description: 'Skill 详细描述(publish 时必填)' },
761
- category: { type: 'string', description: '分类(publish 时可选)' },
689
+ name: { type: 'string', description: 'Skill name (required for publish)' },
690
+ description: { type: 'string', description: 'Skill description (required for publish)' },
691
+ category: { type: 'string', description: 'Category (optional for publish)' },
762
692
  config: {
763
693
  type: 'object',
764
- description: 'Skill 配置(publish 时可选,如 auto_accept 需填 max_daily_orders',
694
+ description: 'Skill config (optional for publish; e.g. auto_accept needs max_daily_orders)',
765
695
  },
766
696
  // subscribe 参数
767
- skill_id: { type: 'string', description: 'Skill IDsubscribe/unsubscribe 时必填)' },
697
+ skill_id: { type: 'string', description: 'Skill ID (required for subscribe/unsubscribe)' },
768
698
  },
769
699
  required: ['action'],
770
700
  },
771
701
  },
772
702
  {
773
703
  name: 'webaz_mykey',
774
- description: `Account RECOVERY check confirm account existence by handle + permanent_code when user has lost their api_key but still remembers handle + 6-char recovery code from registration. Returns redacted api_key hint only — full api_key disclosure requires PWA + Passkey verification (Iron-Rule).
704
+ // was ~909 chars, now ~480 chars
705
+ description: `Account RECOVERY check — confirm account existence by handle + 6-char permanent_code (from registration). Returns redacted api_key_hint only.
775
706
 
776
- USE THIS ONLY when user has lost api_key and provides handle + permanent_code. NOT for "show me my api_key" (you already have it if you're authenticated). NOT for looking up other users (use webaz_profile).
707
+ ⚠️ **Iron-Rule**: full api_key disclosure requires **PWA + Passkey** verification this MCP tool only returns hint + PWA URL, never full key.
777
708
 
778
- Rate-limited: 5 attempts per handle per hour. Excessive failures lock the handle for 1 hour.
709
+ USE THIS ONLY when user lost api_key + has handle + permanent_code. NOT for "show my api_key" (use the one you have). NOT for looking up others (use webaz_profile).
779
710
 
780
- Returns:
781
- - found: boolean
782
- - api_key_hint (e.g. "key_7d3d***faa7b") — confirms which account, never the full key
783
- - full_api_key_recovery — instructions to use PWA for the real recovery
711
+ Rate-limited: 5/handle/hour; excessive → 1h lock.
784
712
 
785
- ──
786
- 中文:handle + permanent_code 双因素确认账户存在,仅返回 redact 过的 api_key_hint。完整 api_key 必须经 PWA + Passkey 二次验证(Iron-Rule)。同 handle 每小时最多 5 次。`,
713
+ Returns: found / api_key_hint (e.g. "key_7d3d***faa7b") / full_api_key_recovery URL.`,
787
714
  inputSchema: {
788
715
  type: 'object',
789
716
  properties: {
@@ -795,44 +722,36 @@ Returns:
795
722
  },
796
723
  {
797
724
  name: 'webaz_profile',
798
- description: `View your own profile / manage roles, AND view any user's public profile + content streams (个人主页内容流).
725
+ // was ~1076 chars, now ~570 chars
726
+ description: `View own profile / manage roles, AND view any user's public profile + content streams.
799
727
 
800
- USE THIS when user wants info about a SPECIFIC PERSON (by usr_xxx / permanent code / @handle / name),
801
- OR wants to see someone's listings / notes / activity stream. NOT for product keyword search — use webaz_search.
728
+ USE THIS for info about a SPECIFIC PERSON (by usr_xxx / permanent code / @handle / name), OR to see someone's listings / notes / activity stream. NOT for product keyword search — use webaz_search.
802
729
 
803
730
  Self actions (need api_key):
804
- - view show your profile & wallet & api_key hint
805
- - add_role add a new role
806
- - switch_role switch active role (one account can hold multiple roles)
731
+ - view (profile + wallet + api_key hint) | add_role | switch_role
807
732
 
808
733
  Public-profile actions:
809
- - view_user another user's public profile (user_id = usr_xxx / permanent_code / @handle; needs api_key)
810
- - feed a user's content stream (user_id + feed). feed options:
811
- secondhand | auctions | reviews | products | shares | reputation | pv | liked
812
- (secondhand/auctions/reviews/products/shares/reputation are public;
813
- pv needs api_key; liked is owner-only and needs your own api_key)
814
-
815
- ──
816
- 中文:看自己资料/管角色,也能看他人公开主页 + 内容流(二手/拍卖/测评/商品/笔记/信誉/PV/点赞)。Actions: view / add_role / switch_role / view_user / feed。`,
734
+ - view_user (user_id = usr_xxx / permanent_code / @handle; needs api_key)
735
+ - feed (user_id + feed): secondhand | auctions | reviews | products | shares | reputation (public) | pv (needs api_key) | liked (owner-only, needs your api_key)`,
817
736
  inputSchema: {
818
737
  type: 'object',
819
738
  properties: {
820
- api_key: { type: 'string', description: 'Your api_keyview/add_role/switch_role/view_user 必填;公开 feed 可省略)' },
739
+ api_key: { type: 'string', description: 'Your api_key (required for view/add_role/switch_role/view_user; optional for public feed)' },
821
740
  action: {
822
741
  type: 'string',
823
742
  enum: ['view', 'add_role', 'switch_role', 'view_user', 'feed'],
824
- description: 'view/add_role/switch_role = 自己;view_user/feed = 看他人主页/内容流',
743
+ description: 'view/add_role/switch_role = self; view_user/feed = other user profile/feed',
825
744
  },
826
745
  role: {
827
746
  type: 'string',
828
747
  enum: ['buyer', 'seller', 'logistics', 'arbitrator'],
829
748
  description: 'Role to add or switch to (required for add_role / switch_role)',
830
749
  },
831
- user_id: { type: 'string', description: '目标用户:usr_xxx / 永久码 / @handleview_user / feed 时必填)' },
750
+ user_id: { type: 'string', description: 'Target user: usr_xxx / permanent_code / @handle (required for view_user/feed)' },
832
751
  feed: {
833
752
  type: 'string',
834
753
  enum: ['secondhand', 'auctions', 'reviews', 'products', 'shares', 'reputation', 'pv', 'liked'],
835
- description: '内容流类型(feed 时必填)',
754
+ description: 'Feed type (required for feed)',
836
755
  },
837
756
  },
838
757
  required: ['action'],
@@ -840,18 +759,14 @@ Public-profile actions:
840
759
  },
841
760
  {
842
761
  name: 'webaz_revoke_key',
843
- description: `Initiate api_key revocation (NO REPLACEMENT — old key dies, no new one issued). Iron-Rule: actual revocation requires PWA + Passkey confirmation — MCP only registers the intent and returns the PWA URL where you finish the action.
844
-
845
- ⚠️ STRONG RECOMMENDATION: use webaz_rotate_key instead unless you intentionally want zero replacement (e.g. fully decommissioning the agent / device). Rotate = atomic swap (no access gap). Revoke = death + you re-register from scratch.
762
+ // was ~778 chars, now ~430 chars
763
+ description: `Initiate api_key revocation (**NO REPLACEMENT** — old key dies, no new issued).
846
764
 
847
- Use revoke (not rotate) when:
848
- - You are PERMANENTLY decommissioning this agent / device, OR
849
- - You want all access to die NOW with no fallback
765
+ ⚠️ **Iron-Rule**: actual revocation needs **PWA + Passkey** confirm. MCP only registers intent + returns PWA URL.
850
766
 
851
- After PWA confirmation, the old api_key returns 401 on all tools.
767
+ ⚠️ **STRONG REC**: use \`webaz_rotate_key\` instead unless you want zero replacement. Rotate = atomic swap (no access gap). Revoke = death + re-register.
852
768
 
853
- ──
854
- 中文:发起 api_key 吊销。Iron-Rule:真正吊销必须 PWA + Passkey 二次确认(agent 不能单方面执行不可逆操作)。MCP 仅登记意图,返回 PWA 确认 URL。`,
769
+ Use revoke when: PERMANENT decommission of agent/device, OR want access death NOW with no fallback. After PWA confirm: old key → 401 on all tools.`,
855
770
  inputSchema: {
856
771
  type: 'object',
857
772
  properties: {
@@ -863,12 +778,10 @@ After PWA confirmation, the old api_key returns 401 on all tools.
863
778
  },
864
779
  {
865
780
  name: 'webaz_rotate_key',
866
- description: `Initiate api_key rotation (invalidate old key + issue new one). Iron-Rule: requires PWA + Passkey confirmation. After PWA confirms, old key returns 401 and new key is shown once — store immediately.
867
-
868
- Safer than webaz_revoke_key because issuance is atomic with invalidation — no access gap.
781
+ // was ~372 chars, now ~260 chars
782
+ description: `Initiate api_key rotation (invalidate old + issue new). ⚠️ **Iron-Rule**: needs **PWA + Passkey** confirm. After PWA: old → 401; new shown ONCE — store immediately.
869
783
 
870
- ──
871
- 中文:发起 api_key 轮换(旧 key 失效 + 新 key 同时签发)。比 revoke 安全,原子操作无访问中断。需 PWA + Passkey。`,
784
+ Safer than \`webaz_revoke_key\` — atomic swap, no access gap.`,
872
785
  inputSchema: {
873
786
  type: 'object',
874
787
  properties: {
@@ -880,9 +793,11 @@ Safer than webaz_revoke_key because issuance is atomic with invalidation — no
880
793
  },
881
794
  {
882
795
  name: 'webaz_referral',
883
- description: `View your full referral status: 3-tier commission (推土机) team + earnings + invite links + binary PV matching (原子能) tree + tier progress + L1 share permission gate. Use this to know how to promote and what you have earned.
796
+ description: `View your referral status: 3-tier commission (推土机) team + earnings + invite links + binary PV matching (原子能) tree + tier progress + L1 share permission gate + **rewards_status (RFC-002 §3.5 opt-in state + pending escrow)**.
797
+
798
+ ⚠️ **Opt-in required (RFC-002)**: rewards default = off. \`rewards_status\` field returns 4-state {opted_in | never_activated | auto_downgraded | deactivated} + pending_escrow tally. Opted-out users still see attribution + tree, but commission held in escrow until activation via PWA #me.
884
799
 
885
- ⚠️ Commission structure involves multi-tier referral + binary pairing tree which may overlap with MLM legal definitions in many jurisdictions (see webaz_info.commission_model.compliance_notice). Agents acting on behalf of a human user MUST get the user's explicit consent before generating referral links or promoting on their behalf. Do NOT auto-recruit.`,
800
+ ⚠️ **MLM disclosure**: structure may overlap with MLM legal definitions (see webaz_info.commission_model.compliance_notice). Agent acting for human user **MUST get explicit consent** before generating referral links / promoting. Do NOT auto-recruit.`,
886
801
  inputSchema: {
887
802
  type: 'object',
888
803
  properties: {
@@ -893,9 +808,11 @@ Safer than webaz_revoke_key because issuance is atomic with invalidation — no
893
808
  },
894
809
  {
895
810
  name: 'webaz_share_link',
896
- description: `Generate a product share link with your referral attached. Open this in any social platform (TikTok / WeChat / Telegram). Whoever clicks and registers/buys will count toward your 3-tier commission (if you are verified buyer) and PV tree.
811
+ description: `Generate product share link with your referral attached. Open in any social platform (TikTok/WeChat/Telegram). Clicker registers/buys counts toward your 3-tier commission (if verified buyer) + PV tree.
812
+
813
+ ⚠️ **Opt-in required (RFC-002 §3.5)**: this is a valuation-layer action. Caller must have \`rewards_opted_in=1\` (builder-identity opt-in). Opted-out users get \`{error: 'rewards_opt_in_required', missing_requirements, next_steps}\` — direct user to PWA #me to apply.
897
814
 
898
- ⚠️ This tool builds the referral chain. Generating a link is taking an active promotion step in a multi-tier commission + binary pairing structure (see webaz_info.commission_model.compliance_notice — may overlap with MLM legal definitions). Agents acting for a human user MUST get explicit consent before calling this on their behalf. Do NOT auto-generate.`,
815
+ ⚠️ **MLM disclosure**: builds referral chain (multi-tier commission + binary pairing). Agent acting for human user **MUST get explicit consent**. Do NOT auto-generate. See webaz_info.commission_model.compliance_notice.`,
899
816
  inputSchema: {
900
817
  type: 'object',
901
818
  properties: {
@@ -912,17 +829,12 @@ Safer than webaz_revoke_key because issuance is atomic with invalidation — no
912
829
  },
913
830
  {
914
831
  name: 'webaz_blocklist',
915
- description: `Manage your blocklist of sellers/users. Blocked users' products are auto-hidden from your searches.
832
+ // was ~607 chars, now ~370 chars
833
+ description: `Manage blocklist of sellers/users. Blocked → auto-hidden from your search + can't follow them.
916
834
 
917
- Scope (元规则 #5 不偏袒 design):
918
- - ✓ Hides blocked user's products from YOUR search results
919
- - ✓ Prevents YOU from following them (webaz_follows respects this)
920
- - ✗ Does NOT prevent placing orders on their products (商品发布即承诺销售 — public listing = sales commitment)
921
- - ✗ Does NOT silence existing chat conversations (business context overrides)
922
- - ✗ Does NOT prevent NEW chat starts on shared order/rfq context
923
- - For active rejection: delist products, don't bid on RFQs, or cancel the order.
835
+ ⚠️ **Scope** (元规则 #5 不偏袒): ✓ hides from YOUR search ✓ prevents follow. ✗ Does NOT prevent placing orders on their products (商品发布即承诺销售) ✗ Does NOT silence existing chat (business context wins) ✗ Does NOT prevent new chat on shared order/rfq context. For active rejection: delist / don't bid / cancel order.
924
836
 
925
- Returns the action result.`,
837
+ Actions: list | block | unblock.`,
926
838
  inputSchema: {
927
839
  type: 'object',
928
840
  properties: {
@@ -949,18 +861,12 @@ Returns the action result.`,
949
861
  },
950
862
  {
951
863
  name: 'webaz_nearby',
952
- description: `Query anonymized nearby (~11km cell) purchase aggregation. k-anonymity ≥ 3 privacy guard. Or set/clear your coarse geo location (0.1° = 11km precision, never stores exact GPS).
864
+ // was ~831 chars, now ~430 chars
865
+ description: `Query anonymized nearby (~11km cell) purchase aggregation. **k-anonymity ≥3** privacy guard. Set/clear your coarse geo (0.1° precision, never exact GPS).
953
866
 
954
- USE THIS when user asks "what's popular/being bought near me / 我附近 / 同城" — geo-aggregated
955
- view, no specific keyword. NOT for "find product X" — use webaz_search. NOT for "items shippable
956
- to my address" — use webaz_search ship_to filter.
867
+ USE THIS for "what's popular near me / 我附近 / 同城" — geo-aggregated, no keyword. NOT for "find product X" (use webaz_search). NOT for "shippable to me" (use webaz_search ship_to).
957
868
 
958
- ⚠️ MCP query 需要先 set_location(否则返回 has_location: false 提示)
959
- PWA #nearby 有【全网 / 同城 / 周边 / 14 公里】 4 档 fallback,无 location 也能看全网视图 —
960
- 这是设计性差异(MCP agent 应明示要 location,PWA UI 友好降级)。
961
- ⚠️ MCP query needs set_location first (else returns has_location: false).
962
- PWA #nearby has 4-tier fallback (national/city/around/14km) showing global view without location —
963
- by design (MCP demands location; PWA degrades gracefully).`,
869
+ ⚠️ MCP \`query\` needs \`set_location\` first (else \`has_location: false\`). PWA #nearby has 4-tier fallback (national / city / around / 14km) — designed difference: MCP demands location, PWA degrades.`,
964
870
  inputSchema: {
965
871
  type: 'object',
966
872
  properties: {
@@ -974,13 +880,10 @@ to my address" — use webaz_search ship_to filter.
974
880
  },
975
881
  {
976
882
  name: 'webaz_default_address',
977
- description: `Read or set your default shipping address. Used to auto-filter unshippable products in search + fallback when webaz_rfq/place_order omits shipping_address.
883
+ // was ~370 chars, now ~230 chars
884
+ description: `Read or set default shipping address. Used by webaz_search unshippable filter + fallback for webaz_rfq/place_order if omitted.
978
885
 
979
- ⚠️ set 仅接受 2 个字段:text(自由格式地址字符串)+ region(可选;用于 unshippable 过滤)。
980
- 不接受 structured 字段(recipient/line1/city/country/phone 等)— 跟传统电商地址 API 不同,agent 必须自己拼接。
981
-
982
- ──
983
- 中文:读取/设置默认收货地址。set 需要 text 必填 + region 可选;不收 structured 字段。`,
886
+ ⚠️ \`set\` accepts only 2 fields: \`text\` (free-text address, ≤200 chars, required) + \`region\` (optional, for unshippable filter, ≤40 chars). NO structured fields (no recipient/line1/city/country/phone) — agent must concat itself.`,
984
887
  inputSchema: {
985
888
  type: 'object',
986
889
  properties: {
@@ -994,16 +897,14 @@ to my address" — use webaz_search ship_to filter.
994
897
  },
995
898
  {
996
899
  name: 'webaz_shareables',
997
- description: `Bind your EXTERNAL content (YouTube / TikTok / 小红书 / B站 / IG / Twitter posts) to a WebAZ product — turns your content into a referral-earning channel. WebAZ indexes only the URL, never the content bytes.
900
+ // was ~843 chars, now ~480 chars
901
+ description: `Bind your **EXISTING external content** (YouTube / TikTok / 小红书 / B站 / IG / Twitter) to a WebAZ product/anchor — turns your content into referral-earning channel. WebAZ indexes only URL, never content bytes.
998
902
 
999
- USE THIS when:
1000
- - creator/user wants to "anchor" their existing review/unboxing/recommendation video/post to a WebAZ product (or anchor) so future buyers clicking that content → registration / purchase counts toward THEIR referral commission, OR
1001
- - agent wants to look up "what external content is associated with this product / this anchor"
903
+ USE THIS when: creator anchors existing review/unboxing post → future buyers click → counts toward THEIR referral commission. OR agent looks up "what external content for this product/anchor".
1002
904
 
1003
- Differs from webaz_share_link (which generates a NEW short link for sharing) — shareables register your EXISTING content as the discovery surface.
905
+ ⚠️ Different from \`webaz_share_link\` (generates NEW short link) — shareables register EXISTING content as discovery surface.
1004
906
 
1005
- ──
1006
- 中文:把你在 YouTube/TikTok/小红书/B站/IG/Twitter 已发的内容(测评/开箱/推荐)锚定到 WebAZ 商品 —— 让你的外部内容变成赚 referral 佣金的入口。WebAZ 只锚 URL,不取内容。区别于 webaz_share_link(那个是生成新短链)。`,
907
+ Actions: list_mine | add (external_url + product/anchor) | delete | by_product | by_anchor.`,
1007
908
  inputSchema: {
1008
909
  type: 'object',
1009
910
  properties: {
@@ -1022,76 +923,63 @@ Differs from webaz_share_link (which generates a NEW short link for sharing) —
1022
923
  // ── P3 RFQ / bid / chat / auto_bid(MCP 通过 HTTP 调 PWA,复用所有校验+状态机)────
1023
924
  {
1024
925
  name: 'webaz_rfq',
1025
- description: `RFQ (Request-for-Quotation) — buyer posts demand, sellers bid within a time window.
926
+ // was ~1822 chars, now ~880 chars
927
+ description: `RFQ (Request-for-Quotation) — buyer posts demand, sellers bid within time window.
1026
928
 
1027
- USE THIS when buyer wants to POST a need (and have sellers come to them) typically because
1028
- webaz_search returned no good match, OR the buyer wants competing quotes (bulk / custom / unusual
1029
- spec / time-sensitive). NOT a search tool. For browsing existing listings use webaz_search.
929
+ USE THIS when buyer POSTS a need (no good search match / bulk / custom / time-sensitive / wants competing quotes). NOT a search tool — for browsing use webaz_search. For AUCTION (English forward on a listed item) use webaz_auction.
1030
930
 
1031
931
  Actions:
1032
- - create (buyer): publish RFQ; needs title/qty/max_price/category/urgency/award_mode
1033
- - mine (buyer): my RFQ list
1034
- - browse (seller): board view (filter by region/category/urgency/unbidded)
1035
- - detail: full detail (buyer sees all bids; seller sees only own)
1036
- - award (buyer): pick winner (pass bid_id for manual; omit for auto-lowest)
1037
- - cancel (buyer): cancel (only if no bid awarded; 30% deposit forfeited)
932
+ - create (buyer) publish RFQ (title/qty/max_price/category/urgency/award_mode)
933
+ - mine (buyer) my RFQ list
934
+ - browse (seller) board view (filter by region/category/urgency/unbidded)
935
+ - detail full detail (buyer sees all bids; seller sees only own)
936
+ - award (buyer) pick winner (bid_id for manual; omit = auto-lowest)
937
+ - cancel (buyer) only pre-award; 30% deposit forfeit to charity_fund
1038
938
 
1039
939
  Economics:
1040
- - Buyer deposit = clamp(0.1, 1) of (max_price × qty × 0.01) — i.e. 1% capped at 1 WAZ (anti-spam, NOT anti-fraud; real anti-fraud is 30% cancel penalty)
1041
- - No-max-price RFQ deposit = 0.1 WAZ flat
1042
- - Seller bid stake = max(0.5, price × qty × 0.05) 5% with floor 0.5 WAZ
1043
- - Cancel before award: 30% deposit forfeit to charity_fund
1044
- - Award winner → standard order lifecycle, BUT with snapshot_commission_rate = 0 (RFQ orders 0% commission — direct deal between buyer/seller, no promoter chain to compensate). Seller gets price minus protocol_fee (2%) and fund_base (1%); no L1/L2/L3 dilution.
1045
- - Seller bid stake (4.5+ WAZ) becomes bid_stake_held on the order; released to seller balance on successful complete; 50/50 split to buyer+sys_protocol on fault_seller (settleFault).
1046
- - Window defaults: now=15min / today=60min / flex=1440min(24h)
1047
-
1048
- Shipping address: if omitted, falls back to webaz_default_address (set via that tool first).
940
+ - Buyer deposit = clamp(0.1, 1) of max_price × qty × 1% (anti-spam). No-max-price = 0.1 WAZ flat.
941
+ - Seller bid stake = max(0.5, price × qty × 5%). Becomes bid_stake_held on award; released on complete; 50/50 split (buyer + sys_protocol) on fault_seller.
942
+ - Award standard order lifecycle BUT **snapshot_commission_rate = 0** (RFQ 0% commission, no L1/L2/L3 promoter dilution); seller gets price − protocol_fee 2% fund_base 1%.
943
+ - Window defaults: now=15min / today=60min / flex=24h.
1049
944
 
1050
- ──
1051
- 中文:求购单 RFQ。买家押金 1%(封顶 1 WAZ,仅防 spam);卖家 bid stake 5%(最少 0.5 WAZ);撤单扣 30% 入慈善池。`,
945
+ Shipping address falls back to webaz_default_address if omitted.`,
1052
946
  inputSchema: {
1053
947
  type: 'object',
1054
948
  properties: {
1055
- api_key: { type: 'string', description: '你的 api_key' },
949
+ api_key: { type: 'string', description: 'Your api_key' },
1056
950
  action: { type: 'string', enum: ['create', 'mine', 'browse', 'detail', 'award', 'cancel'] },
1057
951
  // create
1058
952
  title: { type: 'string' },
1059
953
  qty: { type: 'number' },
1060
- max_price: { type: 'number', description: 'WAZ 预算上限(可选;不填时 buyer 押金为 1 WAZ' },
954
+ max_price: { type: 'number', description: 'Max budget in WAZ (optional; if omitted, buyer deposit = 1 WAZ)' },
1061
955
  category: { type: 'string', enum: ['standard', 'general', 'highvalue', 'restricted'] },
1062
956
  urgency: { type: 'string', enum: ['now', 'today', 'flex'] },
1063
957
  award_mode: { type: 'string', enum: ['manual', 'first_match', 'time_window'] },
1064
958
  award_window_min: { type: 'number' },
1065
959
  notes: { type: 'string' },
1066
- shipping_address: { type: 'string', description: '可选;缺省取 buyer 默认地址' },
960
+ shipping_address: { type: 'string', description: 'Optional; falls back to buyer default address' },
1067
961
  // browse filters
1068
962
  region: { type: 'string' },
1069
963
  unbidded: { type: 'boolean' },
1070
964
  // detail/award/cancel
1071
965
  rfq_id: { type: 'string' },
1072
- bid_id: { type: 'string', description: 'award 时可选 不传则自动选当前最低价' },
966
+ bid_id: { type: 'string', description: 'Optional for award — if omitted, auto-pick current lowest bid' },
1073
967
  },
1074
968
  required: ['api_key', 'action'],
1075
969
  },
1076
970
  },
1077
971
  {
1078
972
  name: 'webaz_bid',
973
+ // was ~733 chars, now ~400 chars
1079
974
  description: `Bid on RFQs (seller-side, Request-for-Quotation).
1080
975
 
1081
- USE THIS ONLY for RFQ bidding (when a buyer posted demand via webaz_rfq and you want to quote). For AUCTION bidding (English forward auction on a listed item) use webaz_auction action=bid — they are separate systems with different economics (RFQ has bid stake; auction has min_increment + sniper extension).
1082
-
1083
- Actions:
1084
- - submit: new bid; needs rfq_id + price + qty_offered + fulfillment_type; optional eta_hours/note
1085
- - patch: edit price/ETA/fulfillment/note (only active; stake delta auto-settled)
1086
- - cancel: withdraw (only active; deposit released immediately)
1087
- - list_mine: full bid history
976
+ ⚠️ **ONLY for RFQ bidding** (buyer posted demand via webaz_rfq). For AUCTION (English forward on listed item) use \`webaz_auction action=bid\` — separate systems with different economics (RFQ = bid stake; auction = min_increment + sniper extension).
1088
977
 
1089
- ──
1090
- 中文:对 RFQ 报价(卖家)。Actions: submit / patch / cancel / list_mine。改价时 stake 自动结算差额。`,
978
+ Actions: submit (rfq_id + price + qty_offered + fulfillment_type; optional eta/note) | patch (active only, stake delta auto-settled) | cancel (active only, deposit released immediately) | list_mine.`,
1091
979
  inputSchema: {
1092
980
  type: 'object',
1093
981
  properties: {
1094
- api_key: { type: 'string', description: '卖家 api_key' },
982
+ api_key: { type: 'string', description: 'Seller api_key' },
1095
983
  action: { type: 'string', enum: ['submit', 'patch', 'cancel', 'list_mine'] },
1096
984
  rfq_id: { type: 'string' },
1097
985
  bid_id: { type: 'string' },
@@ -1100,42 +988,25 @@ Actions:
1100
988
  eta_hours: { type: 'number' },
1101
989
  fulfillment_type: { type: 'string', enum: ['instant_pickup', 'same_day', 'next_day', 'standard'] },
1102
990
  note: { type: 'string' },
1103
- offer_id: { type: 'string', description: '可选;引用已有 offer 商品' },
991
+ offer_id: { type: 'string', description: 'Optional; reference existing offer' },
1104
992
  },
1105
993
  required: ['api_key', 'action'],
1106
994
  },
1107
995
  },
1108
996
  {
1109
997
  name: 'webaz_chat',
1110
- description: `Relay buyer↔seller (or RFQ partner) MESSAGES — context-bound DM, no open DM. Only order / rfq / listing_qa contexts allowed.
998
+ // was ~1963 chars, now ~860 chars
999
+ description: `Relay buyer↔seller (or RFQ partner) MESSAGES — **context-bound DM**, NO open DM. Only \`order\` / \`rfq\` / \`listing_qa\` contexts.
1111
1000
 
1112
- USE THIS when the user wants to communicate with the OTHER PARTY of a trade (e.g. "ask seller about return", "tell buyer about shipping delay", "answer Q&A on my listing"). NOT a general LLM chat — every message attaches to an order/rfq/listing_qa context. If the user just wants to chat with YOU (the agent), don't call this tool.
1113
- Actions:
1114
- - start: open conversation — needs kind + context_id (for rfq, also recipient_id)
1115
- - list: my conversation list
1116
- - read: read messages (last 50; flag_reasons is array)
1117
- - send: send message (anti-scam regex; matches get flagged=true but still delivered; flag_reasons is array)
1118
- - mark_read: mark as read
1119
- - block: block this specific conversation (sets conv.status=blocked; ≠ webaz_blocklist which hides from search)
1001
+ USE THIS for trade communication ("ask seller about return", "tell buyer about delay", "answer listing Q&A"). NOT general LLM chat — every message attaches to context. User chatting with agent? Don't call this.
1120
1002
 
1121
- Anti-scam regex names (returned in flag_reasons array):
1122
- phone_cn (CN mobile 11-digit), wechat (微信/vx/wechat/weixin), alipay (支付宝/alipay),
1123
- qq (qq:digits), bank_card (16-19 consecutive digits), telegram (@handle/t.me/telegram),
1124
- external_url (any http(s) URL except localhost/webaz.app/webaz.io).
1003
+ Actions: start (kind + context_id; rfq needs recipient_id) | list | read (last 50, flag_reasons array) | send (anti-scam regex; matches flagged=true but still delivered) | mark_read | block (this conv only; ≠ webaz_blocklist which hides from search).
1125
1004
 
1126
- Rate limits (PWA-enforced):
1127
- - Short-term: 60 messages / minute / user
1128
- - AGENT_DAILY_CAP (reset at UTC midnight): new=30, trusted=100, quality=300, legend=1000
1129
- (returns 429 + error_code=AGENT_DAILY_CAP + cap + used + level fields)
1130
- 3 overruns/day → auto agent warning strike.
1005
+ ⚠️ **Anti-scam regex** (in flag_reasons[]): phone_cn (11-digit) / wechat (微信/vx/wechat) / alipay / qq / bank_card (16-19 digits) / telegram (@/t.me) / external_url (non-webaz HTTPS).
1131
1006
 
1132
- Behavior note: webaz_blocklist hides target from your search; per-conversation block (this tool's "block")
1133
- silences the specific conv. Existing conversations are NOT auto-silenced by webaz_blocklist
1134
- (business context overrides — block prevents future ad-hoc contact but keeps active deal channels open).
1007
+ Rate limits: 60/min/user short-term + AGENT_DAILY_CAP (UTC reset): new=30 / trusted=100 / quality=300 / legend=1000 (over 429 + error_code=AGENT_DAILY_CAP). 3 overruns/day → auto warning strike.
1135
1008
 
1136
- ──
1137
- 中文:上下文私聊 — 仅 order/rfq/listing_qa 三种场景可发起,无自由 DM。Actions: start / list / read / send / mark_read / block。
1138
- 反诈 regex 7 类 + 60/min rate limit。blocklist 不影响已建立 conversation(商业上下文优先)。`,
1009
+ webaz_blocklist hides from search but does NOT auto-silence existing convs (business context wins) — use this tool's \`block\` for per-conv silence.`,
1139
1010
  inputSchema: {
1140
1011
  type: 'object',
1141
1012
  properties: {
@@ -1145,60 +1016,45 @@ silences the specific conv. Existing conversations are NOT auto-silenced by weba
1145
1016
  context_id: { type: 'string' },
1146
1017
  recipient_id: { type: 'string' },
1147
1018
  conversation_id: { type: 'string' },
1148
- body: { type: 'string', description: 'send action 的消息正文 (≤ 2000 )' },
1019
+ body: { type: 'string', description: 'Message body for send action (≤2000 chars)' },
1149
1020
  },
1150
1021
  required: ['api_key', 'action'],
1151
1022
  },
1152
1023
  },
1153
1024
  {
1154
1025
  name: 'webaz_price_history',
1155
- description: `Product historical sale price + volume distribution — helps agents avoid bottom-price dumping bait.
1156
- Returns:
1157
- - windows: { d30, d90, lifetime } each {sales, volume, avg, median, p25, p75}
1158
- - price_buckets: distribution array [{price, count, qty, pct}]
1159
- - daily_avg: 30-day daily avg price trend [{date, sales, avg}]
1160
- - category_avg_30d: same-category 30-day average
1161
- - anomaly_flags: ('current_below_70pct_median' / 'far_below_category_avg' / 'far_above_category_avg')
1162
- Returns insufficient_data:true when data sparse.
1026
+ // was ~571 chars, now ~350 chars
1027
+ description: `Product historical sale price + volume — helps agents avoid bottom-price dumping bait.
1163
1028
 
1164
- ──
1165
- 中文:商品历史成交价 + 量分布 — 防底价倾销。返回多时窗统计 + 价位分布 + 同类均价 + 异常预警。`,
1029
+ Returns: windows {d30, d90, lifetime} each {sales, volume, avg, median, p25, p75} | price_buckets [{price, count, qty, pct}] | daily_avg (30-day trend) | category_avg_30d | anomaly_flags (current_below_70pct_median / far_below_category_avg / far_above_category_avg). \`insufficient_data: true\` if sparse.`,
1166
1030
  inputSchema: {
1167
1031
  type: 'object',
1168
1032
  properties: {
1169
- product_id: { type: 'string', description: '商品 ID' },
1033
+ product_id: { type: 'string', description: 'Product ID' },
1170
1034
  },
1171
1035
  required: ['product_id'],
1172
1036
  },
1173
1037
  },
1174
1038
  {
1175
1039
  name: 'webaz_charity',
1176
- description: `Charity WISH POOL + repayment + community FUND — double-anonymous + dual-signed anchoring + isolated prestige.
1040
+ // was ~1856 chars, now ~850 chars
1041
+ description: `Charity wish pool + repayment + community fund — double-anonymous + dual-signed anchoring + isolated prestige.
1177
1042
 
1178
- USE THIS when:
1179
- - user wants to publish a "wish" (need help with money/service) for community fulfillment, OR
1180
- - user wants to claim/fulfill someone else's wish, OR
1181
- - user wants to donate to / browse the community charity fund (separate from per-order donation).
1043
+ USE THIS for: publishing wish (need help) | claiming/fulfilling others' wishes | donating to / browsing community fund.
1182
1044
 
1183
- NOT for per-order charity donation — that's handled by webaz_place_order's donation_pct param (0.5% / 1% / 2% / 5% sent to charity_fund at order time). This tool is for the standalone wish-fulfillment economy.
1184
- Actions:
1185
- - list: browse public wishes (filter by category/target_kind; anonymous accessible)
1186
- - detail: single wish details (commit_hash + fulfillment + repayments)
1187
- - create: (auth) publish a wish
1188
- - claim: (auth) fulfiller claims (1:1 exclusive; 30-day self-claim lock; auto-release if no proof in 48h)
1189
- - proof: (auth) submit completion evidence
1190
- - confirm: (auth) wisher confirms → fulfiller +10 prestige
1191
- - disclose: (auth) apply for public disclosure (both parties must agree)
1192
- - cancel: (auth) wisher cancels (only open wishes)
1193
- - me: (auth) my charity profile (prestige breakdown + pending repayment queue)
1194
- - stories / leaderboard: public
1195
- - repay: (auth) wisher initiates repayment (≥ 0.1 WAZ; auto-accepted if no response in 7d)
1196
- - repay_respond:(auth) fulfiller responds (accept | decline_to_fund) — decline → funds go to community fund, wisher +8 / fulfiller +2 grace
1197
- - donate: (auth) donate to community fund (≥ 0.1 WAZ; daily 50 WAZ matched 1:1 → donation_honor)
1198
- - fund: fund balance + ledger + philanthropist leaderboard (public)
1045
+ **NOT** for per-order charity donation — that's webaz_place_order's \`donation_pct\` (0.5/1/2/5% to charity_fund at order time). This tool is the **standalone wish-fulfillment economy**.
1199
1046
 
1200
- ──
1201
- 中文:慈善许愿池 + 还愿 + 慈善基金。双匿名 + 双签锚定 + 隔离 prestige。Actions: list/detail/create/claim/proof/confirm/disclose/cancel/me/stories/leaderboard/repay/repay_respond/donate/fund。`,
1047
+ Actions (15):
1048
+ - list / detail / stories / leaderboard / fund — public
1049
+ - create (auth) publish wish
1050
+ - claim (auth) 1:1 exclusive, 30-day self-claim lock, auto-release if no proof 48h
1051
+ - proof / confirm (auth) complete + wisher confirm → fulfiller +10 prestige
1052
+ - disclose (auth) both-agree public disclosure
1053
+ - cancel (auth) only open wishes
1054
+ - me (auth) prestige breakdown + pending repayment queue
1055
+ - repay (auth) ≥0.1 WAZ; auto-accept if no response 7d
1056
+ - repay_respond (auth) accept | decline_to_fund (decline → fund, wisher +8 / fulfiller +2 grace)
1057
+ - donate (auth) ≥0.1 WAZ; daily 50 WAZ matched 1:1 → donation_honor`,
1202
1058
  inputSchema: {
1203
1059
  type: 'object',
1204
1060
  properties: {
@@ -1210,14 +1066,14 @@ Actions:
1210
1066
  choice: { type: 'string', enum: ['accept', 'decline_to_fund'] },
1211
1067
  category: { type: 'string', enum: ['medical', 'education', 'daily', 'elderly', 'disaster', 'tech', 'other'] },
1212
1068
  target_kind: { type: 'string', enum: ['item', 'service', 'cash'] },
1213
- target_waz: { type: 'number', description: 'cash 模式必填,≤ 500' },
1214
- escrow_self: { type: 'number', description: '1=自我托管锁仓全额,0=纯协调' },
1069
+ target_waz: { type: 'number', description: 'Required for cash mode, 500' },
1070
+ escrow_self: { type: 'number', description: '1=self-escrow lock full amount; 0=pure coordination' },
1215
1071
  title: { type: 'string' }, content: { type: 'string' },
1216
- window_hours: { type: 'number', description: '24-720 小时' },
1072
+ window_hours: { type: 'number', description: '24-720 hours' },
1217
1073
  allow_public: { type: 'number' },
1218
1074
  proof_hash: { type: 'string', description: 'sha256 hex of proof_text' },
1219
1075
  proof_note: { type: 'string' },
1220
- amount: { type: 'number', description: 'repay / donate 金额(WAZ' },
1076
+ amount: { type: 'number', description: 'repay / donate amount in WAZ' },
1221
1077
  note: { type: 'string' },
1222
1078
  limit: { type: 'number' },
1223
1079
  },
@@ -1226,20 +1082,15 @@ Actions:
1226
1082
  },
1227
1083
  {
1228
1084
  name: 'webaz_p2p_product',
1085
+ // was ~880 chars, now ~480 chars
1229
1086
  description: `P2P native store — product detail lives on seller's node; WebAZ only anchors hash + key fields.
1230
- Actions:
1231
- - create (seller): publish anchor — needs title/price/stock + content_hash (sha256) + content_signature (HMAC-SHA256(api_key, hash|signed_at))
1232
- - list: browse public P2P products (incl. hash + peer_endpoint)
1233
- - detail: single product (incl. hash + endpoint; agent should self-fetch peer_endpoint and verify sha256)
1234
- - patch (seller): edit (price/stock/title direct; detail JSON change → must re-sign hash + signature)
1235
1087
 
1236
- Verification flow (agent implements):
1088
+ Actions: create (seller, needs title/price/stock + content_hash sha256 + content_signature HMAC-SHA256(api_key, hash|signed_at)) | list | detail | patch (price/stock/title direct; detail JSON change → must re-sign).
1089
+
1090
+ ⚠️ **Agent verification flow** (must implement):
1237
1091
  1. GET peer_endpoint/<product_id> → raw JSON
1238
1092
  2. canonicalize (sort keys, drop nulls) → JSON.stringify
1239
- 3. sha256(canonical) === product.content_hash ? accept : reject trade
1240
-
1241
- ──
1242
- 中文:P2P 原生商店 — 商品详情存卖家节点,WebAZ 只锚定 hash + 关键字段。Actions: create / list / detail / patch。Agent 须自行 GET peer_endpoint 校验 sha256。`,
1093
+ 3. sha256(canonical) === product.content_hash ? accept : **reject trade**`,
1243
1094
  inputSchema: {
1244
1095
  type: 'object',
1245
1096
  properties: {
@@ -1259,14 +1110,12 @@ Verification flow (agent implements):
1259
1110
  },
1260
1111
  {
1261
1112
  name: 'webaz_like',
1262
- description: `Like a shareable (others' shared content) to boost product ranking.
1263
- Actions:
1264
- - toggle: like or unlike (same endpoint; second call auto-unlikes)
1265
- - status: my like status on a shareable + total count
1266
- Threshold: must have ≥1 completed order (anti-Sybil). One vote per person, can't like own.
1113
+ // was ~369 chars, now ~230 chars
1114
+ description: `Like a shareable to boost product ranking.
1267
1115
 
1268
- ──
1269
- 中文:对 shareable 点赞 — 提升商品 ranking。Actions: toggle / status。门槛:≥1 完成订单,不能给自己点。`,
1116
+ Actions: toggle (same endpoint; 2nd call auto-unlikes) | status (my like status + total).
1117
+
1118
+ ⚠️ **Anti-Sybil**: must have ≥1 completed order. One vote per person, can't like own.`,
1270
1119
  inputSchema: {
1271
1120
  type: 'object',
1272
1121
  properties: {
@@ -1279,49 +1128,43 @@ Threshold: must have ≥1 completed order (anti-Sybil). One vote per person, can
1279
1128
  },
1280
1129
  {
1281
1130
  name: 'webaz_leaderboard',
1282
- description: `WebAZ leaderboards — no centralized traffic distribution, pure real-signal ranking. Privacy-first: GMV / revenue amounts are NEVER exposed.
1283
- Kinds:
1284
- - products trending products (rank_score = sales×0.5 + referrals×2.0 + likes×1.0)
1285
- - value_products value-certified (💎 cheapest 20% per category · daily batch)
1286
- - creators creator board (by total likes received)
1287
- - sellers seller board (by rating × log(reviews+1); GMV hidden)
1288
- - buyers buyer activity (by completed order count; GMV hidden)
1289
- - verifiers verifier board (correct count / accuracy)
1290
- - arbitrators arbitrator reputation (fairness_score)
1291
- - agents agent eval (trust_score + 30d call count)
1131
+ // was ~817 chars, now ~480 chars
1132
+ description: `WebAZ leaderboards — no centralized traffic distribution, pure real-signal ranking. **Privacy-first**: GMV / revenue amounts NEVER exposed.
1292
1133
 
1293
- ──
1294
- 中文:排行榜(无中心流量分发,纯真实信号)。8 类:products / value_products / creators / sellers / buyers / verifiers / arbitrators / agents。隐私第一不露 GMV。`,
1134
+ 8 kinds:
1135
+ - products (sales×0.5 + referrals×2.0 + likes×1.0)
1136
+ - value_products (💎 cheapest 20% per category, daily batch)
1137
+ - creators (total likes received)
1138
+ - sellers (rating × log(reviews+1); GMV hidden)
1139
+ - buyers (completed order count; GMV hidden)
1140
+ - verifiers (correct count / accuracy)
1141
+ - arbitrators (fairness_score)
1142
+ - agents (trust_score + 30d call count)`,
1295
1143
  inputSchema: {
1296
1144
  type: 'object',
1297
1145
  properties: {
1298
1146
  kind: {
1299
1147
  type: 'string',
1300
1148
  enum: ['products', 'value_products', 'creators', 'sellers', 'buyers', 'verifiers', 'arbitrators', 'agents'],
1301
- description: '榜单类型',
1149
+ description: 'Leaderboard kind',
1302
1150
  },
1303
- limit: { type: 'number', description: '默认 20,最多 50' },
1151
+ limit: { type: 'number', description: 'Default 20, max 50' },
1304
1152
  },
1305
1153
  required: ['kind'],
1306
1154
  },
1307
1155
  },
1308
1156
  {
1309
1157
  name: 'webaz_auction',
1310
- description: `English forward auction seller posts → buyers raise bids → anti-sniping extension → highest bid wins.
1158
+ // was ~967 chars, now ~550 chars
1159
+ description: `English forward auction — seller posts → buyers raise → **anti-sniping extension** → highest wins.
1311
1160
 
1312
- USE THIS when user wants to BID on auction items OR a seller wants to START an auction (rare goods,
1313
- collectibles, price-discovery). NOT a regular product search — auctions are time-windowed events.
1314
- For fixed-price items use webaz_search.
1315
- Actions:
1316
- - create (seller): start auction; needs title/qty/category/starting_price, optional min_increment/reserve_price/window_min/sniper_extend_min
1317
- - browse: public board
1318
- - mine: my created (seller) + my participated (buyer)
1319
- - detail: full detail incl. bid history (buyer_id redacted for non-seller / non-bidder viewers)
1320
- - bid (buyer): place bid; needs auction_id + price (first ≥ starting; subsequent ≥ current + increment)
1321
- - cancel (seller): cancel (only before any bid placed)
1161
+ USE THIS to BID on auction items OR seller starts auction (rare goods / collectibles / price-discovery). NOT regular product search — auctions are **time-windowed events**. For fixed-price use webaz_search.
1322
1162
 
1323
- ──
1324
- 中文:加价拍卖(English forward)— 反狙击延时 + 最高价中标。Actions: create / browse / mine / detail / bid / cancel。仅未出价时可取消。`,
1163
+ Actions:
1164
+ - create (seller): title/qty/category/starting_price + optional min_increment/reserve_price/window_min/sniper_extend_min
1165
+ - browse / mine (own + participated) / detail (bid history; buyer_id redacted to non-seller/non-bidder)
1166
+ - bid (buyer): auction_id + price (first ≥ starting; next ≥ current + increment)
1167
+ - cancel (seller, only pre-bid)`,
1325
1168
  inputSchema: {
1326
1169
  type: 'object',
1327
1170
  properties: {
@@ -1344,16 +1187,12 @@ Actions:
1344
1187
  },
1345
1188
  {
1346
1189
  name: 'webaz_auto_bid',
1190
+ // was ~595 chars, now ~340 chars
1347
1191
  description: `Seller auto_bid Skill config — auto-quote on RFQ creation instantly.
1348
1192
 
1349
- USE THIS as a shortcut equivalent to webaz_skill install kind=auto_bid + ongoing config edits. Dedicated tool because auto_bid is the most-used Skill and needs frequent param tuning (max_eta_h / undercut_pct / daily_cap). For other Skill kinds use webaz_skill directly.
1350
- Actions:
1351
- - get: read current Skill config
1352
- - set: create/update Skill (needs categories[] / regions[] / max_eta_h / bid_strategy etc.)
1353
- - disable: one-click disable (keeps config)
1193
+ Shortcut for \`webaz_skill install kind=auto_bid\` + ongoing config edits. Dedicated tool because auto_bid is most-used + needs frequent tuning (max_eta_h / undercut_pct / daily_cap). For other Skill kinds use webaz_skill.
1354
1194
 
1355
- ──
1356
- 中文:卖家 auto_bid Skill — RFQ 创建瞬间自动报价。Actions: get / set / disable。`,
1195
+ Actions: get | set (categories[] / regions[] / max_eta_h / bid_strategy) | disable (keeps config).`,
1357
1196
  inputSchema: {
1358
1197
  type: 'object',
1359
1198
  properties: {
@@ -1364,7 +1203,7 @@ Actions:
1364
1203
  max_eta_h: { type: 'number' },
1365
1204
  fulfillment_type: { type: 'string', enum: ['instant_pickup', 'same_day', 'next_day', 'standard'] },
1366
1205
  bid_strategy: { type: 'string', enum: ['cheapest_undercut', 'match_budget'] },
1367
- undercut_pct: { type: 'number', description: '0–0.5;折价幅度' },
1206
+ undercut_pct: { type: 'number', description: '0–0.5; undercut margin' },
1368
1207
  max_price_cap: { type: 'number' },
1369
1208
  daily_cap: { type: 'number' },
1370
1209
  cooldown_min: { type: 'number' },
@@ -1375,151 +1214,191 @@ Actions:
1375
1214
  },
1376
1215
  {
1377
1216
  name: 'webaz_skill_market',
1378
- description: `Knowledge-skill marketplace anyone publishes reusable content skills (templates / prompts / guides / checklists); others pay to unlock. DISTINCT from webaz_skill (that one is seller behaviour-automation plugins).
1217
+ // was ~1426 chars, now ~720 chars
1218
+ description: `Knowledge-skill marketplace — anyone publishes content skills (templates / prompts / guides / checklists); others pay to unlock.
1379
1219
 
1380
- Lifecycle: publish WebAZ content review (human admin, not via MCP) listed buyers unlock.
1381
- Billing modes: free / one_time (buy once, permanent) / per_use (charged each read).
1382
- Revenue is an independent flow (author net → wallet, 5% protocol fee → sys_protocol); it does NOT enter PV / referral commission engines.
1220
+ ⚠️ **DISTINCT from webaz_skill** (which is seller behaviour-automation plugins, totally separate revenue flow).
1383
1221
 
1384
- Actions:
1385
- - list browse listed skills (filters: kind / billing / query; no auth needed)
1386
- - detail one skill's public detail (skill_id; content is NOT included)
1387
- - publish publish a new skill (title + content + billing_mode required) → enters review queue
1388
- - update edit own skill (editing an approved one re-enters review)
1389
- - delist take own skill offline
1390
- - resubmit resubmit a rejected/delisted skill for review
1391
- - purchase unlock free / one_time skill (cannot buy your own)
1392
- - read read the unlocked content; per_use charges price each call
1393
- - my_skills my published skills (all statuses)
1394
- - library my unlocked / used skills
1222
+ Lifecycle: publish → human admin content review (NOT via MCP) → listed → buyers unlock.
1395
1223
 
1396
- ──
1397
- 中文:知识技能市场 — 人人发布内容型技能(模板/提示词/指南/清单),他人付费解锁。与 webaz_skill(卖家自动化插件)是两套。计费 free/one_time/per_use;收入独立流转,不进 PV/佣金。审计是人工 admin 节点,不经 MCP。Actions: list / detail / publish / update / delist / resubmit / purchase / read / my_skills / library。`,
1224
+ Billing: \`free\` | \`one_time\` (buy once, permanent) | \`per_use\` (charged each read).
1225
+
1226
+ ⚠️ **Revenue is independent flow**: author net → wallet, 5% protocol fee → sys_protocol. Does **NOT** enter PV / referral commission engines.
1227
+
1228
+ Actions: list (no auth, filters: kind/billing/query) | detail (public, no content) | publish (→ review queue) | update (re-enters review if approved) | delist | resubmit | purchase (free / one_time; cannot self-buy) | read (per_use charges each call) | my_skills | library.`,
1398
1229
  inputSchema: {
1399
1230
  type: 'object',
1400
1231
  properties: {
1401
- api_key: { type: 'string', description: '你的 api_keylist / detail 时可省略)' },
1232
+ api_key: { type: 'string', description: 'Your api_key (omit for list/detail)' },
1402
1233
  action: {
1403
1234
  type: 'string',
1404
1235
  enum: ['list', 'detail', 'publish', 'update', 'delist', 'resubmit', 'purchase', 'read', 'my_skills', 'library'],
1405
- description: '要执行的操作',
1236
+ description: 'Action to execute',
1406
1237
  },
1407
- skill_id: { type: 'string', description: '技能 IDdetail/update/delist/resubmit/purchase/read 时必填)' },
1238
+ skill_id: { type: 'string', description: 'Skill ID (required for detail/update/delist/resubmit/purchase/read)' },
1408
1239
  // publish / update
1409
- title: { type: 'string', description: '标题(publish 必填)' },
1410
- content: { type: 'string', description: '技能正文,购买后才可见(publish 必填)' },
1411
- summary: { type: 'string', description: '一句话简介(可选)' },
1412
- preview: { type: 'string', description: '公开试读,未购可见(可选)' },
1413
- skill_kind: { type: 'string', enum: ['template', 'prompt', 'guide', 'checklist'], description: '技能类型(默认 template' },
1414
- billing_mode: { type: 'string', enum: ['free', 'one_time', 'per_use'], description: '计费模式(publish 必填)' },
1415
- price: { type: 'number', description: 'WAZ 价格;free 必须为 0,付费必须 >0,上限 100000' },
1416
- category: { type: 'string', description: '分类(可选)' },
1240
+ title: { type: 'string', description: 'Title (required for publish)' },
1241
+ content: { type: 'string', description: 'Skill content, visible only after purchase (required for publish)' },
1242
+ summary: { type: 'string', description: 'One-line summary (optional)' },
1243
+ preview: { type: 'string', description: 'Public preview, visible without purchase (optional)' },
1244
+ skill_kind: { type: 'string', enum: ['template', 'prompt', 'guide', 'checklist'], description: 'Skill kind (default template)' },
1245
+ billing_mode: { type: 'string', enum: ['free', 'one_time', 'per_use'], description: 'Billing mode (required for publish)' },
1246
+ price: { type: 'number', description: 'Price in WAZ; free must = 0, paid must > 0, max 100000' },
1247
+ category: { type: 'string', description: 'Category (optional)' },
1417
1248
  // list filters
1418
- kind: { type: 'string', enum: ['template', 'prompt', 'guide', 'checklist'], description: '过滤类型(list 时可选)' },
1419
- billing: { type: 'string', enum: ['free', 'one_time', 'per_use'], description: '过滤计费模式(list 时可选)' },
1420
- query: { type: 'string', description: '关键词搜索(list 时可选)' },
1249
+ kind: { type: 'string', enum: ['template', 'prompt', 'guide', 'checklist'], description: 'Filter type (optional for list)' },
1250
+ billing: { type: 'string', enum: ['free', 'one_time', 'per_use'], description: 'Filter billing mode (optional for list)' },
1251
+ query: { type: 'string', description: 'Keyword search (optional for list)' },
1421
1252
  },
1422
1253
  required: ['action'],
1423
1254
  },
1424
1255
  },
1425
1256
  {
1426
1257
  name: 'webaz_secondhand',
1427
- description: `Secondhand market (个人闲置二手) — peer-to-peer pre-owned goods, 1% protocol fee, escrow-protected. Supports shipping and in-person handoff.
1428
-
1429
- USE THIS when user wants USED / pre-owned / 闲置 / 二手 items, OR wants to sell own used items.
1430
- For NEW manufactured products use webaz_search. Note: secondhand and shop catalog are separate
1431
- spaces — webaz_search does NOT return secondhand listings.
1258
+ // was ~1285 chars, now ~650 chars
1259
+ description: `Secondhand market (个人闲置二手) — P2P pre-owned goods, 1% protocol fee, escrow-protected. Supports shipping + in-person handoff.
1432
1260
 
1433
- Actions:
1434
- - browse list available items (filters: category / condition / region / min_price / max_price / query / sort; no auth needed; excludes your own when api_key given)
1435
- - detail one item's detail + seller's other listings (item_id; no auth needed)
1436
- - publish list an item (title + category + condition + price + images[] required; ≥1 image)
1437
- - update edit own item (item_id + fields; can set status available/reserved/closed)
1438
- - mine my listings + stats (available/sold/earned)
1439
- - buy place an order on an item (item_id + fulfillment_mode; shipping needs shipping_address)
1261
+ USE THIS for USED / pre-owned / 闲置 / 二手 items, OR selling own used. NOT for NEW manufactured (use webaz_search). **Separate space** — webaz_search does NOT return secondhand listings.
1440
1262
 
1441
- category: phone / computer / appliance / furniture / clothing / book / toy / sports / other
1442
- condition: brand_new / like_new / lightly_used / well_used / heavily_used
1443
- fulfillment: shipping / in_person / both
1263
+ Actions: browse (filters: category/condition/region/price/query/sort; no auth, excludes own when api_key given) | detail (no auth) | publish (title + category + condition + price + images[≥1]) | update (item_id + fields; status available/reserved/closed) | mine | buy (item_id + fulfillment_mode; shipping needs shipping_address).
1444
1264
 
1445
- ──
1446
- 中文:二手集市 — 个人闲置 P2P,协议费 1%,escrow 保护,支持快递/面交。Actions: browse / detail / publish / update / mine / buy。`,
1265
+ Enums: **category** phone/computer/appliance/furniture/clothing/book/toy/sports/other · **condition** brand_new/like_new/lightly_used/well_used/heavily_used · **fulfillment** shipping/in_person/both.`,
1447
1266
  inputSchema: {
1448
1267
  type: 'object',
1449
1268
  properties: {
1450
- api_key: { type: 'string', description: '你的 api_keybrowse / detail 时可省略)' },
1451
- action: { type: 'string', enum: ['browse', 'detail', 'publish', 'update', 'mine', 'buy'], description: '要执行的操作' },
1452
- item_id: { type: 'string', description: '物品 IDdetail/update/buy 时必填)' },
1269
+ api_key: { type: 'string', description: 'Your api_key (omit for browse/detail)' },
1270
+ action: { type: 'string', enum: ['browse', 'detail', 'publish', 'update', 'mine', 'buy'], description: 'Action to execute' },
1271
+ item_id: { type: 'string', description: 'Item ID (required for detail/update/buy)' },
1453
1272
  // publish / update
1454
- title: { type: 'string', description: '标题 2-60 字(publish 必填)' },
1455
- description: { type: 'string', description: '详细描述(≤1000 字,可选)' },
1456
- category: { type: 'string', enum: ['phone', 'computer', 'appliance', 'furniture', 'clothing', 'book', 'toy', 'sports', 'other'], description: '类目(publish 必填)' },
1457
- condition_grade: { type: 'string', enum: ['brand_new', 'like_new', 'lightly_used', 'well_used', 'heavily_used'], description: '成色(publish 必填)' },
1458
- price: { type: 'number', description: 'WAZ 价格 0-100000publish 必填)' },
1459
- negotiable: { type: 'boolean', description: '是否可议价(可选)' },
1460
- images: { type: 'array', items: { type: 'string' }, description: '图片 dataURL/URL 数组,≥1 张,最多 9 张(publish 必填)' },
1461
- region: { type: 'string', description: '地点(≤40 字,可选)' },
1462
- fulfillment: { type: 'string', enum: ['shipping', 'in_person', 'both'], description: '履约方式(默认 both' },
1463
- status: { type: 'string', enum: ['available', 'reserved', 'closed'], description: '改状态(update 时可选)' },
1273
+ title: { type: 'string', description: 'Title 2-60 chars (required for publish)' },
1274
+ description: { type: 'string', description: 'Description (≤1000 chars, optional)' },
1275
+ category: { type: 'string', enum: ['phone', 'computer', 'appliance', 'furniture', 'clothing', 'book', 'toy', 'sports', 'other'], description: 'Category (required for publish)' },
1276
+ condition_grade: { type: 'string', enum: ['brand_new', 'like_new', 'lightly_used', 'well_used', 'heavily_used'], description: 'Condition grade (required for publish)' },
1277
+ price: { type: 'number', description: 'Price in WAZ 0-100000 (required for publish)' },
1278
+ negotiable: { type: 'boolean', description: 'Negotiable flag (optional)' },
1279
+ images: { type: 'array', items: { type: 'string' }, description: 'Images dataURL/URL array, ≥1 9 (required for publish)' },
1280
+ region: { type: 'string', description: 'Region (≤40 chars, optional)' },
1281
+ fulfillment: { type: 'string', enum: ['shipping', 'in_person', 'both'], description: 'Fulfillment (default both)' },
1282
+ status: { type: 'string', enum: ['available', 'reserved', 'closed'], description: 'Change status (optional for update)' },
1464
1283
  // buy
1465
- fulfillment_mode: { type: 'string', enum: ['shipping', 'in_person'], description: '本单履约方式(buy 必填,默认 shipping' },
1466
- shipping_address: { type: 'string', description: '收货地址(buy shipping 时必填)' },
1467
- notes: { type: 'string', description: '订单备注(buy 可选,可写还价)' },
1284
+ fulfillment_mode: { type: 'string', enum: ['shipping', 'in_person'], description: 'Per-order fulfillment (required for buy, default shipping)' },
1285
+ shipping_address: { type: 'string', description: 'Shipping address (required for buy + shipping)' },
1286
+ notes: { type: 'string', description: 'Order note (optional for buy; can include counter-offer)' },
1468
1287
  // browse filters
1469
- condition: { type: 'string', description: '过滤成色,逗号分隔多选(browse 可选)' },
1288
+ condition: { type: 'string', description: 'Filter condition, comma-separated multi (optional for browse)' },
1470
1289
  min_price: { type: 'number' },
1471
1290
  max_price: { type: 'number' },
1472
- query: { type: 'string', description: '关键词(browse 可选)' },
1473
- sort: { type: 'string', enum: ['newest', 'price_asc', 'price_desc', 'popular'], description: '排序(browse 可选)' },
1291
+ query: { type: 'string', description: 'Keyword (optional for browse)' },
1292
+ sort: { type: 'string', enum: ['newest', 'price_asc', 'price_desc', 'popular'], description: 'Sort (optional for browse)' },
1474
1293
  },
1475
1294
  required: ['action'],
1476
1295
  },
1477
1296
  },
1478
1297
  {
1479
1298
  name: 'webaz_trial',
1480
- description: `Trial-for-review (测评免单) sellers offer order refunds to buyers who post a qualifying review note; when the review reaches a target view threshold the order is auto-refunded.
1299
+ // was ~1506 chars, now ~720 chars
1300
+ description: `Trial-for-review (测评免单) — seller refunds buyer's order when buyer posts qualifying review note that reaches a view threshold.
1481
1301
 
1482
- USE THIS when:
1483
- - buyer asks "is there a trial / free-test / 测评免单 / 0 元试用 for this product?", OR
1484
- - buyer has already ordered a product with a trial campaign and wants to claim the slot, OR
1485
- - seller wants to launch a trial campaign to seed reviews.
1486
- NOT a search tool — for product discovery use webaz_search (can filter by has_trial=true coming soon).
1302
+ USE THIS when: buyer asks "trial / 测评免单 / 0 元试用 for this product?" | buyer has ordered product with active campaign + wants to claim | seller wants to launch campaign. NOT a search tool — use webaz_search.
1487
1303
 
1488
- Anti-abuse is enforced server-side (buyer≠seller, must have a confirmed/completed order, account ≥3 days old, IP/UA rate limits, config snapshot at claim time) — MCP just passes through.
1304
+ ⚠️ **Anti-abuse enforced server-side** (MCP just passes through): buyer seller / must have confirmed-or-completed order / account age 3d / IP+UA rate limits / config snapshot at claim time.
1489
1305
 
1490
1306
  Buyer actions:
1491
- - get_campaign read a product's active trial campaign (product_id; no auth)
1492
- - apply claim a trial slot for a product you've bought (product_id)
1493
- - link_note attach your review note to a claim (claim_id + note_id)
1494
- - my_claims my trial claims + statuses
1495
- Seller actions:
1496
- - create_campaign open/update a campaign on your product (product_id + quota_total + reach_threshold + min_chars + min_days_live)
1497
- - cancel_campaign close your product's campaign (product_id)
1498
- - my_campaigns my seller-side campaigns
1499
- - campaign_claims claims under a campaign (campaign_id)
1307
+ - get_campaign read product's active campaign (no auth)
1308
+ - apply claim slot (product_id)
1309
+ - link_note attach review note (claim_id + note_id; note must be type=note + bound to product + active)
1310
+ - my_claims my claims + statuses
1500
1311
 
1501
- ──
1502
- 中文:测评免单 — 卖家给"发合格测评笔记且达到浏览阈值"的买家退款。反作弊后端强制(买≠卖/须完成订单/账号≥3天/IP频控/配置快照)。买家: get_campaign / apply / link_note / my_claims;卖家: create_campaign / cancel_campaign / my_campaigns / campaign_claims。`,
1312
+ Seller actions:
1313
+ - create_campaign open/update (quota_total 1-200 + reach_threshold 10-10000 + min_chars 20-5000 + min_days_live 1-90)
1314
+ - cancel_campaign / my_campaigns / campaign_claims`,
1503
1315
  inputSchema: {
1504
1316
  type: 'object',
1505
1317
  properties: {
1506
- api_key: { type: 'string', description: '你的 api_keyget_campaign 可省略)' },
1507
- action: { type: 'string', enum: ['get_campaign', 'apply', 'link_note', 'my_claims', 'create_campaign', 'cancel_campaign', 'my_campaigns', 'campaign_claims'], description: '要执行的操作' },
1508
- product_id: { type: 'string', description: '商品 IDget_campaign/apply/create_campaign/cancel_campaign 时必填)' },
1509
- claim_id: { type: 'string', description: '申请 IDlink_note 时必填)' },
1510
- campaign_id: { type: 'string', description: '活动 IDcampaign_claims 时必填)' },
1511
- note_id: { type: 'string', description: '测评笔记 IDlink_note 时必填;须 type=note + 绑定该商品 + active' },
1318
+ api_key: { type: 'string', description: 'Your api_key (omit for get_campaign)' },
1319
+ action: { type: 'string', enum: ['get_campaign', 'apply', 'link_note', 'my_claims', 'create_campaign', 'cancel_campaign', 'my_campaigns', 'campaign_claims'], description: 'Action to execute' },
1320
+ product_id: { type: 'string', description: 'Product ID (required for get_campaign/apply/create_campaign/cancel_campaign)' },
1321
+ claim_id: { type: 'string', description: 'Claim ID (required for link_note)' },
1322
+ campaign_id: { type: 'string', description: 'Campaign ID (required for campaign_claims)' },
1323
+ note_id: { type: 'string', description: 'Review note ID (required for link_note; must be type=note + bound to product + active)' },
1512
1324
  // create_campaign config
1513
- quota_total: { type: 'number', description: '名额数 1-200create_campaign 必填)' },
1514
- reach_threshold: { type: 'number', description: '浏览阈值 10-10000(默认 50' },
1515
- min_chars: { type: 'number', description: '笔记最少字数 20-5000(默认 50' },
1516
- min_days_live: { type: 'number', description: '笔记最少存活天数 1-90(默认 7' },
1325
+ quota_total: { type: 'number', description: 'Quota total 1-200 (required for create_campaign)' },
1326
+ reach_threshold: { type: 'number', description: 'Reach threshold 10-10000 (default 50)' },
1327
+ min_chars: { type: 'number', description: 'Min note chars 20-5000 (default 50)' },
1328
+ min_days_live: { type: 'number', description: 'Min note alive days 1-90 (default 7)' },
1517
1329
  },
1518
1330
  required: ['action'],
1519
1331
  },
1520
1332
  },
1333
+ {
1334
+ name: 'webaz_feedback',
1335
+ description: `Submit the user's in-use feedback / improvement idea about WebAZ itself, right where it happens — agent-native "use → build". When a user hits a problem ("search keeps returning nothing") or has an idea ("you should support sorting by delivery time"), call this instead of telling them to go file a GitHub issue.
1336
+
1337
+ Your unique value: this tool auto-attaches the **scene** (your recent tool calls + outcomes, redacted) so a maintainer can reproduce + fix — far better than a vague complaint.
1338
+
1339
+ actions:
1340
+ - submit (default): type=ux_issue|bug|proposal, area (e.g. search/order/dispute), text (the feedback), severity=low|annoying|blocking (for issues), optional subject. Returns id + status.
1341
+ - my: list the user's past feedback + current status (received→triaged→in_progress→resolved/declined/duplicate). Closed loop — accepted feedback earns co-build reputation.
1342
+ - get: one item by id.
1343
+
1344
+ Gate by type: ux_issue/bug (reporting a problem = "using") needs only a logged-in user — NO Passkey, anyone can report. proposal (building the platform) requires a Passkey-bound real person (identity anchor for contribution rewards). Co-build reputation is credited only to Passkey-bound submitters. NETWORK mode only — feedback must reach the live project; in SANDBOX it returns guidance to switch.
1345
+
1346
+ ──
1347
+ 中文:就地提交用户在使用中发现的问题/改进建议(agent 时代"用→建"距离归零)。自动附带脱敏"现场"(你最近的调用+结果),可复现可修。分级门:ux_issue/bug(报告问题)登录即可、无需 Passkey;proposal(建设)需绑 Passkey(真人锚点)。仅 NETWORK 模式。`,
1348
+ inputSchema: {
1349
+ type: 'object',
1350
+ properties: {
1351
+ action: { type: 'string', enum: ['submit', 'my', 'get'], description: 'submit (default) | my | get' },
1352
+ api_key: { type: 'string', description: "User's api_key (real person required)" },
1353
+ type: { type: 'string', enum: ['ux_issue', 'bug', 'proposal'], description: 'submit: kind of feedback' },
1354
+ area: { type: 'string', description: 'submit: which feature, e.g. search / order / dispute' },
1355
+ severity: { type: 'string', enum: ['low', 'annoying', 'blocking'], description: 'submit: for ux_issue/bug' },
1356
+ subject: { type: 'string', description: 'submit: optional short title' },
1357
+ text: { type: 'string', description: 'submit: the feedback / idea (≥5 chars)' },
1358
+ feedback_id: { type: 'string', description: 'get: the feedback id' },
1359
+ },
1360
+ required: ['api_key'],
1361
+ },
1362
+ },
1521
1363
  ];
1522
1364
  // ─── 工具处理函数 ─────────────────────────────────────────────
1365
+ // RFC-004: webaz_feedback — agent-native "use → build" 反馈(双模;仅 NETWORK 能送达)
1366
+ async function handleFeedback(args) {
1367
+ const action = args.action || 'submit';
1368
+ const apiKey = args.api_key;
1369
+ if (!apiKey)
1370
+ return { error: 'api_key required' };
1371
+ if (toolBackend('webaz_feedback') !== 'network') {
1372
+ return {
1373
+ _mode: 'sandbox',
1374
+ error: 'SANDBOX 模式下反馈无人接收 —— 建设性反馈要进真实项目才有意义。请设 WEBAZ_API_KEY 切到 NETWORK 模式后再提交。 / Feedback needs NETWORK mode to reach the project; set WEBAZ_API_KEY.',
1375
+ error_code: 'FEEDBACK_NEEDS_NETWORK',
1376
+ };
1377
+ }
1378
+ if (action === 'my')
1379
+ return apiCall('/api/build-feedback/mine', { apiKey });
1380
+ if (action === 'get') {
1381
+ const fid = args.feedback_id;
1382
+ if (!fid)
1383
+ return { error: 'feedback_id required for action=get' };
1384
+ return apiCall('/api/build-feedback/' + encodeURIComponent(fid), { apiKey });
1385
+ }
1386
+ // submit(默认)
1387
+ const text = (args.text ?? '').trim();
1388
+ if (text.length < 5)
1389
+ return { error: 'text required (≥5 chars)' };
1390
+ return apiCall('/api/build-feedback', {
1391
+ method: 'POST', apiKey,
1392
+ body: {
1393
+ type: args.type || 'ux_issue',
1394
+ area: args.area,
1395
+ severity: args.severity,
1396
+ subject: args.subject,
1397
+ text,
1398
+ scene: recentCalls.slice(-8), // 现场证据:脱敏摘要(tool / arg_keys / outcome / mode)
1399
+ },
1400
+ });
1401
+ }
1523
1402
  function handleInfo() {
1524
1403
  const summary = getManifestSummary();
1525
1404
  // QA 轮 3 抓到:live_stats 不是 hardcoded、不是 remote — 就是本地 SQLite count。这里加 source 字段澄清。
@@ -1560,13 +1439,26 @@ function handleInfo() {
1560
1439
  // 第三方尽调 agent 抓到过的破绽:live_stats 是本地库数字、引导词推 agent 拉新、佣金结构有 MLM 形态。
1561
1440
  // 此处主动披露,不抗辩;agent 自己判断如何处理。
1562
1441
  network_state: {
1442
+ // RFC-003 P3:显式声明当前客户端模式,让 agent 一眼分清"真网络 vs 本机沙盒"
1443
+ mode: MODE, // 'network' | 'sandbox'
1444
+ mode_banner: modeBanner(),
1445
+ mode_meaning: MODE === 'network'
1446
+ ? '🟢 NETWORK:核心交易工具(下单/上架/履约/比价等)走 webaz.xyz 共享生产网络。注意:本 webaz_info 工具尚未联网,下方 live_stats 仍读本机本地缓存,不代表全网规模。'
1447
+ : '🟡 SANDBOX:所有工具都在本机本地 SQLite 运行,与 webaz.xyz 全网隔离。任何计数 / 账号 / 订单仅本机有效,不是真实网络状态。设 WEBAZ_API_KEY 可切到 NETWORK。',
1563
1448
  phase: 'pre_launch',
1564
1449
  real_users_on_canonical: 0,
1565
1450
  canonical_endpoint: 'https://webaz.xyz',
1566
1451
  economic_flow: 'simulated WAZ (test currency, 1 WAZ ≈ 1 USDC peg is a模拟基准, not a real exchange rate). No fiat/crypto settles yet.',
1567
1452
  disclaimer: '本协议尚未公开上线,prod 真实用户≈0,无真实经济流转。下方 live_stats / 工具示例所有计数均来自**本机 MCP 服务器的本地 SQLite**(~/.webaz/webaz.db),仅供 dev / demo,不代表协议全网真实状态。请勿据此评估市场规模、做投资决策、或替终端用户承诺任何经济关系。',
1568
1453
  },
1569
- description: 'WebAZ 是一个去中心化商业协议。每笔交易通过状态机流转,每个状态转移都需要对应责任方的操作证明。任何超时未操作,协议自动判定该方违约并执行处置。',
1454
+ description: 'WebAZ is a decentralized commerce protocol. Every transaction flows through a state machine; each state transition needs proof-of-action from the responsible party. Any timeout-without-action: protocol auto-rules default + executes remedy. / WebAZ 是去中心化商业协议;每笔交易通过状态机流转,每次状态转移需对应责任方的操作证明;超时未操作则协议自动判违约并执行处置。',
1455
+ // 连接两个场景:用协议(本工具) ↔ 改协议(开发协作)。想改 WebAZ 本身的 agent 从这里进。
1456
+ for_contributors: {
1457
+ note: 'Want to change WebAZ itself (not just use it)? This is an open, agent-native protocol — AI-authored PRs are welcome, with accountability. / 想改 WebAZ 本身(不只是用)?这是开放的 agent 原生协议,欢迎 AI 提 PR,但需问责。',
1458
+ repo: 'https://github.com/seasonsagents-art/webaz',
1459
+ start_here: 'AGENTS.md (project map + before-you-code + PR flow) → CONTRIBUTING.md (full guide)',
1460
+ ai_accountability: 'AI-authored PRs: add 🤖🤖🤖 to the PR title; the agent must be triggered by a Passkey-bound human (webazer) who is accountable. / AI 提 PR:标题加 🤖🤖🤖,且须由已绑 Passkey 的真人(webazer)触发并担责。',
1461
+ },
1570
1462
  live_stats: stats,
1571
1463
  economics,
1572
1464
  // QA 轮 14.c P1:显式归因机制(与传统 MLM 自动吃下线的根本区别)
@@ -1577,7 +1469,7 @@ function handleInfo() {
1577
1469
  redirect_rules: 'chain_gap (无 L / sponsor 无效) → charity_fund; region cap (level > region max_levels) → global_fund. global region max_levels=1 (仅 L1);singapore 等 max_levels=3.',
1578
1470
  l1_gate: 'promoter 必须是 verified buyer(≥1 笔完成订单)才能领 commission,否则该份 redirect。',
1579
1471
  // 主动披露,不要让外部尽调 agent 自己读出来再写差评
1580
- compliance_notice: '⚠️ 本协议含三级佣金(L1/L2/L3 7:2:1) + 二元配对树(binary PV matching) + 邀请链结构。这类形态在多数司法辖区可能与**多层级营销(MLM)的法律定义重叠**。本协议通过显式 per-order 归因(非自动吃下线)规避了 MLM 寡头化的核心病灶,但形态层面仍带 MLM 特征,我们诚实告知。**代理 AI 不应默认替终端用户生成推广链接或拉新**——这需要用户的显式授权,且用户自身要先评估当地合规性。',
1472
+ compliance_notice: '⚠️ 本协议含三级佣金(L1/L2/L3 7:2:1) + 二元配对树(binary PV matching) + 邀请链结构。这类形态在多数司法辖区可能与**多层级营销(MLM)的法律定义重叠**。本协议通过显式 per-order 归因(非自动吃下线)规避了 MLM 寡头化的核心病灶,但形态层面仍带 MLM 特征,我们诚实告知。**代理 AI 不应默认替终端用户生成推广链接或拉新**——这需要用户的显式授权,且用户自身要先评估当地合规性。\n\n**Reward participation is opt-in (RFC-002)**: default = off. Users must apply (Passkey + ≥1 completed order); attribution always recorded (relation layer), but commission settlement gated until opt-in. Pending commission held in pending_commission_escrow for 30d grace. See docs/rfcs/RFC-002-rewards-opt-in.md for full state matrix.',
1581
1473
  },
1582
1474
  // QA 轮 3 FAIL:roles 漏 reviewer。register 工具支持 5 个角色,info 必须列全。
1583
1475
  roles: {
@@ -1617,6 +1509,25 @@ function handleInfo() {
1617
1509
  };
1618
1510
  }
1619
1511
  function handleRegister(args) {
1512
+ // ─── RFC-003 P3:NETWORK 模式不自助建号 ────────────────────────
1513
+ // 自助注册会绕过邀请码 / captcha / 责任制;且 CHARTER §4 I-5 要求账号必须由已绑 Passkey
1514
+ // 的真人创建("每个 agent 背后有可问责的真人")。NETWORK 模式下改为引导真人去 webaz.xyz 拿 key。
1515
+ if (MODE === 'network') {
1516
+ return {
1517
+ _mode: 'network',
1518
+ registration: 'must_be_done_by_human_at_webaz_xyz',
1519
+ message: '🟢 NETWORK 模式下不支持 agent 自助注册。开放协议的信任来自"每个 agent 背后有可问责的真人",所以注册这一步刻意留给真人在 webaz.xyz 完成。请按三步加入共享网络:',
1520
+ steps: [
1521
+ '1. 打开 https://webaz.xyz 注册账号(需邀请码;注册时绑定 Passkey 成为可问责真人)',
1522
+ '2. 进入「我的 / 设置」→ 复制你的 api_key',
1523
+ '3. 把 api_key 填入 MCP 配置环境变量 WEBAZ_API_KEY,重启 MCP —— 之后所有交易工具自动在 webaz.xyz 共享网络上操作',
1524
+ ],
1525
+ register_url: WEBAZ_API_URL,
1526
+ why_not_agent_self_register: 'agent 自助注册会绕过邀请 / captcha / 真人 Passkey 责任制,破坏协议的可问责性(#6 不滥用 / CHARTER §4 I-5)。',
1527
+ want_to_try_offline_first: '只想离线试玩、暂不连网络?设环境变量 WEBAZ_MODE=sandbox(或清空 WEBAZ_API_KEY),webaz_register 会在本机沙盒建一个测试账号(仅本机有效)。',
1528
+ };
1529
+ }
1530
+ // ─── SANDBOX 模式:本机建测试账号(显著标注,仅本机有效,与 webaz.xyz 全网隔离)──
1620
1531
  const name = args.name;
1621
1532
  const role = args.role;
1622
1533
  const initialBalance = args.initial_balance ?? 1000;
@@ -1642,7 +1553,10 @@ function handleRegister(args) {
1642
1553
  : '等待订单分配给你';
1643
1554
  return {
1644
1555
  success: true,
1645
- message: '注册成功!妥善保管 api_key(身份凭证)+ permanent_code(恢复码,丢失 api_key 用它配 handle 找回)',
1556
+ _mode: 'sandbox',
1557
+ sandbox_account: true,
1558
+ sandbox_warning: '⚠️ 这是 SANDBOX 测试账号 —— 仅本机有效,未在 webaz.xyz 全网注册,与共享网络完全隔离。要真正加入网络(让交易对其他人可见、形成网络效应),请在 https://webaz.xyz 注册并把 api_key 填入 WEBAZ_API_KEY 切到 NETWORK 模式。',
1559
+ message: '沙盒注册成功(仅本机)!妥善保管 api_key(身份凭证)+ permanent_code(恢复码,丢失 api_key 用它配 handle 找回)',
1646
1560
  user_id: id,
1647
1561
  api_key: apiKey,
1648
1562
  permanent_code: permaCode,
@@ -1747,6 +1661,38 @@ async function handleSearch(args) {
1747
1661
  if (limit > 200)
1748
1662
  limit = 200;
1749
1663
  const sortMode = args.sort ?? 'trending';
1664
+ // RFC-003 P4: NETWORK 模式关键词搜索 → 生产 GET /api/products?mode=agent
1665
+ // (同款协议级 strict alias 引擎,公开读,不传 fuzzy)。让 agent 搜到的是全网真实在售商品。
1666
+ if (toolBackend('webaz_search') === 'network') {
1667
+ const qs = new URLSearchParams({ mode: 'agent', limit: String(limit) });
1668
+ if (query)
1669
+ qs.set('q', query);
1670
+ if (category)
1671
+ qs.set('category', String(category));
1672
+ if (maxPrice != null)
1673
+ qs.set('max_price', String(maxPrice));
1674
+ if (minReturnDays != null)
1675
+ qs.set('min_return_days', String(minReturnDays));
1676
+ if (maxHandlingHours != null)
1677
+ qs.set('max_handling_hours', String(maxHandlingHours));
1678
+ if (hasSales)
1679
+ qs.set('has_sales', String(hasSales));
1680
+ if (sellerId)
1681
+ qs.set('seller_id', String(sellerId));
1682
+ if (args.sort)
1683
+ qs.set('sort', String(args.sort));
1684
+ const r = await apiCall('/api/products?' + qs.toString());
1685
+ if ('error' in r)
1686
+ return r;
1687
+ const products = r.products ?? [];
1688
+ return {
1689
+ ...r,
1690
+ found: products.length,
1691
+ hint: products.length
1692
+ ? `网络上匹配到 ${products.length} 件商品。下单前用 webaz_verify_price 锁价。`
1693
+ : '网络上未找到精确匹配商品(协议级 strict 匹配)。可换更准确的商品名,或用 paste_text 贴外链搜索。',
1694
+ };
1695
+ }
1750
1696
  let sql = `
1751
1697
  SELECT p.*, u.name as seller_name,
1752
1698
  COALESCE((SELECT total_points FROM reputation_scores WHERE user_id = p.seller_id), 0) as rep_points,
@@ -1919,7 +1865,15 @@ async function handleSearch(args) {
1919
1865
  hint: 'agent 模式:products 已附带 metrics + score(含阶梯新鲜度 + 14d 首单 boost),可基于自身策略二次排序',
1920
1866
  };
1921
1867
  }
1922
- function handleVerifyPrice(args) {
1868
+ async function handleVerifyPrice(args) {
1869
+ // RFC-003 P2: network 模式转发到生产 POST /api/verify-price(前置,绕过本地 db)
1870
+ if (toolBackend('webaz_verify_price') === 'network') {
1871
+ return apiCall('/api/verify-price', {
1872
+ method: 'POST',
1873
+ apiKey: args.api_key,
1874
+ body: { product_id: args.product_id, quantity: Number(args.quantity ?? 1) },
1875
+ });
1876
+ }
1923
1877
  const auth = requireAuth(db, args.api_key);
1924
1878
  if ('error' in auth)
1925
1879
  return auth;
@@ -1969,6 +1923,56 @@ async function handleListProduct(args) {
1969
1923
  const apiKey = args.api_key;
1970
1924
  if (!apiKey)
1971
1925
  return { error: 'api_key required' };
1926
+ // RFC-003 P2b: NETWORK 模式 — 卖家目录管理全部转发生产端点(单一真相源)
1927
+ if (toolBackend('webaz_list_product') === 'network') {
1928
+ const pid = args.product_id;
1929
+ if (action === 'mine') {
1930
+ const r = await apiCall('/api/my-products', { apiKey });
1931
+ if (Array.isArray(r))
1932
+ return { found: r.length, products: r };
1933
+ return r;
1934
+ }
1935
+ if (action === 'create') {
1936
+ const createFields = ['title', 'description', 'price', 'stock', 'category', 'specs', 'brand', 'model', 'source_url', 'source_price', 'external_title', 'weight_kg', 'ship_regions', 'handling_hours', 'estimated_days', 'fragile', 'return_days', 'return_condition', 'warranty_days', 'commission_rate', 'product_type', 'aliases', 'image_hashes'];
1937
+ const body = {};
1938
+ for (const k of createFields)
1939
+ if (args[k] !== undefined)
1940
+ body[k] = args[k];
1941
+ const created = await apiCall('/api/products', { method: 'POST', apiKey, body });
1942
+ if ('error' in created)
1943
+ return created;
1944
+ const newId = (created.product_id ?? created.id);
1945
+ const extraKeys = ['i18n_titles', 'i18n_descs', 'origin_claims', 'low_stock_threshold', 'auto_delist_on_zero'];
1946
+ if (newId && extraKeys.some(k => args[k] !== undefined)) {
1947
+ const eb = {};
1948
+ for (const k of extraKeys)
1949
+ if (args[k] !== undefined)
1950
+ eb[k] = args[k];
1951
+ const extra = await apiCall(`/api/products/${encodeURIComponent(newId)}`, { method: 'PUT', apiKey, body: eb });
1952
+ return { ...created, extra_fields_applied: !('error' in extra), extra_result: extra };
1953
+ }
1954
+ return created;
1955
+ }
1956
+ if (!pid)
1957
+ return { error: `product_id required for action=${action}` };
1958
+ if (action === 'update') {
1959
+ const updatable = ['title', 'description', 'price', 'stock', 'specs', 'brand', 'model', 'handling_hours', 'ship_regions', 'estimated_days', 'fragile', 'return_days', 'return_condition', 'warranty_days', 'low_stock_threshold', 'auto_delist_on_zero', 'i18n_titles', 'i18n_descs', 'origin_claims'];
1960
+ const body = {};
1961
+ for (const k of updatable)
1962
+ if (args[k] !== undefined)
1963
+ body[k] = args[k];
1964
+ return apiCall(`/api/products/${encodeURIComponent(pid)}`, { method: 'PUT', apiKey, body });
1965
+ }
1966
+ if (action === 'delist')
1967
+ return apiCall(`/api/products/${encodeURIComponent(pid)}/status`, { method: 'PATCH', apiKey, body: { status: 'warehouse' } });
1968
+ if (action === 'relist')
1969
+ return apiCall(`/api/products/${encodeURIComponent(pid)}/status`, { method: 'PATCH', apiKey, body: { status: 'active' } });
1970
+ if (action === 'trash')
1971
+ return apiCall(`/api/products/${encodeURIComponent(pid)}/status`, { method: 'PATCH', apiKey, body: { status: 'deleted' } });
1972
+ if (action === 'delete')
1973
+ return apiCall(`/api/products/${encodeURIComponent(pid)}`, { method: 'DELETE', apiKey });
1974
+ return { error: `unknown action: ${action}. Valid actions: create | mine | update | delist | relist | trash | delete` };
1975
+ }
1972
1976
  if (action !== 'create') {
1973
1977
  const auth0 = requireAuth(db, apiKey);
1974
1978
  if ('error' in auth0)
@@ -2081,7 +2085,21 @@ async function handleListProduct(args) {
2081
2085
  ...(extraResult ? { extra_fields_applied: !('error' in extraResult), extra_result: extraResult } : {}),
2082
2086
  };
2083
2087
  }
2084
- function handlePlaceOrder(args) {
2088
+ async function handlePlaceOrder(args) {
2089
+ // RFC-003 P2: network 模式转发到生产 POST /api/orders(前置,绕过本地 db)。
2090
+ // 生产端做完整鉴权/库存/session/spend-cap/结算。
2091
+ if (toolBackend('webaz_place_order') === 'network') {
2092
+ const body = { product_id: args.product_id, quantity: Number(args.quantity ?? 1) };
2093
+ if (args.session_token != null)
2094
+ body.session_token = args.session_token;
2095
+ if (args.expected_price != null)
2096
+ body.expected_price = args.expected_price;
2097
+ if (args.shipping_address != null)
2098
+ body.shipping_address = args.shipping_address;
2099
+ if (args.donation_pct != null)
2100
+ body.donation_pct = args.donation_pct;
2101
+ return apiCall('/api/orders', { method: 'POST', apiKey: args.api_key, body });
2102
+ }
2085
2103
  const auth = requireAuth(db, args.api_key);
2086
2104
  if ('error' in auth)
2087
2105
  return auth;
@@ -2240,6 +2258,24 @@ function handlePlaceOrder(args) {
2240
2258
  };
2241
2259
  }
2242
2260
  async function handleUpdateOrder(args) {
2261
+ // RFC-003 P2b: NETWORK 模式 — 全部状态机动作转发生产 /api/orders/:id/action(单一真相源;
2262
+ // sandbox 路径里 confirm 也是这么转发的,network 把整套履约状态机统一走 PWA 引擎)
2263
+ if (toolBackend('webaz_update_order') === 'network') {
2264
+ const orderId = args.order_id;
2265
+ const action = args.action;
2266
+ if (!orderId || !action)
2267
+ return { error: 'order_id and action required' };
2268
+ return apiCall(`/api/orders/${encodeURIComponent(orderId)}/action`, {
2269
+ method: 'POST',
2270
+ apiKey: args.api_key,
2271
+ body: {
2272
+ action,
2273
+ notes: args.notes ?? '',
2274
+ evidence_description: args.evidence_description ?? '',
2275
+ ...(args.logistics_company_id ? { logistics_company_id: args.logistics_company_id } : {}),
2276
+ },
2277
+ });
2278
+ }
2243
2279
  const auth = requireAuth(db, args.api_key);
2244
2280
  if ('error' in auth)
2245
2281
  return auth;
@@ -2357,7 +2393,14 @@ async function handleUpdateOrder(args) {
2357
2393
  history_record: result.historyId,
2358
2394
  };
2359
2395
  }
2360
- function handleGetStatus(args) {
2396
+ async function handleGetStatus(args) {
2397
+ // RFC-003 P4: NETWORK 模式订单查询 → 生产 GET /api/orders/:id(权威网络订单详情 + 历史)
2398
+ if (toolBackend('webaz_get_status') === 'network') {
2399
+ const orderId = args.order_id;
2400
+ if (!orderId)
2401
+ return { error: 'order_id required' };
2402
+ return apiCall(`/api/orders/${encodeURIComponent(orderId)}`, { apiKey: args.api_key });
2403
+ }
2361
2404
  const auth = requireAuth(db, args.api_key);
2362
2405
  if ('error' in auth)
2363
2406
  return auth;
@@ -3016,8 +3059,41 @@ function handleReferral(args) {
3016
3059
  score_pending: score.pending,
3017
3060
  waz_total_earned: score.settled_waz,
3018
3061
  },
3062
+ rewards_status: (() => {
3063
+ // RFC-002 §3.5 — 4 states + pending escrow visibility (PR-4)
3064
+ const optIn = db.prepare("SELECT rewards_opted_in FROM users WHERE id = ?").get(userId)?.rewards_opted_in ?? 0;
3065
+ const lastAction = db.prepare("SELECT action FROM rewards_applications WHERE user_id = ? ORDER BY created_at DESC LIMIT 1").get(userId)?.action;
3066
+ let state;
3067
+ let note;
3068
+ if (optIn === 1) {
3069
+ state = 'opted_in';
3070
+ note = 'You have opted into rewards. Commissions credit to wallet immediately when orders settle.';
3071
+ }
3072
+ else if (lastAction === 'deactivate') {
3073
+ state = 'deactivated';
3074
+ note = 'You actively deactivated rewards. Future commissions redirect directly to charity_fund (no escrow). You can re-apply via PWA #me.';
3075
+ }
3076
+ else if (lastAction === 'auto_downgrade') {
3077
+ state = 'auto_downgraded';
3078
+ note = 'You were auto-downgraded (failed to re-confirm consent within grace window). Future commissions held in pending_commission_escrow (30d window) — re-confirm via PWA #me to recover them.';
3079
+ }
3080
+ else {
3081
+ state = 'never_activated';
3082
+ note = 'Rewards inactive — attributions recorded; commissions held in pending_commission_escrow (30d window per protocol_params.rewards_opt_in.escrow_days) until you activate via PWA #me.';
3083
+ }
3084
+ const pending = db.prepare("SELECT COUNT(*) AS n, COALESCE(SUM(amount),0) AS total FROM pending_commission_escrow WHERE recipient_user_id = ? AND status = 'pending'").get(userId);
3085
+ const expired = db.prepare("SELECT COUNT(*) AS n, COALESCE(SUM(amount),0) AS total FROM pending_commission_escrow WHERE recipient_user_id = ? AND status = 'expired'").get(userId);
3086
+ return {
3087
+ state,
3088
+ opted_in: optIn === 1,
3089
+ note,
3090
+ pending_escrow: { count: pending.n, total_amount: pending.total },
3091
+ expired_to_charity: { count: expired.n, total_amount: expired.total },
3092
+ spec: 'RFC-002 §3.5 — rewards opt-in / 共建身份申请制',
3093
+ };
3094
+ })(),
3019
3095
  tip: canL1
3020
- ? 'Use webaz_share_link(product_id) to generate a product share link. Both 3-tier commission and PV tree will apply.'
3096
+ ? 'Use webaz_share_link(product_id) to generate a product share link. Both 3-tier commission and PV tree will apply (only when rewards_opted_in=1).'
3021
3097
  : 'Complete 1 purchase first, then your share link will earn 3-tier commission. Until then, your share builds PV tree only.',
3022
3098
  };
3023
3099
  }
@@ -3029,6 +3105,35 @@ function handleShareLink(args) {
3029
3105
  const userId = user.id;
3030
3106
  const productId = args.product_id;
3031
3107
  const sideArg = args.side || 'auto';
3108
+ // RFC-002 §3.5 valuation-layer gate — share_link generation requires opt-in
3109
+ const optIn = db.prepare("SELECT rewards_opted_in FROM users WHERE id = ?").get(userId)?.rewards_opted_in ?? 0;
3110
+ if (optIn !== 1) {
3111
+ const getParam = (key, def) => {
3112
+ const r = db.prepare("SELECT value FROM protocol_params WHERE key = ?").get(key);
3113
+ return r ? Number(r.value) : def;
3114
+ };
3115
+ const minOrders = getParam('rewards_opt_in.min_completed_orders', 1);
3116
+ const requirePasskey = getParam('rewards_opt_in.require_passkey', 1);
3117
+ const totalCompleted = db.prepare("SELECT COUNT(*) as n FROM orders WHERE buyer_id = ? AND status = 'completed'").get(userId).n;
3118
+ const passkeyCount = db.prepare("SELECT COUNT(*) as n FROM webauthn_credentials WHERE user_id = ?").get(userId).n;
3119
+ const missing = [];
3120
+ if (totalCompleted < minOrders)
3121
+ missing.push(`completed_orders ${totalCompleted}/${minOrders}`);
3122
+ if (requirePasskey === 1 && passkeyCount === 0)
3123
+ missing.push('passkey_not_registered');
3124
+ if (missing.length === 0)
3125
+ missing.push('application_not_submitted');
3126
+ return {
3127
+ error: 'rewards_opt_in_required',
3128
+ message: 'Share-link generation is a valuation-layer action — requires builder-identity opt-in (RFC-002 §3.5)',
3129
+ missing_requirements: missing,
3130
+ next_steps: [
3131
+ 'Open PWA #me → tap "申请共建身份 / Apply for builder identity"',
3132
+ 'Read the 8-second disclosure (cannot skip)',
3133
+ 'Submit application — pre-checks run server-side',
3134
+ ],
3135
+ };
3136
+ }
3032
3137
  const product = db.prepare("SELECT id, title, price, commission_rate FROM products WHERE id = ? AND status='active'").get(productId);
3033
3138
  if (!product)
3034
3139
  return { error: '商品不存在或已下架' };
@@ -3039,7 +3144,7 @@ function handleShareLink(args) {
3039
3144
  else {
3040
3145
  // auto = 与 PWA pickPreferredSide 对齐:尊重 placement_pref(team_count | pv_count)
3041
3146
  // 老版只看 total_left_pv vs total_right_pv,team_count 用户被错算
3042
- const u = db.prepare("SELECT placement_pref, total_left_pv, total_right_pv, left_child_id, right_child_id FROM users WHERE id = ?")
3147
+ const u = db.prepare("SELECT placement_pref, total_left_pv, total_right_pv, left_count, right_count FROM users WHERE id = ?")
3043
3148
  .get(userId);
3044
3149
  const pref = u?.placement_pref || 'team_count';
3045
3150
  if (pref === 'pv_count') {
@@ -3052,22 +3157,10 @@ function handleShareLink(args) {
3052
3157
  side = leftPv <= rightPv ? 'left' : 'right';
3053
3158
  }
3054
3159
  else {
3055
- // team_count: 沿子链数下线人数(与 server.ts countSubtreeUsers 一致)
3056
- const countLeg = (rootId, childField) => {
3057
- let count = 0, current = rootId, safety = 10_000;
3058
- while (safety-- > 0) {
3059
- const row = db.prepare(`SELECT ${childField} FROM users WHERE id = ?`).get(current);
3060
- const next = row?.[childField] || null;
3061
- if (!next)
3062
- break;
3063
- count++;
3064
- current = next;
3065
- }
3066
- return count;
3067
- };
3068
- const lCount = countLeg(userId, 'left_child_id');
3069
- const rCount = countLeg(userId, 'right_child_id');
3070
- side = lCount <= rCount ? 'left' : 'right';
3160
+ // team_count: 整棵子树人数(增量维护的 left_count/right_count,与 PWA pickPreferredSide 对齐)。
3161
+ // 2026-06-04 修:旧版沿单条脊链数(countLeg)名实不符 选边失真。分享链接的 side 会被注册时
3162
+ // placement_side 显式采用,必须与 PWA joinPowerLeg 用同一指标,否则两路径不一致。
3163
+ side = (Number(u?.left_count ?? 0) <= Number(u?.right_count ?? 0)) ? 'left' : 'right';
3071
3164
  }
3072
3165
  }
3073
3166
  const completed = db.prepare("SELECT COUNT(*) as n FROM orders WHERE buyer_id = ? AND status = 'completed'").get(userId).n;
@@ -3362,6 +3455,19 @@ function handleShareables(args) {
3362
3455
  }
3363
3456
  // ─── P3 RFQ / bid / chat / auto_bid(HTTP 转发到 PWA,复用所有校验+状态机)────
3364
3457
  const PWA_API_BASE = process.env.WEBAZ_PWA_API_BASE || 'http://localhost:3000/api';
3458
+ // RFC-003 P1: 公开读端点按模式取数 —— network → apiCall(webaz.xyz + Bearer + 15s 超时);sandbox → 本地 PWA。
3459
+ // subpath 不含 /api 前缀(如 '/leaderboard?...'),内部按模式补齐。
3460
+ async function readEndpoint(tool, subpath) {
3461
+ if (toolBackend(tool) === 'network')
3462
+ return apiCall('/api' + subpath);
3463
+ try {
3464
+ const r = await fetch(PWA_API_BASE + subpath, { signal: AbortSignal.timeout(15_000) });
3465
+ return await r.json();
3466
+ }
3467
+ catch (e) {
3468
+ return { error: String(e.message) };
3469
+ }
3470
+ }
3365
3471
  async function pwaApi(method, path, apiKey, body) {
3366
3472
  const opts = {
3367
3473
  method,
@@ -3771,13 +3877,7 @@ async function handlePriceHistory(args) {
3771
3877
  const pid = String(args.product_id || '');
3772
3878
  if (!pid)
3773
3879
  return { error: 'product_id required' };
3774
- try {
3775
- const r = await fetch(PWA_API_BASE + '/products/' + encodeURIComponent(pid) + '/price-history');
3776
- return await r.json();
3777
- }
3778
- catch (e) {
3779
- return { error: String(e.message) };
3780
- }
3880
+ return readEndpoint('webaz_price_history', '/products/' + encodeURIComponent(pid) + '/price-history');
3781
3881
  }
3782
3882
  async function handleCharity(args) {
3783
3883
  const action = String(args.action || '');
@@ -3943,15 +4043,8 @@ async function handleLeaderboard(args) {
3943
4043
  const VALID_KINDS = ['products', 'creators', 'buyers', 'sellers', 'value_products', 'agents', 'arbitrators', 'verifiers'];
3944
4044
  if (!VALID_KINDS.includes(kind))
3945
4045
  return { error: `kind 必须是 ${VALID_KINDS.join(' / ')}` };
3946
- // 排行榜公开(不需 api_key);但 pwaApi 需要 用空 key 调(PWA 端 leaderboard 路由没 auth)
3947
- // 简化:直接调 fetch
3948
- try {
3949
- const r = await fetch(PWA_API_BASE + '/leaderboard?kind=' + kind + '&limit=' + limit);
3950
- return await r.json();
3951
- }
3952
- catch (e) {
3953
- return { error: `PWA API unreachable: ${e.message}` };
3954
- }
4046
+ // 排行榜公开(不需 api_key)。RFC-003 P1:network webaz.xyz,sandbox 走本地。
4047
+ return readEndpoint('webaz_leaderboard', '/leaderboard?kind=' + kind + '&limit=' + limit);
3955
4048
  }
3956
4049
  async function handleAuction(args) {
3957
4050
  const apiKey = String(args.api_key || '');
@@ -4074,7 +4167,7 @@ export async function startMCPServer() {
4074
4167
  {
4075
4168
  uri: MANIFEST_URI,
4076
4169
  name: 'WebAZ Protocol Manifest',
4077
- description: '完整的 WebAZ机器可读规范。包含:状态机、经济模型、角色职责、争议系统、Skill 市场、声誉积分、Agent 操作指南。AI Agent 读完即可参与协议,无需额外文档。',
4170
+ description: 'Full WebAZ machine-readable spec. Covers: state machine, economic model, roles, dispute system, Skill market, reputation, agent operating guide. Reading this is enough for an AI agent to participate in the protocol — no extra docs needed.',
4078
4171
  mimeType: 'application/json',
4079
4172
  },
4080
4173
  ],
@@ -4101,34 +4194,34 @@ export async function startMCPServer() {
4101
4194
  const PROMPTS = [
4102
4195
  {
4103
4196
  name: 'webaz-place-order',
4104
- description: '引导买家 agent 完成「发现验价锁价下单」全流程(含粘贴外链精准匹配)。如果用户给你商品链接,用这个 prompt。',
4197
+ description: 'Guide buyer agent through discover verify_pricelockplace_order (incl. precise match for pasted external links). Use this when the user hands you a product URL.',
4105
4198
  arguments: [
4106
- { name: 'user_intent', description: '用户原始需求或粘贴的链接文本', required: true },
4199
+ { name: 'user_intent', description: 'User raw intent or pasted link text', required: true },
4107
4200
  ],
4108
4201
  },
4109
4202
  {
4110
4203
  name: 'webaz-list-product',
4111
- description: '引导卖家 agent 完成商品上架 SEO/Agent 友好度最佳实践(填全 brand/model/specs/return_days/handling_hours Schema.org 加分字段)',
4204
+ description: 'Guide seller agent through product listing covers SEO/agent-friendliness best practices (fill brand/model/specs/return_days/handling_hours and other Schema.org bonus fields).',
4112
4205
  arguments: [
4113
- { name: 'product_summary', description: '卖家口述的商品概要', required: true },
4206
+ { name: 'product_summary', description: 'Seller-described product summary', required: true },
4114
4207
  ],
4115
4208
  },
4116
4209
  {
4117
4210
  name: 'webaz-onboard',
4118
- description: ' agent 第一次接入 webaz 时的引导 解释协议性质 / pre-launch 状态 / MLM 形态 / 注册路径 / 用户授权边界。先读 webaz_info,再走这个 prompt',
4211
+ description: 'Onboarding for a new agent first connecting to webaz — explains protocol nature / pre-launch state / MLM shape / registration path / user-authorization boundaries. Read webaz_info first, then run this prompt.',
4119
4212
  arguments: [],
4120
4213
  },
4121
4214
  {
4122
4215
  name: 'webaz-handle-dispute',
4123
- description: '订单出现问题时引导处理区分"协商退款 / 走争议仲裁 / 卖家主动取消"三条路径,提示铁律(arbitrate 必须 PWA + Passkey)',
4216
+ description: 'Guide handling when an order goes wrong distinguishes three paths: negotiated refund / dispute arbitration / seller-initiated cancel. Reminds Iron-Rule (arbitrate requires PWA + Passkey).',
4124
4217
  arguments: [
4125
- { name: 'order_id', description: '出问题的订单 ID', required: true },
4126
- { name: 'issue_summary', description: '问题描述(收到货不符 / 没收到 / 质量问题等)', required: true },
4218
+ { name: 'order_id', description: 'The problematic order ID', required: true },
4219
+ { name: 'issue_summary', description: 'Issue description (wrong item received / not received / quality problem, etc.)', required: true },
4127
4220
  ],
4128
4221
  },
4129
4222
  {
4130
4223
  name: 'webaz-cross-border',
4131
- description: '中国跨境卖家参与引导国内用 webaz 自有协议 / 跨境暴露 UCP merchant endpoint 给全球 agent。讲清双轨架构 + 合规边界。',
4224
+ description: 'Onboarding for China cross-border sellers domestic uses WebAZ native protocol / cross-border exposes UCP merchant endpoint to global agents. Explains dual-rail architecture + compliance boundaries.',
4132
4225
  arguments: [],
4133
4226
  },
4134
4227
  ];
@@ -4245,19 +4338,22 @@ export async function startMCPServer() {
4245
4338
  result = await handleSearch(args);
4246
4339
  break;
4247
4340
  case 'webaz_verify_price':
4248
- result = handleVerifyPrice(args);
4341
+ result = await handleVerifyPrice(args);
4249
4342
  break;
4250
4343
  case 'webaz_list_product':
4251
4344
  result = await handleListProduct(args);
4252
4345
  break;
4253
4346
  case 'webaz_place_order':
4254
- result = handlePlaceOrder(args);
4347
+ result = await handlePlaceOrder(args);
4255
4348
  break;
4256
4349
  case 'webaz_update_order':
4257
4350
  result = await handleUpdateOrder(args);
4258
4351
  break;
4259
4352
  case 'webaz_get_status':
4260
- result = handleGetStatus(args);
4353
+ result = await handleGetStatus(args);
4354
+ break;
4355
+ case 'webaz_feedback':
4356
+ result = await handleFeedback(args);
4261
4357
  break;
4262
4358
  case 'webaz_wallet':
4263
4359
  result = await handleWallet(args);
@@ -4353,6 +4449,29 @@ export async function startMCPServer() {
4353
4449
  result = { error: `执行出错:${err.message}` };
4354
4450
  }
4355
4451
  recordToolCall(name, args, result, Date.now() - t0);
4452
+ // RFC-004 现场证据:记本次调用的脱敏摘要(只 arg key 名,不含值)。webaz_feedback 自身不入 buffer。
4453
+ if (name !== 'webaz_feedback') {
4454
+ const isErr = !!result && typeof result === 'object' && 'error' in result;
4455
+ pushRecentCall({
4456
+ tool: name,
4457
+ arg_keys: Object.keys(args || {}).filter(k => k !== 'api_key'),
4458
+ outcome: isErr ? 'error' : 'ok',
4459
+ mode: toolBackend(name),
4460
+ ts: new Date().toISOString(),
4461
+ });
4462
+ }
4463
+ // RFC-003 P0: 给每个工具结果盖模式戳(诚实可见,防把 sandbox 当 live 网络)
4464
+ // P3: handler 可自行预设 _mode(如 register 在 network 模式返回引导,不是 sandbox 结果)→ 不覆盖。
4465
+ const backend = toolBackend(name);
4466
+ if (result && typeof result === 'object' && !Array.isArray(result)) {
4467
+ const r = result;
4468
+ if (!('_mode' in r))
4469
+ r._mode = backend;
4470
+ if (r._mode === 'sandbox' && !('_sandbox_note' in r)) {
4471
+ r._sandbox_note =
4472
+ 'SANDBOX: 本地结果,非 webaz.xyz 全网真实状态 / local-only, NOT the live webaz.xyz network';
4473
+ }
4474
+ }
4356
4475
  return {
4357
4476
  content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
4358
4477
  };
@@ -4360,6 +4479,7 @@ export async function startMCPServer() {
4360
4479
  const transport = new StdioServerTransport();
4361
4480
  await server.connect(transport);
4362
4481
  console.error('✅ WebAZ MCP Server 已启动,等待 Agent 连接...');
4482
+ console.error(modeBanner());
4363
4483
  }
4364
4484
  // ─── 工具函数 ─────────────────────────────────────────────────
4365
4485
  function addHours(date, hours) {