@mikoto_zero/minigame-open-mcp 1.11.2 → 1.11.4
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/dist/proxy.js +250 -5
- package/dist/server.js +1 -1
- package/package.json +1 -1
package/dist/proxy.js
CHANGED
|
@@ -13388,10 +13388,187 @@ var StreamableHTTPClientTransport = class {
|
|
|
13388
13388
|
}
|
|
13389
13389
|
};
|
|
13390
13390
|
|
|
13391
|
+
// src/mcp-proxy/cookieJar.ts
|
|
13392
|
+
var CookieJar = class {
|
|
13393
|
+
constructor(verbose = false) {
|
|
13394
|
+
this.cookies = /* @__PURE__ */ new Map();
|
|
13395
|
+
this.verbose = verbose;
|
|
13396
|
+
}
|
|
13397
|
+
/**
|
|
13398
|
+
* 从响应的 Set-Cookie 头中提取并存储 Cookie
|
|
13399
|
+
*/
|
|
13400
|
+
setCookiesFromResponse(response) {
|
|
13401
|
+
const setCookieHeaders = this.getSetCookieHeaders(response);
|
|
13402
|
+
for (const setCookieHeader of setCookieHeaders) {
|
|
13403
|
+
const cookie = this.parseSetCookie(setCookieHeader);
|
|
13404
|
+
if (cookie) {
|
|
13405
|
+
if (cookie.expires && cookie.expires < /* @__PURE__ */ new Date()) {
|
|
13406
|
+
this.cookies.delete(cookie.name);
|
|
13407
|
+
if (this.verbose) {
|
|
13408
|
+
console.error(`[CookieJar] Cookie expired and removed: ${cookie.name}`);
|
|
13409
|
+
}
|
|
13410
|
+
} else {
|
|
13411
|
+
this.cookies.set(cookie.name, cookie);
|
|
13412
|
+
if (this.verbose) {
|
|
13413
|
+
console.error(
|
|
13414
|
+
`[CookieJar] Cookie stored: ${cookie.name}=${cookie.value.substring(0, 20)}...`
|
|
13415
|
+
);
|
|
13416
|
+
}
|
|
13417
|
+
}
|
|
13418
|
+
}
|
|
13419
|
+
}
|
|
13420
|
+
}
|
|
13421
|
+
/**
|
|
13422
|
+
* 获取所有 Set-Cookie 头
|
|
13423
|
+
*/
|
|
13424
|
+
getSetCookieHeaders(response) {
|
|
13425
|
+
const headers = response.headers;
|
|
13426
|
+
if (typeof headers.getSetCookie === "function") {
|
|
13427
|
+
return headers.getSetCookie();
|
|
13428
|
+
}
|
|
13429
|
+
const setCookie = headers.get("set-cookie");
|
|
13430
|
+
if (setCookie) {
|
|
13431
|
+
return this.splitSetCookieHeader(setCookie);
|
|
13432
|
+
}
|
|
13433
|
+
return [];
|
|
13434
|
+
}
|
|
13435
|
+
/**
|
|
13436
|
+
* 分割 Set-Cookie 头(处理多个 Cookie 合并的情况)
|
|
13437
|
+
*/
|
|
13438
|
+
splitSetCookieHeader(header) {
|
|
13439
|
+
const cookies = [];
|
|
13440
|
+
let current = "";
|
|
13441
|
+
for (let i = 0; i < header.length; i++) {
|
|
13442
|
+
const char = header[i];
|
|
13443
|
+
if (char === ",") {
|
|
13444
|
+
const remaining = header.substring(i + 1).trim();
|
|
13445
|
+
if (/^\d{2}\s(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)/i.test(remaining)) {
|
|
13446
|
+
current += char;
|
|
13447
|
+
continue;
|
|
13448
|
+
}
|
|
13449
|
+
if (current.trim()) {
|
|
13450
|
+
cookies.push(current.trim());
|
|
13451
|
+
}
|
|
13452
|
+
current = "";
|
|
13453
|
+
} else {
|
|
13454
|
+
current += char;
|
|
13455
|
+
}
|
|
13456
|
+
}
|
|
13457
|
+
if (current.trim()) {
|
|
13458
|
+
cookies.push(current.trim());
|
|
13459
|
+
}
|
|
13460
|
+
return cookies;
|
|
13461
|
+
}
|
|
13462
|
+
/**
|
|
13463
|
+
* 解析 Set-Cookie 头
|
|
13464
|
+
*/
|
|
13465
|
+
parseSetCookie(setCookieHeader) {
|
|
13466
|
+
const parts = setCookieHeader.split(";").map((p) => p.trim());
|
|
13467
|
+
if (parts.length === 0) return null;
|
|
13468
|
+
const [nameValue, ...attributes] = parts;
|
|
13469
|
+
const eqIndex = nameValue.indexOf("=");
|
|
13470
|
+
if (eqIndex === -1) return null;
|
|
13471
|
+
const name = nameValue.substring(0, eqIndex).trim();
|
|
13472
|
+
const value = nameValue.substring(eqIndex + 1).trim();
|
|
13473
|
+
if (!name) return null;
|
|
13474
|
+
const cookie = { name, value };
|
|
13475
|
+
for (const attr of attributes) {
|
|
13476
|
+
const attrLower = attr.toLowerCase();
|
|
13477
|
+
if (attrLower.startsWith("expires=")) {
|
|
13478
|
+
const dateStr = attr.substring(8);
|
|
13479
|
+
const date = new Date(dateStr);
|
|
13480
|
+
if (!isNaN(date.getTime())) {
|
|
13481
|
+
cookie.expires = date;
|
|
13482
|
+
}
|
|
13483
|
+
} else if (attrLower.startsWith("max-age=")) {
|
|
13484
|
+
const maxAge = parseInt(attr.substring(8), 10);
|
|
13485
|
+
if (!isNaN(maxAge)) {
|
|
13486
|
+
cookie.maxAge = maxAge;
|
|
13487
|
+
cookie.expires = new Date(Date.now() + maxAge * 1e3);
|
|
13488
|
+
}
|
|
13489
|
+
} else if (attrLower.startsWith("domain=")) {
|
|
13490
|
+
cookie.domain = attr.substring(7);
|
|
13491
|
+
} else if (attrLower.startsWith("path=")) {
|
|
13492
|
+
cookie.path = attr.substring(5);
|
|
13493
|
+
} else if (attrLower === "secure") {
|
|
13494
|
+
cookie.secure = true;
|
|
13495
|
+
} else if (attrLower === "httponly") {
|
|
13496
|
+
cookie.httpOnly = true;
|
|
13497
|
+
} else if (attrLower.startsWith("samesite=")) {
|
|
13498
|
+
const sameSite = attr.substring(9);
|
|
13499
|
+
if (["Strict", "Lax", "None"].includes(sameSite)) {
|
|
13500
|
+
cookie.sameSite = sameSite;
|
|
13501
|
+
}
|
|
13502
|
+
}
|
|
13503
|
+
}
|
|
13504
|
+
return cookie;
|
|
13505
|
+
}
|
|
13506
|
+
/**
|
|
13507
|
+
* 生成 Cookie 请求头值
|
|
13508
|
+
*/
|
|
13509
|
+
getCookieHeader() {
|
|
13510
|
+
this.cleanExpiredCookies();
|
|
13511
|
+
if (this.cookies.size === 0) return void 0;
|
|
13512
|
+
const cookieStr = Array.from(this.cookies.values()).map((cookie) => `${cookie.name}=${cookie.value}`).join("; ");
|
|
13513
|
+
if (this.verbose) {
|
|
13514
|
+
console.error(`[CookieJar] Sending cookies: ${cookieStr.substring(0, 50)}...`);
|
|
13515
|
+
}
|
|
13516
|
+
return cookieStr;
|
|
13517
|
+
}
|
|
13518
|
+
/**
|
|
13519
|
+
* 清理过期的 Cookie
|
|
13520
|
+
*/
|
|
13521
|
+
cleanExpiredCookies() {
|
|
13522
|
+
const now = /* @__PURE__ */ new Date();
|
|
13523
|
+
for (const [name, cookie] of this.cookies.entries()) {
|
|
13524
|
+
if (cookie.expires && cookie.expires < now) {
|
|
13525
|
+
this.cookies.delete(name);
|
|
13526
|
+
if (this.verbose) {
|
|
13527
|
+
console.error(`[CookieJar] Cookie expired: ${name}`);
|
|
13528
|
+
}
|
|
13529
|
+
}
|
|
13530
|
+
}
|
|
13531
|
+
}
|
|
13532
|
+
/**
|
|
13533
|
+
* 清空所有 Cookie(重连时可能需要)
|
|
13534
|
+
*/
|
|
13535
|
+
clear() {
|
|
13536
|
+
this.cookies.clear();
|
|
13537
|
+
if (this.verbose) {
|
|
13538
|
+
console.error("[CookieJar] All cookies cleared");
|
|
13539
|
+
}
|
|
13540
|
+
}
|
|
13541
|
+
/**
|
|
13542
|
+
* 获取当前存储的 Cookie 数量
|
|
13543
|
+
*/
|
|
13544
|
+
get size() {
|
|
13545
|
+
return this.cookies.size;
|
|
13546
|
+
}
|
|
13547
|
+
/**
|
|
13548
|
+
* 检查是否有 Cookie
|
|
13549
|
+
*/
|
|
13550
|
+
get hasCookies() {
|
|
13551
|
+
return this.cookies.size > 0;
|
|
13552
|
+
}
|
|
13553
|
+
};
|
|
13554
|
+
function createCookieFetch(cookieJar) {
|
|
13555
|
+
return async (input, init) => {
|
|
13556
|
+
const modifiedInit = { ...init };
|
|
13557
|
+
const cookieHeader = cookieJar.getCookieHeader();
|
|
13558
|
+
if (cookieHeader) {
|
|
13559
|
+
const headers = new Headers(modifiedInit.headers);
|
|
13560
|
+
headers.set("Cookie", cookieHeader);
|
|
13561
|
+
modifiedInit.headers = headers;
|
|
13562
|
+
}
|
|
13563
|
+
const response = await fetch(input, modifiedInit);
|
|
13564
|
+
cookieJar.setCookiesFromResponse(response);
|
|
13565
|
+
return response;
|
|
13566
|
+
};
|
|
13567
|
+
}
|
|
13568
|
+
|
|
13391
13569
|
// src/mcp-proxy/proxy.ts
|
|
13392
|
-
var VERSION = true ? "1.11.
|
|
13570
|
+
var VERSION = true ? "1.11.4" : "dev";
|
|
13393
13571
|
var TapTapMCPProxy = class {
|
|
13394
|
-
// 30秒验证一次会话
|
|
13395
13572
|
constructor(config) {
|
|
13396
13573
|
this.connected = false;
|
|
13397
13574
|
this.reconnecting = false;
|
|
@@ -13402,7 +13579,9 @@ var TapTapMCPProxy = class {
|
|
|
13402
13579
|
this.sessionValidated = false;
|
|
13403
13580
|
this.lastValidationTime = 0;
|
|
13404
13581
|
this.SESSION_VALIDATION_INTERVAL = 3e4;
|
|
13582
|
+
var _a2;
|
|
13405
13583
|
this.config = config;
|
|
13584
|
+
this.cookieJar = new CookieJar(((_a2 = config.options) == null ? void 0 : _a2.verbose) ?? false);
|
|
13406
13585
|
this.client = new Client(
|
|
13407
13586
|
{ name: "taptap-proxy-client", version: "1.0.0" },
|
|
13408
13587
|
{ capabilities: {} }
|
|
@@ -13416,8 +13595,10 @@ var TapTapMCPProxy = class {
|
|
|
13416
13595
|
* 启动 Proxy
|
|
13417
13596
|
*/
|
|
13418
13597
|
async start() {
|
|
13598
|
+
var _a2;
|
|
13419
13599
|
console.error(`[Proxy] TapTap MCP Proxy v${VERSION}`);
|
|
13420
13600
|
console.error(`[Proxy] Starting...`);
|
|
13601
|
+
console.error(`[Proxy] Server URL: ${this.config.server.url}`);
|
|
13421
13602
|
console.error(`[Proxy] Project Path: ${this.config.tenant.project_path}`);
|
|
13422
13603
|
if (this.config.tenant.user_id) {
|
|
13423
13604
|
console.error(`[Proxy] User ID: ${this.config.tenant.user_id}`);
|
|
@@ -13426,10 +13607,12 @@ var TapTapMCPProxy = class {
|
|
|
13426
13607
|
console.error(`[Proxy] Project ID: ${this.config.tenant.project_id}`);
|
|
13427
13608
|
}
|
|
13428
13609
|
console.error(`[Proxy] Token kid: ${this.config.auth.kid.substring(0, 12)}...`);
|
|
13610
|
+
console.error(`[Proxy] Cookie sticky: ${((_a2 = this.config.options) == null ? void 0 : _a2.enable_cookie_sticky) ?? true}`);
|
|
13429
13611
|
try {
|
|
13430
13612
|
await this.connectToServer();
|
|
13431
13613
|
} catch (error) {
|
|
13432
|
-
console.error("[Proxy] Initial connection failed,
|
|
13614
|
+
console.error("[Proxy] ❌ Initial connection failed:", this.formatError(error));
|
|
13615
|
+
console.error("[Proxy] Will retry in background...");
|
|
13433
13616
|
this.scheduleReconnect();
|
|
13434
13617
|
}
|
|
13435
13618
|
this.setupHandlers();
|
|
@@ -13441,9 +13624,17 @@ var TapTapMCPProxy = class {
|
|
|
13441
13624
|
* 连接到 TapTap MCP Server
|
|
13442
13625
|
*/
|
|
13443
13626
|
async connectToServer() {
|
|
13627
|
+
var _a2, _b;
|
|
13444
13628
|
console.error(`[Proxy] Connecting to ${this.config.server.url}...`);
|
|
13445
13629
|
try {
|
|
13446
|
-
const
|
|
13630
|
+
const cookieEnabled = ((_a2 = this.config.options) == null ? void 0 : _a2.enable_cookie_sticky) ?? true;
|
|
13631
|
+
const customFetch = cookieEnabled ? createCookieFetch(this.cookieJar) : void 0;
|
|
13632
|
+
if (cookieEnabled && ((_b = this.config.options) == null ? void 0 : _b.verbose)) {
|
|
13633
|
+
console.error("[Proxy] Cookie sticky session enabled");
|
|
13634
|
+
}
|
|
13635
|
+
const transport = new StreamableHTTPClientTransport(new URL(this.config.server.url), {
|
|
13636
|
+
fetch: customFetch
|
|
13637
|
+
});
|
|
13447
13638
|
await this.client.connect(transport);
|
|
13448
13639
|
await this.validateSession();
|
|
13449
13640
|
this.connected = true;
|
|
@@ -13527,13 +13718,65 @@ var TapTapMCPProxy = class {
|
|
|
13527
13718
|
this.healthCheckTimer = null;
|
|
13528
13719
|
}
|
|
13529
13720
|
}
|
|
13721
|
+
/**
|
|
13722
|
+
* 格式化错误信息,提取有用的错误详情
|
|
13723
|
+
*
|
|
13724
|
+
* 错误来源及结构:
|
|
13725
|
+
* 1. 网络层错误 (Node.js fetch):
|
|
13726
|
+
* - message: "fetch failed"
|
|
13727
|
+
* - cause.code: "ECONNREFUSED" / "ETIMEDOUT" 等系统错误码
|
|
13728
|
+
* - cause.message: "connect ECONNREFUSED 127.0.0.1:4000"
|
|
13729
|
+
*
|
|
13730
|
+
* 2. HTTP 错误 (MCP SDK send):
|
|
13731
|
+
* - message: "Error POSTing to endpoint (HTTP 502): Bad Gateway"
|
|
13732
|
+
* - HTTP 状态码嵌入在 message 中
|
|
13733
|
+
*
|
|
13734
|
+
* 3. SSE 连接错误 (MCP SDK StreamableHTTPError):
|
|
13735
|
+
* - message: "Streamable HTTP error: Failed to open SSE stream: Bad Gateway"
|
|
13736
|
+
* - code: 502 (HTTP 状态码,注意和系统错误码共用 code 字段)
|
|
13737
|
+
*/
|
|
13738
|
+
formatError(error) {
|
|
13739
|
+
if (!(error instanceof Error)) {
|
|
13740
|
+
return String(error);
|
|
13741
|
+
}
|
|
13742
|
+
const parts = [];
|
|
13743
|
+
parts.push(error.message);
|
|
13744
|
+
const errorCode = error.code;
|
|
13745
|
+
if (errorCode) {
|
|
13746
|
+
if (typeof errorCode === "number") {
|
|
13747
|
+
parts.push(`[HTTP ${errorCode}]`);
|
|
13748
|
+
} else {
|
|
13749
|
+
parts.push(`[${errorCode}]`);
|
|
13750
|
+
}
|
|
13751
|
+
}
|
|
13752
|
+
const cause = error.cause;
|
|
13753
|
+
if (cause) {
|
|
13754
|
+
if (cause instanceof Error) {
|
|
13755
|
+
const causeCode = cause.code;
|
|
13756
|
+
let causeInfo = cause.message;
|
|
13757
|
+
if (causeCode) causeInfo += ` [${causeCode}]`;
|
|
13758
|
+
parts.push(`(cause: ${causeInfo})`);
|
|
13759
|
+
} else {
|
|
13760
|
+
parts.push(`(cause: ${String(cause)})`);
|
|
13761
|
+
}
|
|
13762
|
+
}
|
|
13763
|
+
return parts.join(" ");
|
|
13764
|
+
}
|
|
13530
13765
|
/**
|
|
13531
13766
|
* 重连到 TapTap Server
|
|
13532
13767
|
*/
|
|
13533
13768
|
async reconnectToServer() {
|
|
13769
|
+
var _a2, _b, _c;
|
|
13534
13770
|
if (this.reconnecting) return;
|
|
13535
13771
|
this.reconnecting = true;
|
|
13536
13772
|
this.clearReconnectTimer();
|
|
13773
|
+
const cookieEnabled = ((_a2 = this.config.options) == null ? void 0 : _a2.enable_cookie_sticky) ?? true;
|
|
13774
|
+
if (cookieEnabled && this.cookieJar.hasCookies) {
|
|
13775
|
+
this.cookieJar.clear();
|
|
13776
|
+
if ((_b = this.config.options) == null ? void 0 : _b.verbose) {
|
|
13777
|
+
console.error("[Proxy] Cookies cleared for reconnection");
|
|
13778
|
+
}
|
|
13779
|
+
}
|
|
13537
13780
|
try {
|
|
13538
13781
|
this.client = new Client(
|
|
13539
13782
|
{ name: "taptap-proxy-client", version: "1.0.0" },
|
|
@@ -13542,7 +13785,9 @@ var TapTapMCPProxy = class {
|
|
|
13542
13785
|
await this.connectToServer();
|
|
13543
13786
|
console.error("[Proxy] ✅ Reconnected successfully");
|
|
13544
13787
|
} catch (error) {
|
|
13545
|
-
|
|
13788
|
+
const interval = ((_c = this.config.options) == null ? void 0 : _c.reconnect_interval) ?? 5e3;
|
|
13789
|
+
console.error("[Proxy] ❌ Reconnect failed:", this.formatError(error));
|
|
13790
|
+
console.error(`[Proxy] Will retry in ${interval / 1e3}s...`);
|
|
13546
13791
|
this.reconnecting = false;
|
|
13547
13792
|
this.scheduleReconnect();
|
|
13548
13793
|
}
|
package/dist/server.js
CHANGED
|
@@ -5660,7 +5660,7 @@ class MultiplayerManager {
|
|
|
5660
5660
|
// 导出
|
|
5661
5661
|
// export default MultiplayerManager;
|
|
5662
5662
|
// module.exports = MultiplayerManager;
|
|
5663
|
-
// window.MultiplayerManager = MultiplayerManager;`}]}}};var ha;ha="1.11.
|
|
5663
|
+
// window.MultiplayerManager = MultiplayerManager;`}]}}};var ha;ha="1.11.4";async function uX(){return mi(jc,"api_event_relations")}async function dX(){return mi(jc,"protocol_template")}async function Nv(){return mi(jc,"complete_example")}async function fX(){return`# TapTap 多人联机集成指南
|
|
5664
5664
|
|
|
5665
5665
|
---
|
|
5666
5666
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mikoto_zero/minigame-open-mcp",
|
|
3
|
-
"version": "1.11.
|
|
3
|
+
"version": "1.11.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "TapTap Open API MCP Server - Documentation and Management APIs for TapTap Minigame and H5 Games (Leaderboard, and more features coming)",
|
|
6
6
|
"main": "dist/server.js",
|