@mikoto_zero/minigame-open-mcp 1.11.0 → 1.11.2
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 +6 -3
- package/dist/proxy.js +84 -6
- package/dist/server.js +546 -120
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -19,6 +19,8 @@
|
|
|
19
19
|
|
|
20
20
|
## 🚀 快速开始
|
|
21
21
|
|
|
22
|
+
> 🐣 **新手请看这里**:[TapTap MCP 配置指南 (小白版)](docs/USER_GUIDE.md) - 手把手教你配置 Cursor、Claude Code 和 VS Code。
|
|
23
|
+
|
|
22
24
|
### 安装
|
|
23
25
|
|
|
24
26
|
```bash
|
|
@@ -42,7 +44,7 @@ npx @mikoto_zero/minigame-open-mcp
|
|
|
42
44
|
"command": "npx",
|
|
43
45
|
"args": ["-y", "@mikoto_zero/minigame-open-mcp"],
|
|
44
46
|
"env": {
|
|
45
|
-
"
|
|
47
|
+
"TAPTAP_MCP_WORKSPACE_ROOT": "${workspaceFolder}"
|
|
46
48
|
}
|
|
47
49
|
}
|
|
48
50
|
}
|
|
@@ -52,9 +54,9 @@ npx @mikoto_zero/minigame-open-mcp
|
|
|
52
54
|
**重要说明**:
|
|
53
55
|
|
|
54
56
|
- **零配置 OAuth**:首次使用会提示扫码授权,token 自动保存!
|
|
55
|
-
- **路径处理**:设置 `
|
|
57
|
+
- **路径处理**:设置 `TAPTAP_MCP_WORKSPACE_ROOT` 环境变量可以正确解析相对路径(推荐)
|
|
56
58
|
- 如果不设置,相对路径会基于用户 HOME 目录(可能不符合预期)
|
|
57
|
-
- 建议使用绝对路径,或配置 `
|
|
59
|
+
- 建议使用绝对路径,或配置 `TAPTAP_MCP_WORKSPACE_ROOT`
|
|
58
60
|
|
|
59
61
|
#### OpenHands(推荐 SSE 模式)
|
|
60
62
|
|
|
@@ -311,6 +313,7 @@ graph LR
|
|
|
311
313
|
|
|
312
314
|
### 用户文档
|
|
313
315
|
|
|
316
|
+
- **[docs/USER_GUIDE.md](docs/USER_GUIDE.md)** - 🐣 新手配置指南(Cursor/VS Code/Claude Code)
|
|
314
317
|
- **[CONTRIBUTING.md](CONTRIBUTING.md)** - 贡献指南
|
|
315
318
|
- **[CHANGELOG.md](CHANGELOG.md)** - 版本变更历史
|
|
316
319
|
|
package/dist/proxy.js
CHANGED
|
@@ -13389,13 +13389,19 @@ var StreamableHTTPClientTransport = class {
|
|
|
13389
13389
|
};
|
|
13390
13390
|
|
|
13391
13391
|
// src/mcp-proxy/proxy.ts
|
|
13392
|
-
var VERSION = true ? "1.11.
|
|
13392
|
+
var VERSION = true ? "1.11.2" : "dev";
|
|
13393
13393
|
var TapTapMCPProxy = class {
|
|
13394
|
+
// 30秒验证一次会话
|
|
13394
13395
|
constructor(config) {
|
|
13395
13396
|
this.connected = false;
|
|
13396
13397
|
this.reconnecting = false;
|
|
13397
13398
|
this.reconnectTimer = null;
|
|
13399
|
+
this.healthCheckTimer = null;
|
|
13398
13400
|
this.pendingRequests = [];
|
|
13401
|
+
// 会话验证相关
|
|
13402
|
+
this.sessionValidated = false;
|
|
13403
|
+
this.lastValidationTime = 0;
|
|
13404
|
+
this.SESSION_VALIDATION_INTERVAL = 3e4;
|
|
13399
13405
|
this.config = config;
|
|
13400
13406
|
this.client = new Client(
|
|
13401
13407
|
{ name: "taptap-proxy-client", version: "1.0.0" },
|
|
@@ -13439,8 +13445,12 @@ var TapTapMCPProxy = class {
|
|
|
13439
13445
|
try {
|
|
13440
13446
|
const transport = new StreamableHTTPClientTransport(new URL(this.config.server.url));
|
|
13441
13447
|
await this.client.connect(transport);
|
|
13448
|
+
await this.validateSession();
|
|
13442
13449
|
this.connected = true;
|
|
13443
|
-
|
|
13450
|
+
this.sessionValidated = true;
|
|
13451
|
+
this.lastValidationTime = Date.now();
|
|
13452
|
+
console.error("[Proxy] ✅ Connected and session validated");
|
|
13453
|
+
this.startHealthCheck();
|
|
13444
13454
|
if (this.reconnecting) {
|
|
13445
13455
|
await this.notifyReconnected();
|
|
13446
13456
|
await this.processPendingRequests();
|
|
@@ -13448,9 +13458,75 @@ var TapTapMCPProxy = class {
|
|
|
13448
13458
|
}
|
|
13449
13459
|
} catch (error) {
|
|
13450
13460
|
this.connected = false;
|
|
13461
|
+
this.sessionValidated = false;
|
|
13451
13462
|
throw error;
|
|
13452
13463
|
}
|
|
13453
13464
|
}
|
|
13465
|
+
/**
|
|
13466
|
+
* 验证 MCP 会话是否有效
|
|
13467
|
+
* 通过调用 listTools 来验证 Server 端的 MCP 会话状态
|
|
13468
|
+
*/
|
|
13469
|
+
async validateSession() {
|
|
13470
|
+
console.error("[Proxy] Validating MCP session...");
|
|
13471
|
+
try {
|
|
13472
|
+
await this.client.listTools();
|
|
13473
|
+
console.error("[Proxy] ✅ Session validation successful");
|
|
13474
|
+
} catch (error) {
|
|
13475
|
+
console.error("[Proxy] ❌ Session validation failed:", error);
|
|
13476
|
+
if (this.isSessionInvalidError(error)) {
|
|
13477
|
+
throw new Error("Server session not initialized - need to reconnect");
|
|
13478
|
+
}
|
|
13479
|
+
throw error;
|
|
13480
|
+
}
|
|
13481
|
+
}
|
|
13482
|
+
/**
|
|
13483
|
+
* 检测是否是会话无效错误(Server 未初始化)
|
|
13484
|
+
*/
|
|
13485
|
+
isSessionInvalidError(error) {
|
|
13486
|
+
if (!(error instanceof Error)) return false;
|
|
13487
|
+
const errorMsg = error.message.toLowerCase();
|
|
13488
|
+
const sessionInvalidKeywords = [
|
|
13489
|
+
"server not initialized",
|
|
13490
|
+
"not initialized",
|
|
13491
|
+
"session not found",
|
|
13492
|
+
"session expired",
|
|
13493
|
+
"invalid session",
|
|
13494
|
+
"no active session"
|
|
13495
|
+
];
|
|
13496
|
+
return sessionInvalidKeywords.some((keyword) => errorMsg.includes(keyword));
|
|
13497
|
+
}
|
|
13498
|
+
/**
|
|
13499
|
+
* 启动定期健康检查
|
|
13500
|
+
*/
|
|
13501
|
+
startHealthCheck() {
|
|
13502
|
+
var _a2;
|
|
13503
|
+
this.stopHealthCheck();
|
|
13504
|
+
const interval = ((_a2 = this.config.options) == null ? void 0 : _a2.health_check_interval) ?? this.SESSION_VALIDATION_INTERVAL;
|
|
13505
|
+
this.healthCheckTimer = setInterval(async () => {
|
|
13506
|
+
if (!this.connected || this.reconnecting) return;
|
|
13507
|
+
try {
|
|
13508
|
+
await this.validateSession();
|
|
13509
|
+
this.lastValidationTime = Date.now();
|
|
13510
|
+
} catch (error) {
|
|
13511
|
+
console.error("[Proxy] ❌ Health check failed, triggering reconnection");
|
|
13512
|
+
this.connected = false;
|
|
13513
|
+
this.sessionValidated = false;
|
|
13514
|
+
if (!this.reconnecting) {
|
|
13515
|
+
this.reconnectToServer();
|
|
13516
|
+
}
|
|
13517
|
+
}
|
|
13518
|
+
}, interval);
|
|
13519
|
+
console.error(`[Proxy] Health check started (interval: ${interval}ms)`);
|
|
13520
|
+
}
|
|
13521
|
+
/**
|
|
13522
|
+
* 停止健康检查
|
|
13523
|
+
*/
|
|
13524
|
+
stopHealthCheck() {
|
|
13525
|
+
if (this.healthCheckTimer) {
|
|
13526
|
+
clearInterval(this.healthCheckTimer);
|
|
13527
|
+
this.healthCheckTimer = null;
|
|
13528
|
+
}
|
|
13529
|
+
}
|
|
13454
13530
|
/**
|
|
13455
13531
|
* 重连到 TapTap Server
|
|
13456
13532
|
*/
|
|
@@ -13495,6 +13571,7 @@ var TapTapMCPProxy = class {
|
|
|
13495
13571
|
* 清理资源(公开方法,供进程退出时调用)
|
|
13496
13572
|
*/
|
|
13497
13573
|
cleanup() {
|
|
13574
|
+
this.stopHealthCheck();
|
|
13498
13575
|
if (this.reconnectTimer) {
|
|
13499
13576
|
clearTimeout(this.reconnectTimer);
|
|
13500
13577
|
this.reconnectTimer = null;
|
|
@@ -13506,7 +13583,7 @@ var TapTapMCPProxy = class {
|
|
|
13506
13583
|
}
|
|
13507
13584
|
}
|
|
13508
13585
|
/**
|
|
13509
|
-
*
|
|
13586
|
+
* 检测是否是需要重连的错误(网络错误或会话无效)
|
|
13510
13587
|
*/
|
|
13511
13588
|
isNetworkError(error) {
|
|
13512
13589
|
if (!(error instanceof Error)) return false;
|
|
@@ -13541,12 +13618,13 @@ var TapTapMCPProxy = class {
|
|
|
13541
13618
|
"connection reset",
|
|
13542
13619
|
"timeout",
|
|
13543
13620
|
"dns",
|
|
13544
|
-
"server not initialized",
|
|
13545
|
-
// MCP SDK Server 未初始化(重启后会话丢失)
|
|
13546
13621
|
"not connected"
|
|
13547
13622
|
// 连接断开
|
|
13548
13623
|
];
|
|
13549
|
-
|
|
13624
|
+
if (networkErrorKeywords.some((keyword) => errorMsg.includes(keyword))) {
|
|
13625
|
+
return true;
|
|
13626
|
+
}
|
|
13627
|
+
return this.isSessionInvalidError(error);
|
|
13550
13628
|
}
|
|
13551
13629
|
/**
|
|
13552
13630
|
* 处理待处理的请求队列
|