@taptap/instant-games-open-mcp 1.24.12 → 1.24.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -10,7 +10,8 @@
10
10
  - **📖 完整 API 文档** - 6 个排行榜 API + 详细代码示例
11
11
  - **⚙️ 服务端管理** - 创建/管理排行榜,自动处理 ID
12
12
  - **🎮 H5 游戏支持** - 上传、发布、状态查询
13
- - **📺 广告接入闭环** - 仅用于 TapTap 小游戏/H5,自动查询广告状态和广告位 ID,不与 Maker MCP 混用
13
+ - **📺 广告接入闭环** - 仅用于 TapTap 小游戏/H5,自动查询广告状态和广告位 ID;方向缺失时先刷新
14
+ 服务端应用信息,确认仍未设置后引导用户选择方向,不与 Maker MCP 混用
14
15
  - **🧭 当前游戏 DC 能力** - 商店/评价/社区统计概览、商店快照、论坛内容、评价列表、评价点赞、官方回复
15
16
  - **🦞 OpenClaw Plugin** - 提供一个原生 OpenClaw plugin 子包,内部复用 TapTap MCP 运行时并暴露 raw JSON 工具 + bundled skill
16
17
  - **🚀 三种传输模式** - stdio(本地)、SSE(远程/实时)、HTTP(兼容)
@@ -87,6 +88,11 @@ Node.js(包括 Windows 上未加入 PATH 的 `node.exe`),必要时才回
87
88
  /reload-plugins
88
89
  ```
89
90
 
91
+ 上述 marketplace 只用于从仓库源码验证。正式 WorkBuddy 市场发布 ZIP 直接以插件内容为根,
92
+ 不包含额外的 `taptap-maker/` 或 `plugins/workbuddy/taptap-maker/` 目录;根目录包含
93
+ `.codebuddy-plugin/plugin.json`、`.mcp.json`、`README.md` 和 `SKILL.md`,所有文件的父目录深度
94
+ 最多为两层。普通用户通过 WorkBuddy 官方插件市场安装,不把发布 ZIP 当成本地 marketplace。
95
+
90
96
  WorkBuddy 旧独立 MCP 的迁移使用 `--client workbuddy`,只把旧注册的 `disabled` 设为 `true`,
91
97
  同时支持幂等检查和确认式恢复。插件更新通过 WorkBuddy `/plugin` 完成。
92
98
 
@@ -142,6 +148,7 @@ taptap-maker upgrade
142
148
  taptap-maker mcp verify
143
149
  npx -y --package @taptap/maker@<exact-version> taptap-maker mcp report --ide <client> --target-dir <project> --context-stdin --consent --json
144
150
  taptap-maker dev-kit update
151
+ taptap-maker user-skills pull --target-dir <project>
145
152
  ```
146
153
 
147
154
  普通初始化、clone、下载或拉取远端项目的标准命令是 `taptap-maker init`,CLI 会展示 app 列表,
@@ -216,6 +223,11 @@ MCP 进程自身的 cwd 只作为最后兜底和诊断信息,不应通过重
216
223
  和 `taptap-maker doctor` 会检查老项目 `AGENTS.md` 是否缺失或过期,并提示运行
217
224
  `taptap-maker agents update` 或 `taptap-maker upgrade`。
218
225
  `taptap-maker dev-kit update` 会检查当前环境可用的最新 AI dev kit 并更新当前目录。
226
+ `taptap-maker user-skills pull` 是可选的边缘命令,仅在用户明确要求时从 Maker Server 下载个人
227
+ Skill,并覆盖项目 `.installer/skills/` 中 ZIP 包含的同名目录,再以原始 Skill 名称安装到项目内
228
+ `.codex/skills/`、`.cursor/skills/` 和 `.workbuddy/skills/`;其它本地 Skill 保持不变。
229
+ 归档下载限制为 64 MiB,最多 1000 个条目、解压后最多 128 MiB。
230
+ 该命令不属于正常开发或初始化流程,也不会增加 MCP tool。
219
231
 
220
232
  如果 Maker MCP tools 缺失或出现 `-32000` / `Connection closed`,先按
221
233
  [TapTap Maker MCP 本地连接自检与修复指引](docs/MAKER_MCP_CONNECTION_TROUBLESHOOTING.md)
@@ -253,9 +265,10 @@ Maker MCP 初始化时会通过标准 `initialize.instructions` 向 AI 客户端
253
265
  检查实现”不应自动触发 Maker 远端构建,除非用户明确要求构建、运行或预览 Maker 游戏。
