@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 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.2" : "dev";
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, will retry in background");
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 transport = new StreamableHTTPClientTransport(new URL(this.config.server.url));
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
- console.error("[Proxy] Reconnect failed, will retry in 5s");
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.2";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 多人联机集成指南
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.2",
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",