254
266
  普通构建会先 push 到 Maker 远端再触发远端 build:本地有改动时提交改动,已有未推送 commit 时
255
267
  直接 push,本地干净且没有未推送 commit 时创建 `chore: wake maker build server` 空提交来唤醒远端
256
- 服务。push 失败时不会继续 build,会返回本地 commit、ahead 状态、stderr/stdout 和下一步建议,
257
- 交给本地 Agent/skill 处理 pull、rebase 或冲突;push 成功但 build 失败时,会明确说明代码已到
258
- Maker 远端但构建失败。只有用户明确说“不提交,只构建云端版本”时,才传
268
+ 服务。提交前如果本地仅落后于 Maker 远端,会自动执行 fast-forward 后继续提交;如果远端更新会
269
+ 覆盖本地未提交修改,则会在创建 commit 前停止并保留本地文件。分叉、非 `main`、鉴权或网络失败仍
270
+ 按原有提示处理。push 成功但 build 失败时,会明确说明代码已到 Maker 远端但构建失败。只有用户明确
271
+ 说“不提交,只构建云端版本”时,才传
259
272
  `confirm_remote_build_without_submit=true`;该模式只构建 Maker 远端已提交版本,不会自动打开
260
273
  Maker 页面。
261
274
 
@@ -468,7 +481,7 @@ curl http://localhost:5002/health # RND
468
481
  #### H5 游戏管理 (3)
469
482
 
470
483
  - `prepare_h5_upload` - 收集 H5 游戏信息(上传前)
471
- - `upload_h5_game` - 上传 H5 游戏包
484
+ - `upload_h5_game` - 上传 H5 游戏包;首次上传未设置横竖屏时暂停并要求用户选择,提交后校验服务端方向
472
485
  - `get_debug_feedbacks` - 拉取用户调试反馈并下载日志/截图
473
486
 
474
487
  #### 振动 API 文档 (1)
@@ -567,6 +580,10 @@ maker_build_current_directory
567
580
  远端 proxy tools 使用版本化的本地完整定义在首次 `tools/list` 时立即注册,不等待 cwd、Maker 项目绑定、
568
581
  PAT/TapTap token 或远端 proxy 连接。项目定位和鉴权只在实际调用 tool 时校验;远端 schema 不会在运行时
569
582
  替换本地定义。schema 变更通过本地 MCP 版本更新发布,远端不可用不会让 proxy tools 从当前会话消失。
583
+ 唯一例外是 Maker Server 明确返回 `BLACKLISTED` 的账号:MCP 每个进程启动时只检查一次账号状态,
584
+ `tools/list` 只保留 `maker_status_lite`,任何 tool call 和 `maker://status` 都直接返回限制提示,不进入
585
+ 本地构建或远端 proxy。PAT 缺失、过期、网络超时和其它非黑名单错误不会隐藏工具;账号状态变化需要
586
+ 重连或重启 MCP 后生效。
570
587
  Maker 内嵌代理不打开可选的 standalone SSE GET,远端 RPC 响应和构建进度统一通过 POST SSE 返回;
571
588
  这避免 Node.js 26 中长连接占用后续 `tools/list` 请求而触发固定 60 秒超时。普通 MCP Proxy 默认仍保留
572
589
  standalone SSE,只有显式设置 `disable_standalone_sse` 才会关闭。
@@ -739,7 +756,8 @@ graph LR
739
756
 
740
757
  - **[docs/ARCHITECTURE.md](docs/ARCHITECTURE.md)** - 架构文档
741
758
  - **[docs/DEPLOYMENT.md](docs/DEPLOYMENT.md)** - 部署指南(本地、Docker、开发者测试)
742
- - **[docs/PROXY.md](docs/PROXY.md)** - MCP Proxy 开发指南(面向 TapCode 等平台)
759
+ - **[docs/PROXY.md](docs/PROXY.md)** - MCP Proxy 开发指南(面向 TapCode 等平台)。
760
+ 通用 Proxy 默认不添加 `local` 来源标记;本地 Maker 嵌入入口显式启用,服务端无需修改配置。
743
761
  - **[docs/PATH_RESOLUTION.md](docs/PATH_RESOLUTION.md)** - 路径解析系统
744
762
 
745
763
  ## Maker 持久化 Proxy 与多项目
package/dist/proxy.js CHANGED
@@ -29151,7 +29151,7 @@ var LogWriter = class {
29151
29151
  };
29152
29152
 
29153
29153
  // src/mcp-proxy/config.ts
29154
- var DEFAULT_TOOL_CALL_TIMEOUT_MS = 60 * 60 * 1e3;
29154
+ var DEFAULT_TOOL_CALL_TIMEOUT_MS = 5 * 60 * 1e3;
29155
29155
  function readStdin() {
29156
29156
  return new Promise((resolve, reject) => {
29157
29157
  const chunks = [];
@@ -29306,8 +29306,7 @@ function applyDefaults(config2) {
29306
29306
  }
29307
29307
 
29308
29308
  // src/mcp-proxy/proxy.ts
29309
- var VERSION = true ? "1.24.12" : "dev";
29310
- var LOCAL_PROXY_TAG = "local";
29309
+ var VERSION = true ? "1.24.14" : "dev";
29311
29310
  var DEFAULT_RECONNECT_INTERVAL_MS = 5e3;
29312
29311
  var MAX_RECONNECT_INTERVAL_MS = 60 * 1e3;
29313
29312
  function createNonReplayableToolResult(name, executionState) {
@@ -29369,20 +29368,23 @@ function isHttpClientError(error2) {
29369
29368
  return numericCode !== void 0 && numericCode >= 400 && numericCode < 500 || /\bHTTP\s+4\d\d\b/i.test(error2.message);
29370
29369
  }
29371
29370
  var TapTapMCPProxy = class {
29372
- constructor(config2) {
29371
+ constructor(config2, runtimeOptions = {}) {
29373
29372
  this.connected = false;
29374
29373
  this.reconnecting = false;
29375
29374
  this.reconnectTimer = null;
29376
29375
  this.healthCheckTimer = null;
29377
29376
  this.pendingRequests = [];
29378
- this.reconnectDelayMs = DEFAULT_RECONNECT_INTERVAL_MS;
29379
29377
  // 会话验证相关
29380
29378
  this.sessionValidated = false;
29381
29379
  this.lastValidationTime = 0;
29382
29380
  this.SESSION_VALIDATION_INTERVAL = 3e4;
29383
- var _a3;
29381
+ var _a3, _b;
29384
29382
  this.config = config2;
29385
- this.cookieJar = new CookieJar(((_a3 = config2.options) == null ? void 0 : _a3.verbose) ?? false);
29383
+ this.sourceTag = runtimeOptions.sourceTag;
29384
+ this.remoteErrorMode = runtimeOptions.remoteErrorMode ?? "passthrough";
29385
+ this.recoveryMode = runtimeOptions.recoveryMode ?? "compatible";
29386
+ this.reconnectDelayMs = ((_a3 = config2.options) == null ? void 0 : _a3.reconnect_interval) ?? DEFAULT_RECONNECT_INTERVAL_MS;
29387
+ this.cookieJar = new CookieJar(((_b = config2.options) == null ? void 0 : _b.verbose) ?? false);
29386
29388
  this.logWriter = this.createLogWriter();
29387
29389
  this.client = this.createClient();
29388
29390
  this.server = new Server(
@@ -29480,11 +29482,13 @@ var TapTapMCPProxy = class {
29480
29482
  * - X-TapTap-Project-Path: 项目路径
29481
29483
  * - X-TapTap-Mac-Token: MAC 认证令牌(JSON)
29482
29484
  * - X-TapTap-Custom-Fields: 业务自定义字段(JSON)
29483
- * - X-TapTap-Tag: 调用来源标记,固定为 "local"
29485
+ * - X-TapTap-Tag: 调用来源标记,仅在嵌入入口显式启用时发送
29484
29486
  */
29485
29487
  buildSessionHeaders() {
29486
29488
  const headers = {};
29487
- headers["X-TapTap-Tag"] = LOCAL_PROXY_TAG;
29489
+ if (this.sourceTag !== void 0) {
29490
+ headers["X-TapTap-Tag"] = this.sourceTag;
29491
+ }
29488
29492
  if (this.config.tenant.user_id) {
29489
29493
  headers["X-TapTap-User-Id"] = this.config.tenant.user_id;
29490
29494
  }
@@ -29512,12 +29516,14 @@ var TapTapMCPProxy = class {
29512
29516
  * - _project_id: 项目标识(可选)
29513
29517
  * - _project_path: 项目路径(可选)
29514
29518
  * - _custom_fields: 业务自定义字段(可选)
29515
- * - _tag: 调用来源标记,固定为 "local"
29519
+ * - _tag: 调用来源标记,仅在嵌入入口显式启用时注入
29516
29520
  */
29517
29521
  injectPrivateParams(args) {
29518
29522
  const injected = { ...args || {} };
29519
29523
  injected._mac_token = this.config.auth;
29520
- injected._tag = LOCAL_PROXY_TAG;
29524
+ if (this.sourceTag !== void 0) {
29525
+ injected._tag = this.sourceTag;
29526
+ }
29521
29527
  if (this.config.tenant.user_id) {
29522
29528
  injected._user_id = this.config.tenant.user_id;
29523
29529
  }
@@ -29568,6 +29574,18 @@ var TapTapMCPProxy = class {
29568
29574
  const replayableTools = (_a3 = this.config.options) == null ? void 0 : _a3.replayable_tools;
29569
29575
  return replayableTools === void 0 || replayableTools.includes(name);
29570
29576
  }
29577
+ toolErrorResult(error2) {
29578
+ return this.remoteErrorMode === "tool-result" ? convertMcpApplicationErrorToToolResult(error2) : void 0;
29579
+ }
29580
+ shouldReplayToolFailure(name, error2) {
29581
+ if (!this.isToolReplayable(name) || !(error2 instanceof Error)) return false;
29582
+ if (this.recoveryMode === "resilient") return true;
29583
+ if (this.isSessionInvalidError(error2) || error2.message.toLowerCase().includes("not connected")) {
29584
+ return true;
29585
+ }
29586
+ const code = error2.code;
29587
+ return !isTransientHttpServerError(error2) && code !== ErrorCode.ConnectionClosed && code !== ErrorCode.RequestTimeout;
29588
+ }
29571
29589
  /**
29572
29590
  * 连接到 TapTap MCP Server
29573
29591
  */
@@ -29604,8 +29622,13 @@ var TapTapMCPProxy = class {
29604
29622
  this.log("info", "✅ Connected and session validated");
29605
29623
  this.startHealthCheck();
29606
29624
  if (this.reconnecting) {
29625
+ if (this.recoveryMode === "compatible") {
29626
+ await this.notifyReconnected();
29627
+ }
29607
29628
  await this.processPendingRequests();
29608
- await this.notifyReconnected();
29629
+ if (this.recoveryMode === "resilient") {
29630
+ await this.notifyReconnected();
29631
+ }
29609
29632
  this.reconnecting = false;
29610
29633
  }
29611
29634
  } catch (error2) {
@@ -29760,15 +29783,17 @@ var TapTapMCPProxy = class {
29760
29783
  var _a3, _b, _c;
29761
29784
  this.clearReconnectTimer();
29762
29785
  const configuredInterval = ((_a3 = this.config.options) == null ? void 0 : _a3.reconnect_interval) ?? DEFAULT_RECONNECT_INTERVAL_MS;
29763
- const interval = this.reconnectDelayMs || configuredInterval;
29786
+ const interval = this.recoveryMode === "resilient" ? this.reconnectDelayMs : configuredInterval;
29764
29787
  this.reconnectTimer = setTimeout(() => {
29765
29788
  this.reconnectToServer();
29766
29789
  }, interval);
29767
29790
  (_c = (_b = this.reconnectTimer).unref) == null ? void 0 : _c.call(_b);
29768
- this.reconnectDelayMs = Math.min(
29769
- Math.max(interval * 2, configuredInterval),
29770
- MAX_RECONNECT_INTERVAL_MS
29771
- );
29791
+ if (this.recoveryMode === "resilient") {
29792
+ this.reconnectDelayMs = Math.min(
29793
+ Math.max(interval * 2, configuredInterval),
29794
+ Math.max(MAX_RECONNECT_INTERVAL_MS, configuredInterval)
29795
+ );
29796
+ }
29772
29797
  }
29773
29798
  /**
29774
29799
  * 清除重连定时器
@@ -29809,15 +29834,18 @@ var TapTapMCPProxy = class {
29809
29834
  * 检测是否是需要重连的错误(网络错误或会话无效)
29810
29835
  */
29811
29836
  isNetworkError(error2) {
29837
+ var _a3;
29812
29838
  if (!(error2 instanceof Error)) return false;
29813
29839
  if (convertMcpApplicationErrorToToolResult(error2)) {
29814
29840
  return false;
29815
29841
  }
29816
29842
  if (isHttpClientError(error2)) {
29817
- return false;
29818
- }
29819
- if (isTransientHttpServerError(error2)) {
29820
- return true;
29843
+ if (this.isMcpApplicationError(error2)) {
29844
+ return false;
29845
+ }
29846
+ const code = error2.code;
29847
+ const status = typeof code === "number" && code >= 400 && code < 500 ? code : typeof code === "string" && /^4\d\d$/.test(code) ? Number(code) : Number((_a3 = error2.message.match(/\bHTTP\s+(4\d\d)\b/i)) == null ? void 0 : _a3[1]);
29848
+ return (status === 400 || status === 404) && this.isSessionInvalidError(error2);
29821
29849
  }
29822
29850
  const errorMsg = error2.message.toLowerCase();
29823
29851
  const errorCode = error2.code;
@@ -29845,11 +29873,14 @@ var TapTapMCPProxy = class {
29845
29873
  if (errorCode === ErrorCode.ConnectionClosed || errorCode === ErrorCode.RequestTimeout) {
29846
29874
  return true;
29847
29875
  }
29876
+ if (this.isMcpApplicationError(error2)) {
29877
+ return false;
29878
+ }
29848
29879
  if (errorMsg.includes("not connected") || this.isSessionInvalidError(error2)) {
29849
29880
  return true;
29850
29881
  }
29851
- if (this.isMcpApplicationError(error2)) {
29852
- return false;
29882
+ if (isTransientHttpServerError(error2)) {
29883
+ return true;
29853
29884
  }
29854
29885
  const networkErrorKeywords = [
29855
29886
  "fetch failed",
@@ -29876,7 +29907,6 @@ var TapTapMCPProxy = class {
29876
29907
  async processPendingRequests() {
29877
29908
  var _a3, _b, _c;
29878
29909
  const timeout = ((_a3 = this.config.options) == null ? void 0 : _a3.request_timeout) ?? 3e4;
29879
- const now = Date.now();
29880
29910
  this.log("info", `Processing ${this.pendingRequests.length} pending requests...`);
29881
29911
  while (this.pendingRequests.length > 0) {
29882
29912
  const req = this.pendingRequests.shift();
@@ -29884,7 +29914,7 @@ var TapTapMCPProxy = class {
29884
29914
  req.resolve(createNonReplayableToolResult(req.name, req.executionState ?? "unknown"));
29885
29915
  continue;
29886
29916
  }
29887
- if (now - req.timestamp > timeout) {
29917
+ if (Date.now() - req.timestamp > timeout) {
29888
29918
  req.reject(new Error("Request timeout while waiting for reconnection"));
29889
29919
  continue;
29890
29920
  }
@@ -29904,7 +29934,7 @@ var TapTapMCPProxy = class {
29904
29934
  );
29905
29935
  req.resolve(result);
29906
29936
  } catch (error2) {
29907
- const toolErrorResult = convertMcpApplicationErrorToToolResult(error2);
29937
+ const toolErrorResult = this.toolErrorResult(error2);
29908
29938
  if (toolErrorResult) {
29909
29939
  req.resolve(toolErrorResult);
29910
29940
  continue;
@@ -29912,7 +29942,11 @@ var TapTapMCPProxy = class {
29912
29942
  if (this.isNetworkError(error2)) {
29913
29943
  this.connected = false;
29914
29944
  this.sessionValidated = false;
29915
- this.pendingRequests.unshift(req);
29945
+ if (this.recoveryMode === "resilient") {
29946
+ this.pendingRequests.unshift(req);
29947
+ } else {
29948
+ req.reject(error2);
29949
+ }
29916
29950
  throw error2;
29917
29951
  }
29918
29952
  req.reject(error2 instanceof Error ? error2 : new Error(String(error2)));
@@ -30051,19 +30085,23 @@ var TapTapMCPProxy = class {
30051
30085
  );
30052
30086
  return result;
30053
30087
  } catch (error2) {
30054
- const toolErrorResult = convertMcpApplicationErrorToToolResult(error2);
30088
+ const toolErrorResult = this.toolErrorResult(error2);
30055
30089
  if (toolErrorResult) {
30056
30090
  return toolErrorResult;
30057
30091
  }
30058
30092
  if (this.isNetworkError(error2)) {
30059
30093
  this.log("error", "❌ Network error detected, marking connection as lost");
30060
30094
  this.connected = false;
30095
+ this.sessionValidated = false;
30061
30096
  if (!this.reconnecting) {
30062
30097
  this.log("info", "Triggering immediate reconnection...");
30063
30098
  this.reconnectToServer();
30064
30099
  if (!this.isToolReplayable(name)) {
30065
30100
  return createNonReplayableToolResult(name, "unknown");
30066
30101
  }
30102
+ if (!this.shouldReplayToolFailure(name, error2)) {
30103
+ throw error2;
30104
+ }
30067
30105
  this.log("info", `⏳ Queueing current request: ${name}`);
30068
30106
  return new Promise((resolve, reject) => {
30069
30107
  this.pendingRequests.push({