@taptap/instant-games-open-mcp 1.24.11 → 1.24.13
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 +291 -21
- package/dist/native/taptap-signer.darwin-arm64.node +0 -0
- package/dist/native/taptap-signer.darwin-x64.node +0 -0
- package/dist/native/taptap-signer.linux-arm64-musl.node +0 -0
- package/dist/native/taptap-signer.linux-x64-gnu.node +0 -0
- package/dist/native/taptap-signer.linux-x64-musl.node +0 -0
- package/dist/native/taptap-signer.win32-x64-msvc.node +0 -0
- package/dist/proxy.js +501 -158
- package/dist/server.js +392 -327
- package/package.json +13 -4
package/dist/proxy.js
CHANGED
|
@@ -28925,10 +28925,13 @@ var CookieJar = class {
|
|
|
28925
28925
|
return this.cookies.size > 0;
|
|
28926
28926
|
}
|
|
28927
28927
|
};
|
|
28928
|
-
function createCookieFetch(cookieJar) {
|
|
28928
|
+
function createCookieFetch(cookieJar, options = {}) {
|
|
28929
28929
|
return async (input, init) => {
|
|
28930
|
+
if (options.rejectStandaloneSse && isStandaloneSseRequest(input, init)) {
|
|
28931
|
+
return new Response(null, { status: 405, statusText: "Method Not Allowed" });
|
|
28932
|
+
}
|
|
28930
28933
|
const modifiedInit = { ...init };
|
|
28931
|
-
const cookieHeader = cookieJar.getCookieHeader();
|
|
28934
|
+
const cookieHeader = options.enableCookies === false ? void 0 : cookieJar.getCookieHeader();
|
|
28932
28935
|
if (cookieHeader) {
|
|
28933
28936
|
const headers = new Headers(modifiedInit.headers);
|
|
28934
28937
|
headers.set("Cookie", cookieHeader);
|
|
@@ -28939,6 +28942,17 @@ function createCookieFetch(cookieJar) {
|
|
|
28939
28942
|
return response;
|
|
28940
28943
|
};
|
|
28941
28944
|
}
|
|
28945
|
+
function isStandaloneSseRequest(input, init) {
|
|
28946
|
+
var _a3;
|
|
28947
|
+
const method = ((init == null ? void 0 : init.method) || (input instanceof Request ? input.method : "GET")).toUpperCase();
|
|
28948
|
+
if (method !== "GET") {
|
|
28949
|
+
return false;
|
|
28950
|
+
}
|
|
28951
|
+
const headers = new Headers(
|
|
28952
|
+
(init == null ? void 0 : init.headers) || (input instanceof Request ? input.headers : void 0)
|
|
28953
|
+
);
|
|
28954
|
+
return ((_a3 = headers.get("accept")) == null ? void 0 : _a3.split(",").some((value) => value.trim().split(";", 1)[0].toLowerCase() === "text/event-stream")) === true;
|
|
28955
|
+
}
|
|
28942
28956
|
|
|
28943
28957
|
// src/core/utils/logWriter.ts
|
|
28944
28958
|
import * as fs from "node:fs";
|
|
@@ -29136,9 +29150,224 @@ var LogWriter = class {
|
|
|
29136
29150
|
}
|
|
29137
29151
|
};
|
|
29138
29152
|
|
|
29153
|
+
// src/mcp-proxy/config.ts
|
|
29154
|
+
var DEFAULT_TOOL_CALL_TIMEOUT_MS = 60 * 60 * 1e3;
|
|
29155
|
+
function readStdin() {
|
|
29156
|
+
return new Promise((resolve, reject) => {
|
|
29157
|
+
const chunks = [];
|
|
29158
|
+
process.stdin.on("data", (chunk) => {
|
|
29159
|
+
chunks.push(chunk);
|
|
29160
|
+
});
|
|
29161
|
+
process.stdin.on("end", () => {
|
|
29162
|
+
resolve(Buffer.concat(chunks).toString("utf-8"));
|
|
29163
|
+
});
|
|
29164
|
+
process.stdin.on("error", reject);
|
|
29165
|
+
setTimeout(() => {
|
|
29166
|
+
reject(new Error("Timeout reading from stdin"));
|
|
29167
|
+
}, 5e3);
|
|
29168
|
+
});
|
|
29169
|
+
}
|
|
29170
|
+
async function loadConfig() {
|
|
29171
|
+
let configJson;
|
|
29172
|
+
let source;
|
|
29173
|
+
if (process.argv[2]) {
|
|
29174
|
+
configJson = process.argv[2];
|
|
29175
|
+
source = "command line argument";
|
|
29176
|
+
} else if (process.env.PROXY_CONFIG) {
|
|
29177
|
+
configJson = process.env.PROXY_CONFIG;
|
|
29178
|
+
source = "PROXY_CONFIG environment variable";
|
|
29179
|
+
} else if (!process.stdin.isTTY) {
|
|
29180
|
+
configJson = await readStdin();
|
|
29181
|
+
source = "stdin";
|
|
29182
|
+
} else {
|
|
29183
|
+
throw new Error(
|
|
29184
|
+
`No configuration provided. Please use one of:
|
|
29185
|
+
1. Command line: node index.js '{"server":{...}}'
|
|
29186
|
+
2. Env var: PROXY_CONFIG='{"server":{...}}' node index.js
|
|
29187
|
+
3. Stdin: echo '{"server":{...}}' | node index.js
|
|
29188
|
+
|
|
29189
|
+
See config.example.json for configuration format.`
|
|
29190
|
+
);
|
|
29191
|
+
}
|
|
29192
|
+
console.error(`[Proxy] Loading config from ${source}`);
|
|
29193
|
+
let config2;
|
|
29194
|
+
try {
|
|
29195
|
+
config2 = JSON.parse(configJson);
|
|
29196
|
+
} catch (error2) {
|
|
29197
|
+
throw new Error(
|
|
29198
|
+
`Failed to parse configuration JSON: ${error2 instanceof Error ? error2.message : String(error2)}
|
|
29199
|
+
Received: ${configJson.substring(0, 100)}...`
|
|
29200
|
+
);
|
|
29201
|
+
}
|
|
29202
|
+
validateConfig(config2);
|
|
29203
|
+
return applyDefaults(config2);
|
|
29204
|
+
}
|
|
29205
|
+
function validateConfig(config2) {
|
|
29206
|
+
var _a3, _b;
|
|
29207
|
+
const errors = [];
|
|
29208
|
+
if (!config2.server) {
|
|
29209
|
+
errors.push("- Missing required field: server");
|
|
29210
|
+
} else {
|
|
29211
|
+
if (!config2.server.url) {
|
|
29212
|
+
errors.push("- Missing required field: server.url");
|
|
29213
|
+
}
|
|
29214
|
+
if (config2.server.env && !["rnd", "production"].includes(config2.server.env)) {
|
|
29215
|
+
errors.push('- Invalid server.env: must be "rnd" or "production"');
|
|
29216
|
+
}
|
|
29217
|
+
}
|
|
29218
|
+
if (!config2.tenant) {
|
|
29219
|
+
errors.push("- Missing required field: tenant");
|
|
29220
|
+
} else {
|
|
29221
|
+
if (config2.tenant.custom_fields !== void 0) {
|
|
29222
|
+
const cf = config2.tenant.custom_fields;
|
|
29223
|
+
if (typeof cf !== "object" || cf === null || Array.isArray(cf) || Object.getPrototypeOf(cf) !== Object.prototype) {
|
|
29224
|
+
errors.push("- tenant.custom_fields must be a plain object (Record<string, string>)");
|
|
29225
|
+
} else if (!Object.values(cf).every((v) => typeof v === "string")) {
|
|
29226
|
+
errors.push("- tenant.custom_fields values must all be strings");
|
|
29227
|
+
}
|
|
29228
|
+
}
|
|
29229
|
+
}
|
|
29230
|
+
if (!config2.auth) {
|
|
29231
|
+
errors.push("- Missing required field: auth");
|
|
29232
|
+
} else {
|
|
29233
|
+
if (!config2.auth.kid) {
|
|
29234
|
+
errors.push("- Missing required field: auth.kid");
|
|
29235
|
+
}
|
|
29236
|
+
if (!config2.auth.mac_key) {
|
|
29237
|
+
errors.push("- Missing required field: auth.mac_key");
|
|
29238
|
+
}
|
|
29239
|
+
if (config2.auth.token_type !== "mac") {
|
|
29240
|
+
errors.push('- Invalid auth.token_type: must be "mac"');
|
|
29241
|
+
}
|
|
29242
|
+
if (config2.auth.mac_algorithm !== "hmac-sha-1") {
|
|
29243
|
+
errors.push('- Invalid auth.mac_algorithm: must be "hmac-sha-1"');
|
|
29244
|
+
}
|
|
29245
|
+
}
|
|
29246
|
+
if (((_a3 = config2.options) == null ? void 0 : _a3.exposed_tools) !== void 0) {
|
|
29247
|
+
const exposedTools = config2.options.exposed_tools;
|
|
29248
|
+
if (!Array.isArray(exposedTools)) {
|
|
29249
|
+
errors.push("- options.exposed_tools must be an array of tool names");
|
|
29250
|
+
} else if (!exposedTools.every((toolName) => typeof toolName === "string" && toolName.trim().length > 0)) {
|
|
29251
|
+
errors.push("- options.exposed_tools values must be non-empty strings");
|
|
29252
|
+
}
|
|
29253
|
+
}
|
|
29254
|
+
if (((_b = config2.options) == null ? void 0 : _b.replayable_tools) !== void 0) {
|
|
29255
|
+
const replayableTools = config2.options.replayable_tools;
|
|
29256
|
+
if (!Array.isArray(replayableTools)) {
|
|
29257
|
+
errors.push("- options.replayable_tools must be an array of tool names");
|
|
29258
|
+
} else if (!replayableTools.every(
|
|
29259
|
+
(toolName) => typeof toolName === "string" && toolName.trim().length > 0
|
|
29260
|
+
)) {
|
|
29261
|
+
errors.push("- options.replayable_tools values must be non-empty strings");
|
|
29262
|
+
}
|
|
29263
|
+
}
|
|
29264
|
+
if (errors.length > 0) {
|
|
29265
|
+
throw new Error("Invalid configuration:\n" + errors.join("\n"));
|
|
29266
|
+
}
|
|
29267
|
+
}
|
|
29268
|
+
var DEFAULT_LOG_ROOT = "/tmp/taptap-mcp/logs";
|
|
29269
|
+
function applyDefaults(config2) {
|
|
29270
|
+
var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t;
|
|
29271
|
+
const verbose = ((_a3 = config2.options) == null ? void 0 : _a3.verbose) ?? false;
|
|
29272
|
+
return {
|
|
29273
|
+
server: {
|
|
29274
|
+
url: config2.server.url,
|
|
29275
|
+
env: config2.server.env || "rnd"
|
|
29276
|
+
},
|
|
29277
|
+
tenant: {
|
|
29278
|
+
project_path: config2.tenant.project_path || ".",
|
|
29279
|
+
user_id: config2.tenant.user_id,
|
|
29280
|
+
project_id: config2.tenant.project_id,
|
|
29281
|
+
custom_fields: config2.tenant.custom_fields
|
|
29282
|
+
},
|
|
29283
|
+
auth: config2.auth,
|
|
29284
|
+
options: {
|
|
29285
|
+
verbose,
|
|
29286
|
+
reconnect_interval: ((_b = config2.options) == null ? void 0 : _b.reconnect_interval) ?? 5e3,
|
|
29287
|
+
request_timeout: ((_c = config2.options) == null ? void 0 : _c.request_timeout) ?? 3e4,
|
|
29288
|
+
tool_call_timeout: ((_d = config2.options) == null ? void 0 : _d.tool_call_timeout) ?? DEFAULT_TOOL_CALL_TIMEOUT_MS,
|
|
29289
|
+
reset_timeout_on_progress: ((_e = config2.options) == null ? void 0 : _e.reset_timeout_on_progress) ?? true,
|
|
29290
|
+
health_check_interval: ((_f = config2.options) == null ? void 0 : _f.health_check_interval) ?? 3e4,
|
|
29291
|
+
enable_cookie_sticky: ((_g = config2.options) == null ? void 0 : _g.enable_cookie_sticky) ?? true,
|
|
29292
|
+
disable_standalone_sse: ((_h = config2.options) == null ? void 0 : _h.disable_standalone_sse) ?? false,
|
|
29293
|
+
inject_params_per_call: ((_i = config2.options) == null ? void 0 : _i.inject_params_per_call) ?? true,
|
|
29294
|
+
force_inject_progress_token: ((_j = config2.options) == null ? void 0 : _j.force_inject_progress_token) ?? false,
|
|
29295
|
+
exposed_tools: (_k = config2.options) == null ? void 0 : _k.exposed_tools,
|
|
29296
|
+
replayable_tools: (_l = config2.options) == null ? void 0 : _l.replayable_tools,
|
|
29297
|
+
log: {
|
|
29298
|
+
root: ((_n = (_m = config2.options) == null ? void 0 : _m.log) == null ? void 0 : _n.root) ?? DEFAULT_LOG_ROOT,
|
|
29299
|
+
enabled: ((_p = (_o = config2.options) == null ? void 0 : _o.log) == null ? void 0 : _p.enabled) ?? false,
|
|
29300
|
+
// verbose=true 时自动使用 debug 级别
|
|
29301
|
+
level: verbose ? "debug" : ((_r = (_q = config2.options) == null ? void 0 : _q.log) == null ? void 0 : _r.level) ?? "info",
|
|
29302
|
+
max_days: ((_t = (_s = config2.options) == null ? void 0 : _s.log) == null ? void 0 : _t.max_days) ?? 7
|
|
29303
|
+
}
|
|
29304
|
+
}
|
|
29305
|
+
};
|
|
29306
|
+
}
|
|
29307
|
+
|
|
29139
29308
|
// src/mcp-proxy/proxy.ts
|
|
29140
|
-
var VERSION = true ? "1.24.
|
|
29309
|
+
var VERSION = true ? "1.24.13" : "dev";
|
|
29141
29310
|
var LOCAL_PROXY_TAG = "local";
|
|
29311
|
+
var DEFAULT_RECONNECT_INTERVAL_MS = 5e3;
|
|
29312
|
+
var MAX_RECONNECT_INTERVAL_MS = 60 * 1e3;
|
|
29313
|
+
function createNonReplayableToolResult(name, executionState) {
|
|
29314
|
+
const text = executionState === "not_executed" ? `${name} was not sent because the upstream MCP connection is unavailable. It was not executed. Automatic retry is disabled; retry explicitly after the connection recovers.` : `${name} may have completed before the upstream MCP response was interrupted. Its execution state is unknown. Automatic retry is disabled; verify remote output, state, and usage before deciding whether to retry explicitly.`;
|
|
29315
|
+
return {
|
|
29316
|
+
isError: true,
|
|
29317
|
+
content: [{ type: "text", text }],
|
|
29318
|
+
structuredContent: {
|
|
29319
|
+
execution_state: executionState,
|
|
29320
|
+
automatic_retry: false
|
|
29321
|
+
}
|
|
29322
|
+
};
|
|
29323
|
+
}
|
|
29324
|
+
function convertMcpApplicationErrorToToolResult(error2) {
|
|
29325
|
+
if (!(error2 instanceof Error)) {
|
|
29326
|
+
return void 0;
|
|
29327
|
+
}
|
|
29328
|
+
const data = error2.data;
|
|
29329
|
+
if (!isRecord(data) || !("remote_result" in data) || data.remote_result === void 0) {
|
|
29330
|
+
return void 0;
|
|
29331
|
+
}
|
|
29332
|
+
return {
|
|
29333
|
+
isError: true,
|
|
29334
|
+
content: [
|
|
29335
|
+
{
|
|
29336
|
+
type: "text",
|
|
29337
|
+
text: [
|
|
29338
|
+
error2.message,
|
|
29339
|
+
"remote_result:",
|
|
29340
|
+
formatProxyDiagnosticValue(data.remote_result)
|
|
29341
|
+
].join("\n")
|
|
29342
|
+
}
|
|
29343
|
+
]
|
|
29344
|
+
};
|
|
29345
|
+
}
|
|
29346
|
+
function isRecord(value) {
|
|
29347
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
29348
|
+
}
|
|
29349
|
+
function formatProxyDiagnosticValue(value) {
|
|
29350
|
+
if (typeof value === "string") {
|
|
29351
|
+
return value;
|
|
29352
|
+
}
|
|
29353
|
+
try {
|
|
29354
|
+
return JSON.stringify(value, null, 2) || String(value);
|
|
29355
|
+
} catch {
|
|
29356
|
+
return String(value);
|
|
29357
|
+
}
|
|
29358
|
+
}
|
|
29359
|
+
function isTransientHttpServerError(error2) {
|
|
29360
|
+
const code = error2.code;
|
|
29361
|
+
if (typeof code === "number" && code >= 500 && code < 600) {
|
|
29362
|
+
return true;
|
|
29363
|
+
}
|
|
29364
|
+
return /\bHTTP\s+5\d\d\b|bad gateway|service unavailable|gateway timeout/i.test(error2.message);
|
|
29365
|
+
}
|
|
29366
|
+
function isHttpClientError(error2) {
|
|
29367
|
+
const code = error2.code;
|
|
29368
|
+
const numericCode = typeof code === "number" ? code : typeof code === "string" && /^4\d\d$/.test(code) ? Number(code) : void 0;
|
|
29369
|
+
return numericCode !== void 0 && numericCode >= 400 && numericCode < 500 || /\bHTTP\s+4\d\d\b/i.test(error2.message);
|
|
29370
|
+
}
|
|
29142
29371
|
var TapTapMCPProxy = class {
|
|
29143
29372
|
constructor(config2) {
|
|
29144
29373
|
this.connected = false;
|
|
@@ -29146,6 +29375,7 @@ var TapTapMCPProxy = class {
|
|
|
29146
29375
|
this.reconnectTimer = null;
|
|
29147
29376
|
this.healthCheckTimer = null;
|
|
29148
29377
|
this.pendingRequests = [];
|
|
29378
|
+
this.reconnectDelayMs = DEFAULT_RECONNECT_INTERVAL_MS;
|
|
29149
29379
|
// 会话验证相关
|
|
29150
29380
|
this.sessionValidated = false;
|
|
29151
29381
|
this.lastValidationTime = 0;
|
|
@@ -29154,15 +29384,15 @@ var TapTapMCPProxy = class {
|
|
|
29154
29384
|
this.config = config2;
|
|
29155
29385
|
this.cookieJar = new CookieJar(((_a3 = config2.options) == null ? void 0 : _a3.verbose) ?? false);
|
|
29156
29386
|
this.logWriter = this.createLogWriter();
|
|
29157
|
-
this.client =
|
|
29158
|
-
{ name: "taptap-proxy-client", version: "1.0.0" },
|
|
29159
|
-
{ capabilities: {} }
|
|
29160
|
-
);
|
|
29387
|
+
this.client = this.createClient();
|
|
29161
29388
|
this.server = new Server(
|
|
29162
29389
|
{ name: "taptap-proxy", version: "1.0.0" },
|
|
29163
|
-
{ capabilities: { tools: {}, resources: {} } }
|
|
29390
|
+
{ capabilities: { tools: { listChanged: true }, resources: {} } }
|
|
29164
29391
|
);
|
|
29165
29392
|
}
|
|
29393
|
+
createClient() {
|
|
29394
|
+
return new Client({ name: "taptap-proxy-client", version: "1.0.0" }, { capabilities: {} });
|
|
29395
|
+
}
|
|
29166
29396
|
/**
|
|
29167
29397
|
* 创建文件日志写入器
|
|
29168
29398
|
*/
|
|
@@ -29201,6 +29431,12 @@ var TapTapMCPProxy = class {
|
|
|
29201
29431
|
`;
|
|
29202
29432
|
this.logWriter.writeSync(level, formattedMessage);
|
|
29203
29433
|
}
|
|
29434
|
+
logLifecycleEvent(source, message) {
|
|
29435
|
+
try {
|
|
29436
|
+
this.log("info", `lifecycle:${source}: ${message}`);
|
|
29437
|
+
} catch {
|
|
29438
|
+
}
|
|
29439
|
+
}
|
|
29204
29440
|
/**
|
|
29205
29441
|
* 启动 Proxy
|
|
29206
29442
|
*/
|
|
@@ -29327,18 +29563,30 @@ var TapTapMCPProxy = class {
|
|
|
29327
29563
|
throw new McpError(ErrorCode.MethodNotFound, `Tool is not exposed by this proxy: ${name}`);
|
|
29328
29564
|
}
|
|
29329
29565
|
}
|
|
29566
|
+
isToolReplayable(name) {
|
|
29567
|
+
var _a3;
|
|
29568
|
+
const replayableTools = (_a3 = this.config.options) == null ? void 0 : _a3.replayable_tools;
|
|
29569
|
+
return replayableTools === void 0 || replayableTools.includes(name);
|
|
29570
|
+
}
|
|
29330
29571
|
/**
|
|
29331
29572
|
* 连接到 TapTap MCP Server
|
|
29332
29573
|
*/
|
|
29333
29574
|
async connectToServer() {
|
|
29334
|
-
var _a3, _b;
|
|
29575
|
+
var _a3, _b, _c, _d, _e;
|
|
29335
29576
|
this.log("info", `Connecting to ${this.config.server.url}...`);
|
|
29336
29577
|
try {
|
|
29337
29578
|
const cookieEnabled = ((_a3 = this.config.options) == null ? void 0 : _a3.enable_cookie_sticky) ?? true;
|
|
29338
|
-
const
|
|
29339
|
-
|
|
29579
|
+
const standaloneSseDisabled = ((_b = this.config.options) == null ? void 0 : _b.disable_standalone_sse) ?? false;
|
|
29580
|
+
const customFetch = cookieEnabled || standaloneSseDisabled ? createCookieFetch(this.cookieJar, {
|
|
29581
|
+
enableCookies: cookieEnabled,
|
|
29582
|
+
rejectStandaloneSse: standaloneSseDisabled
|
|
29583
|
+
}) : void 0;
|
|
29584
|
+
if (cookieEnabled && ((_c = this.config.options) == null ? void 0 : _c.verbose)) {
|
|
29340
29585
|
this.log("debug", "Cookie sticky session enabled");
|
|
29341
29586
|
}
|
|
29587
|
+
if (standaloneSseDisabled && ((_d = this.config.options) == null ? void 0 : _d.verbose)) {
|
|
29588
|
+
this.log("debug", "Standalone SSE disabled; using POST response streams");
|
|
29589
|
+
}
|
|
29342
29590
|
const sessionHeaders = this.buildSessionHeaders();
|
|
29343
29591
|
const transport = new StreamableHTTPClientTransport(new URL(this.config.server.url), {
|
|
29344
29592
|
fetch: customFetch,
|
|
@@ -29352,11 +29600,12 @@ var TapTapMCPProxy = class {
|
|
|
29352
29600
|
this.connected = true;
|
|
29353
29601
|
this.sessionValidated = true;
|
|
29354
29602
|
this.lastValidationTime = Date.now();
|
|
29603
|
+
this.reconnectDelayMs = ((_e = this.config.options) == null ? void 0 : _e.reconnect_interval) ?? DEFAULT_RECONNECT_INTERVAL_MS;
|
|
29355
29604
|
this.log("info", "✅ Connected and session validated");
|
|
29356
29605
|
this.startHealthCheck();
|
|
29357
29606
|
if (this.reconnecting) {
|
|
29358
|
-
await this.notifyReconnected();
|
|
29359
29607
|
await this.processPendingRequests();
|
|
29608
|
+
await this.notifyReconnected();
|
|
29360
29609
|
this.reconnecting = false;
|
|
29361
29610
|
}
|
|
29362
29611
|
} catch (error2) {
|
|
@@ -29402,7 +29651,7 @@ var TapTapMCPProxy = class {
|
|
|
29402
29651
|
* 启动定期健康检查
|
|
29403
29652
|
*/
|
|
29404
29653
|
startHealthCheck() {
|
|
29405
|
-
var _a3;
|
|
29654
|
+
var _a3, _b, _c;
|
|
29406
29655
|
this.stopHealthCheck();
|
|
29407
29656
|
const interval = ((_a3 = this.config.options) == null ? void 0 : _a3.health_check_interval) ?? this.SESSION_VALIDATION_INTERVAL;
|
|
29408
29657
|
this.healthCheckTimer = setInterval(async () => {
|
|
@@ -29419,6 +29668,7 @@ var TapTapMCPProxy = class {
|
|
|
29419
29668
|
}
|
|
29420
29669
|
}
|
|
29421
29670
|
}, interval);
|
|
29671
|
+
(_c = (_b = this.healthCheckTimer).unref) == null ? void 0 : _c.call(_b);
|
|
29422
29672
|
this.log("debug", `Health check started (interval: ${interval}ms)`);
|
|
29423
29673
|
}
|
|
29424
29674
|
/**
|
|
@@ -29478,10 +29728,11 @@ var TapTapMCPProxy = class {
|
|
|
29478
29728
|
* 重连到 TapTap Server
|
|
29479
29729
|
*/
|
|
29480
29730
|
async reconnectToServer() {
|
|
29481
|
-
var _a3, _b
|
|
29731
|
+
var _a3, _b;
|
|
29482
29732
|
if (this.reconnecting) return;
|
|
29483
29733
|
this.reconnecting = true;
|
|
29484
29734
|
this.clearReconnectTimer();
|
|
29735
|
+
this.stopHealthCheck();
|
|
29485
29736
|
const cookieEnabled = ((_a3 = this.config.options) == null ? void 0 : _a3.enable_cookie_sticky) ?? true;
|
|
29486
29737
|
if (cookieEnabled && this.cookieJar.hasCookies) {
|
|
29487
29738
|
this.cookieJar.clear();
|
|
@@ -29490,14 +29741,12 @@ var TapTapMCPProxy = class {
|
|
|
29490
29741
|
}
|
|
29491
29742
|
}
|
|
29492
29743
|
try {
|
|
29493
|
-
this.client
|
|
29494
|
-
|
|
29495
|
-
{ capabilities: {} }
|
|
29496
|
-
);
|
|
29744
|
+
await this.closeClientSafely("reconnect-old-client");
|
|
29745
|
+
this.client = this.createClient();
|
|
29497
29746
|
await this.connectToServer();
|
|
29498
29747
|
this.log("info", "✅ Reconnected successfully");
|
|
29499
29748
|
} catch (error2) {
|
|
29500
|
-
const interval =
|
|
29749
|
+
const interval = this.reconnectDelayMs;
|
|
29501
29750
|
this.log("error", `❌ Reconnect failed: ${this.formatError(error2)}`);
|
|
29502
29751
|
this.log("info", `Will retry in ${interval / 1e3}s...`);
|
|
29503
29752
|
this.reconnecting = false;
|
|
@@ -29508,12 +29757,18 @@ var TapTapMCPProxy = class {
|
|
|
29508
29757
|
* 调度重连
|
|
29509
29758
|
*/
|
|
29510
29759
|
scheduleReconnect() {
|
|
29511
|
-
var _a3;
|
|
29760
|
+
var _a3, _b, _c;
|
|
29512
29761
|
this.clearReconnectTimer();
|
|
29513
|
-
const
|
|
29762
|
+
const configuredInterval = ((_a3 = this.config.options) == null ? void 0 : _a3.reconnect_interval) ?? DEFAULT_RECONNECT_INTERVAL_MS;
|
|
29763
|
+
const interval = this.reconnectDelayMs || configuredInterval;
|
|
29514
29764
|
this.reconnectTimer = setTimeout(() => {
|
|
29515
29765
|
this.reconnectToServer();
|
|
29516
29766
|
}, interval);
|
|
29767
|
+
(_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
|
+
);
|
|
29517
29772
|
}
|
|
29518
29773
|
/**
|
|
29519
29774
|
* 清除重连定时器
|
|
@@ -29538,12 +29793,32 @@ var TapTapMCPProxy = class {
|
|
|
29538
29793
|
const req = this.pendingRequests.shift();
|
|
29539
29794
|
req.reject(timeout);
|
|
29540
29795
|
}
|
|
29796
|
+
void this.closeClientSafely("cleanup");
|
|
29797
|
+
}
|
|
29798
|
+
async closeClientSafely(source) {
|
|
29799
|
+
try {
|
|
29800
|
+
await this.client.close();
|
|
29801
|
+
} catch (error2) {
|
|
29802
|
+
this.log(
|
|
29803
|
+
"warning",
|
|
29804
|
+
`Failed to close proxy client during ${source}: ${this.formatError(error2)}`
|
|
29805
|
+
);
|
|
29806
|
+
}
|
|
29541
29807
|
}
|
|
29542
29808
|
/**
|
|
29543
29809
|
* 检测是否是需要重连的错误(网络错误或会话无效)
|
|
29544
29810
|
*/
|
|
29545
29811
|
isNetworkError(error2) {
|
|
29546
29812
|
if (!(error2 instanceof Error)) return false;
|
|
29813
|
+
if (convertMcpApplicationErrorToToolResult(error2)) {
|
|
29814
|
+
return false;
|
|
29815
|
+
}
|
|
29816
|
+
if (isHttpClientError(error2)) {
|
|
29817
|
+
return false;
|
|
29818
|
+
}
|
|
29819
|
+
if (isTransientHttpServerError(error2)) {
|
|
29820
|
+
return true;
|
|
29821
|
+
}
|
|
29547
29822
|
const errorMsg = error2.message.toLowerCase();
|
|
29548
29823
|
const errorCode = error2.code;
|
|
29549
29824
|
const networkErrorCodes = [
|
|
@@ -29567,6 +29842,15 @@ var TapTapMCPProxy = class {
|
|
|
29567
29842
|
if (errorCode && networkErrorCodes.includes(errorCode)) {
|
|
29568
29843
|
return true;
|
|
29569
29844
|
}
|
|
29845
|
+
if (errorCode === ErrorCode.ConnectionClosed || errorCode === ErrorCode.RequestTimeout) {
|
|
29846
|
+
return true;
|
|
29847
|
+
}
|
|
29848
|
+
if (errorMsg.includes("not connected") || this.isSessionInvalidError(error2)) {
|
|
29849
|
+
return true;
|
|
29850
|
+
}
|
|
29851
|
+
if (this.isMcpApplicationError(error2)) {
|
|
29852
|
+
return false;
|
|
29853
|
+
}
|
|
29570
29854
|
const networkErrorKeywords = [
|
|
29571
29855
|
"fetch failed",
|
|
29572
29856
|
"socket hang up",
|
|
@@ -29574,15 +29858,18 @@ var TapTapMCPProxy = class {
|
|
|
29574
29858
|
"connection refused",
|
|
29575
29859
|
"connection reset",
|
|
29576
29860
|
"timeout",
|
|
29577
|
-
"dns"
|
|
29578
|
-
"not connected"
|
|
29579
|
-
// 连接断开
|
|
29861
|
+
"dns"
|
|
29580
29862
|
];
|
|
29581
29863
|
if (networkErrorKeywords.some((keyword) => errorMsg.includes(keyword))) {
|
|
29582
29864
|
return true;
|
|
29583
29865
|
}
|
|
29584
29866
|
return this.isSessionInvalidError(error2);
|
|
29585
29867
|
}
|
|
29868
|
+
isMcpApplicationError(error2) {
|
|
29869
|
+
const message = error2.message.toLowerCase();
|
|
29870
|
+
const code = error2.code;
|
|
29871
|
+
return typeof code === "number" && code < 0 || /\bmcp error -\d+/.test(message);
|
|
29872
|
+
}
|
|
29586
29873
|
/**
|
|
29587
29874
|
* 处理待处理的请求队列
|
|
29588
29875
|
*/
|
|
@@ -29593,6 +29880,10 @@ var TapTapMCPProxy = class {
|
|
|
29593
29880
|
this.log("info", `Processing ${this.pendingRequests.length} pending requests...`);
|
|
29594
29881
|
while (this.pendingRequests.length > 0) {
|
|
29595
29882
|
const req = this.pendingRequests.shift();
|
|
29883
|
+
if (!this.isToolReplayable(req.name)) {
|
|
29884
|
+
req.resolve(createNonReplayableToolResult(req.name, req.executionState ?? "unknown"));
|
|
29885
|
+
continue;
|
|
29886
|
+
}
|
|
29596
29887
|
if (now - req.timestamp > timeout) {
|
|
29597
29888
|
req.reject(new Error("Request timeout while waiting for reconnection"));
|
|
29598
29889
|
continue;
|
|
@@ -29606,13 +29897,24 @@ var TapTapMCPProxy = class {
|
|
|
29606
29897
|
void 0,
|
|
29607
29898
|
// resultSchema
|
|
29608
29899
|
{
|
|
29609
|
-
timeout: ((_b = this.config.options) == null ? void 0 : _b.tool_call_timeout) ??
|
|
29900
|
+
timeout: ((_b = this.config.options) == null ? void 0 : _b.tool_call_timeout) ?? DEFAULT_TOOL_CALL_TIMEOUT_MS,
|
|
29610
29901
|
resetTimeoutOnProgress: ((_c = this.config.options) == null ? void 0 : _c.reset_timeout_on_progress) ?? true,
|
|
29611
29902
|
onprogress: req.onprogress
|
|
29612
29903
|
}
|
|
29613
29904
|
);
|
|
29614
29905
|
req.resolve(result);
|
|
29615
29906
|
} catch (error2) {
|
|
29907
|
+
const toolErrorResult = convertMcpApplicationErrorToToolResult(error2);
|
|
29908
|
+
if (toolErrorResult) {
|
|
29909
|
+
req.resolve(toolErrorResult);
|
|
29910
|
+
continue;
|
|
29911
|
+
}
|
|
29912
|
+
if (this.isNetworkError(error2)) {
|
|
29913
|
+
this.connected = false;
|
|
29914
|
+
this.sessionValidated = false;
|
|
29915
|
+
this.pendingRequests.unshift(req);
|
|
29916
|
+
throw error2;
|
|
29917
|
+
}
|
|
29616
29918
|
req.reject(error2 instanceof Error ? error2 : new Error(String(error2)));
|
|
29617
29919
|
}
|
|
29618
29920
|
}
|
|
@@ -29692,7 +29994,7 @@ var TapTapMCPProxy = class {
|
|
|
29692
29994
|
}
|
|
29693
29995
|
const progressToken = (_c = request.params._meta) == null ? void 0 : _c.progressToken;
|
|
29694
29996
|
const callToolOptions = {
|
|
29695
|
-
timeout: ((_d = this.config.options) == null ? void 0 : _d.tool_call_timeout) ??
|
|
29997
|
+
timeout: ((_d = this.config.options) == null ? void 0 : _d.tool_call_timeout) ?? DEFAULT_TOOL_CALL_TIMEOUT_MS,
|
|
29696
29998
|
resetTimeoutOnProgress: ((_e = this.config.options) == null ? void 0 : _e.reset_timeout_on_progress) ?? true
|
|
29697
29999
|
};
|
|
29698
30000
|
const forceInjectProgressToken = ((_f = this.config.options) == null ? void 0 : _f.force_inject_progress_token) ?? false;
|
|
@@ -29715,6 +30017,9 @@ var TapTapMCPProxy = class {
|
|
|
29715
30017
|
}
|
|
29716
30018
|
}
|
|
29717
30019
|
if (!this.connected) {
|
|
30020
|
+
if (!this.isToolReplayable(name)) {
|
|
30021
|
+
return createNonReplayableToolResult(name, "not_executed");
|
|
30022
|
+
}
|
|
29718
30023
|
if (this.reconnecting) {
|
|
29719
30024
|
this.log("info", `⏳ Queueing request: ${name} (reconnecting...)`);
|
|
29720
30025
|
return new Promise((resolve, reject) => {
|
|
@@ -29724,6 +30029,7 @@ var TapTapMCPProxy = class {
|
|
|
29724
30029
|
resolve,
|
|
29725
30030
|
reject,
|
|
29726
30031
|
timestamp: Date.now(),
|
|
30032
|
+
executionState: "not_executed",
|
|
29727
30033
|
onprogress: callToolOptions.onprogress
|
|
29728
30034
|
});
|
|
29729
30035
|
});
|
|
@@ -29745,12 +30051,19 @@ var TapTapMCPProxy = class {
|
|
|
29745
30051
|
);
|
|
29746
30052
|
return result;
|
|
29747
30053
|
} catch (error2) {
|
|
30054
|
+
const toolErrorResult = convertMcpApplicationErrorToToolResult(error2);
|
|
30055
|
+
if (toolErrorResult) {
|
|
30056
|
+
return toolErrorResult;
|
|
30057
|
+
}
|
|
29748
30058
|
if (this.isNetworkError(error2)) {
|
|
29749
30059
|
this.log("error", "❌ Network error detected, marking connection as lost");
|
|
29750
30060
|
this.connected = false;
|
|
29751
30061
|
if (!this.reconnecting) {
|
|
29752
30062
|
this.log("info", "Triggering immediate reconnection...");
|
|
29753
30063
|
this.reconnectToServer();
|
|
30064
|
+
if (!this.isToolReplayable(name)) {
|
|
30065
|
+
return createNonReplayableToolResult(name, "unknown");
|
|
30066
|
+
}
|
|
29754
30067
|
this.log("info", `⏳ Queueing current request: ${name}`);
|
|
29755
30068
|
return new Promise((resolve, reject) => {
|
|
29756
30069
|
this.pendingRequests.push({
|
|
@@ -29759,10 +30072,14 @@ var TapTapMCPProxy = class {
|
|
|
29759
30072
|
resolve,
|
|
29760
30073
|
reject,
|
|
29761
30074
|
timestamp: Date.now(),
|
|
30075
|
+
executionState: "unknown",
|
|
29762
30076
|
onprogress: callToolOptions.onprogress
|
|
29763
30077
|
});
|
|
29764
30078
|
});
|
|
29765
30079
|
}
|
|
30080
|
+
if (!this.isToolReplayable(name)) {
|
|
30081
|
+
return createNonReplayableToolResult(name, "unknown");
|
|
30082
|
+
}
|
|
29766
30083
|
}
|
|
29767
30084
|
throw error2;
|
|
29768
30085
|
}
|
|
@@ -29770,147 +30087,176 @@ var TapTapMCPProxy = class {
|
|
|
29770
30087
|
}
|
|
29771
30088
|
};
|
|
29772
30089
|
|
|
29773
|
-
// src/
|
|
29774
|
-
|
|
29775
|
-
|
|
29776
|
-
|
|
29777
|
-
|
|
29778
|
-
|
|
29779
|
-
|
|
29780
|
-
|
|
29781
|
-
|
|
29782
|
-
|
|
29783
|
-
|
|
29784
|
-
|
|
29785
|
-
|
|
29786
|
-
|
|
29787
|
-
|
|
30090
|
+
// src/core/utils/processLifecycle.ts
|
|
30091
|
+
var DISCONNECTED_STDIO_CODES = /* @__PURE__ */ new Set([
|
|
30092
|
+
"EPIPE",
|
|
30093
|
+
"ERR_STREAM_DESTROYED",
|
|
30094
|
+
"ECONNRESET",
|
|
30095
|
+
"EIO",
|
|
30096
|
+
"ENXIO"
|
|
30097
|
+
]);
|
|
30098
|
+
function isDisconnectedStdioError(error2) {
|
|
30099
|
+
if (!error2 || typeof error2 !== "object") {
|
|
30100
|
+
return false;
|
|
30101
|
+
}
|
|
30102
|
+
const code = error2.code;
|
|
30103
|
+
if (typeof code === "string" && DISCONNECTED_STDIO_CODES.has(code)) {
|
|
30104
|
+
return true;
|
|
30105
|
+
}
|
|
30106
|
+
const message = error2 instanceof Error ? error2.message.toLowerCase() : "";
|
|
30107
|
+
return message.includes("epipe") || message.includes("stream destroyed");
|
|
29788
30108
|
}
|
|
29789
|
-
|
|
29790
|
-
|
|
29791
|
-
|
|
29792
|
-
if (process.argv[2]) {
|
|
29793
|
-
configJson = process.argv[2];
|
|
29794
|
-
source = "command line argument";
|
|
29795
|
-
} else if (process.env.PROXY_CONFIG) {
|
|
29796
|
-
configJson = process.env.PROXY_CONFIG;
|
|
29797
|
-
source = "PROXY_CONFIG environment variable";
|
|
29798
|
-
} else if (!process.stdin.isTTY) {
|
|
29799
|
-
configJson = await readStdin();
|
|
29800
|
-
source = "stdin";
|
|
29801
|
-
} else {
|
|
29802
|
-
throw new Error(
|
|
29803
|
-
`No configuration provided. Please use one of:
|
|
29804
|
-
1. Command line: node index.js '{"server":{...}}'
|
|
29805
|
-
2. Env var: PROXY_CONFIG='{"server":{...}}' node index.js
|
|
29806
|
-
3. Stdin: echo '{"server":{...}}' | node index.js
|
|
29807
|
-
|
|
29808
|
-
See config.example.json for configuration format.`
|
|
29809
|
-
);
|
|
30109
|
+
function shouldExitForParentDeath(options) {
|
|
30110
|
+
if ((options.platform === "darwin" || options.platform === "linux") && options.initialPpid > 1 && options.currentPpid === 1) {
|
|
30111
|
+
return true;
|
|
29810
30112
|
}
|
|
29811
|
-
console.error(`[Proxy] Loading config from ${source}`);
|
|
29812
|
-
let config2;
|
|
29813
30113
|
try {
|
|
29814
|
-
|
|
30114
|
+
options.probeParent();
|
|
30115
|
+
return false;
|
|
29815
30116
|
} catch (error2) {
|
|
29816
|
-
|
|
29817
|
-
|
|
29818
|
-
Received: ${configJson.substring(0, 100)}...`
|
|
30117
|
+
return Boolean(
|
|
30118
|
+
error2 && typeof error2 === "object" && error2.code === "ESRCH" && options.initialPpid > 1
|
|
29819
30119
|
);
|
|
29820
30120
|
}
|
|
29821
|
-
validateConfig(config2);
|
|
29822
|
-
return applyDefaults(config2);
|
|
29823
30121
|
}
|
|
29824
|
-
function
|
|
29825
|
-
|
|
29826
|
-
const
|
|
29827
|
-
|
|
29828
|
-
|
|
29829
|
-
|
|
29830
|
-
if (
|
|
29831
|
-
|
|
29832
|
-
}
|
|
29833
|
-
if (config2.server.env && !["rnd", "production"].includes(config2.server.env)) {
|
|
29834
|
-
errors.push('- Invalid server.env: must be "rnd" or "production"');
|
|
29835
|
-
}
|
|
29836
|
-
}
|
|
29837
|
-
if (!config2.tenant) {
|
|
29838
|
-
errors.push("- Missing required field: tenant");
|
|
29839
|
-
} else {
|
|
29840
|
-
if (config2.tenant.custom_fields !== void 0) {
|
|
29841
|
-
const cf = config2.tenant.custom_fields;
|
|
29842
|
-
if (typeof cf !== "object" || cf === null || Array.isArray(cf) || Object.getPrototypeOf(cf) !== Object.prototype) {
|
|
29843
|
-
errors.push("- tenant.custom_fields must be a plain object (Record<string, string>)");
|
|
29844
|
-
} else if (!Object.values(cf).every((v) => typeof v === "string")) {
|
|
29845
|
-
errors.push("- tenant.custom_fields values must all be strings");
|
|
29846
|
-
}
|
|
29847
|
-
}
|
|
29848
|
-
}
|
|
29849
|
-
if (!config2.auth) {
|
|
29850
|
-
errors.push("- Missing required field: auth");
|
|
29851
|
-
} else {
|
|
29852
|
-
if (!config2.auth.kid) {
|
|
29853
|
-
errors.push("- Missing required field: auth.kid");
|
|
30122
|
+
function installStdinExitHandler(options) {
|
|
30123
|
+
const stdin = options.stdin ?? process.stdin;
|
|
30124
|
+
const exit = options.exit ?? ((code) => process.exit(code));
|
|
30125
|
+
let exiting = false;
|
|
30126
|
+
const exitOnStdinClosed = () => {
|
|
30127
|
+
var _a3;
|
|
30128
|
+
if (exiting) {
|
|
30129
|
+
return;
|
|
29854
30130
|
}
|
|
29855
|
-
|
|
29856
|
-
|
|
30131
|
+
exiting = true;
|
|
30132
|
+
if (options.onClosed) {
|
|
30133
|
+
options.onClosed(options.source, options.message);
|
|
30134
|
+
return;
|
|
29857
30135
|
}
|
|
29858
|
-
|
|
29859
|
-
|
|
30136
|
+
(_a3 = options.log) == null ? void 0 : _a3.call(options, options.source, options.message);
|
|
30137
|
+
options.cleanup();
|
|
30138
|
+
exit(0);
|
|
30139
|
+
};
|
|
30140
|
+
stdin.once("end", exitOnStdinClosed);
|
|
30141
|
+
stdin.once("close", exitOnStdinClosed);
|
|
30142
|
+
}
|
|
30143
|
+
function installParentDeathWatchdog(options) {
|
|
30144
|
+
var _a3;
|
|
30145
|
+
const initialPpid = options.initialPpid ?? process.ppid;
|
|
30146
|
+
const getCurrentPpid = options.getCurrentPpid ?? (() => process.ppid);
|
|
30147
|
+
const platform = options.platform ?? process.platform;
|
|
30148
|
+
const probeParent = options.probeParent ?? (() => process.kill(initialPpid, 0));
|
|
30149
|
+
const exit = options.exit ?? ((code) => process.exit(code));
|
|
30150
|
+
let exiting = false;
|
|
30151
|
+
const timer = setInterval(() => {
|
|
30152
|
+
var _a4;
|
|
30153
|
+
if (exiting) {
|
|
30154
|
+
return;
|
|
29860
30155
|
}
|
|
29861
|
-
|
|
29862
|
-
|
|
30156
|
+
const shouldExit = shouldExitForParentDeath({
|
|
30157
|
+
initialPpid,
|
|
30158
|
+
currentPpid: getCurrentPpid(),
|
|
30159
|
+
platform,
|
|
30160
|
+
probeParent
|
|
30161
|
+
});
|
|
30162
|
+
if (!shouldExit) {
|
|
30163
|
+
return;
|
|
29863
30164
|
}
|
|
30165
|
+
exiting = true;
|
|
30166
|
+
(_a4 = options.log) == null ? void 0 : _a4.call(options, options.source, options.message);
|
|
30167
|
+
options.cleanup();
|
|
30168
|
+
exit(0);
|
|
30169
|
+
}, options.intervalMs ?? 15e3);
|
|
30170
|
+
(_a3 = timer.unref) == null ? void 0 : _a3.call(timer);
|
|
30171
|
+
return timer;
|
|
30172
|
+
}
|
|
30173
|
+
function installStdioErrorHandlers(options) {
|
|
30174
|
+
const exit = options.exit ?? ((code) => process.exit(code));
|
|
30175
|
+
let exiting = false;
|
|
30176
|
+
for (const stream of options.streams) {
|
|
30177
|
+
stream.on("error", (error2) => {
|
|
30178
|
+
var _a3, _b;
|
|
30179
|
+
if (!isDisconnectedStdioError(error2)) {
|
|
30180
|
+
(_a3 = options.log) == null ? void 0 : _a3.call(
|
|
30181
|
+
options,
|
|
30182
|
+
options.ignoredSource ?? "stdio-error",
|
|
30183
|
+
options.ignoredMessage ? options.ignoredMessage(error2) : `stdio error ignored: ${formatError2(error2)}`
|
|
30184
|
+
);
|
|
30185
|
+
return;
|
|
30186
|
+
}
|
|
30187
|
+
if (exiting) {
|
|
30188
|
+
return;
|
|
30189
|
+
}
|
|
30190
|
+
exiting = true;
|
|
30191
|
+
if (options.onDisconnected) {
|
|
30192
|
+
options.onDisconnected(options.disconnectedSource, options.disconnectedMessage);
|
|
30193
|
+
return;
|
|
30194
|
+
}
|
|
30195
|
+
(_b = options.log) == null ? void 0 : _b.call(options, options.disconnectedSource, options.disconnectedMessage);
|
|
30196
|
+
options.cleanup();
|
|
30197
|
+
exit(0);
|
|
30198
|
+
});
|
|
29864
30199
|
}
|
|
29865
|
-
|
|
29866
|
-
|
|
29867
|
-
|
|
29868
|
-
|
|
29869
|
-
|
|
29870
|
-
|
|
30200
|
+
}
|
|
30201
|
+
function formatError2(error2) {
|
|
30202
|
+
return error2 instanceof Error ? error2.message : String(error2);
|
|
30203
|
+
}
|
|
30204
|
+
|
|
30205
|
+
// src/mcp-proxy/lifecycle.ts
|
|
30206
|
+
function installStandaloneProxyLifecycleHandlers(options) {
|
|
30207
|
+
const stdin = options.stdin ?? process.stdin;
|
|
30208
|
+
const stdout = options.stdout ?? process.stdout;
|
|
30209
|
+
const stderr = options.stderr ?? process.stderr;
|
|
30210
|
+
const exit = options.exit ?? ((code) => process.exit(code));
|
|
30211
|
+
const log = options.log;
|
|
30212
|
+
let exiting = false;
|
|
30213
|
+
const exitOnce = (source, message) => {
|
|
30214
|
+
if (exiting) {
|
|
30215
|
+
return;
|
|
29871
30216
|
}
|
|
30217
|
+
exiting = true;
|
|
30218
|
+
log == null ? void 0 : log(source, message);
|
|
30219
|
+
options.proxy.cleanup();
|
|
30220
|
+
exit(0);
|
|
30221
|
+
};
|
|
30222
|
+
installStdinExitHandler({
|
|
30223
|
+
stdin,
|
|
30224
|
+
cleanup: () => void 0,
|
|
30225
|
+
exit: () => void 0,
|
|
30226
|
+
source: "standalone-proxy-stdin-closed",
|
|
30227
|
+
message: "Standalone proxy stdin closed; exiting.",
|
|
30228
|
+
onClosed: exitOnce
|
|
30229
|
+
});
|
|
30230
|
+
installStdioErrorHandlers({
|
|
30231
|
+
streams: [stdin, stdout, stderr].filter(Boolean),
|
|
30232
|
+
cleanup: () => void 0,
|
|
30233
|
+
exit: () => void 0,
|
|
30234
|
+
log,
|
|
30235
|
+
disconnectedSource: "standalone-proxy-stdio-disconnected",
|
|
30236
|
+
disconnectedMessage: "Standalone proxy stdio disconnected; exiting.",
|
|
30237
|
+
onDisconnected: exitOnce,
|
|
30238
|
+
ignoredSource: "standalone-proxy-stdio-error",
|
|
30239
|
+
ignoredMessage: (error2) => `Standalone proxy stdio error ignored: ${formatError3(error2)}`
|
|
30240
|
+
});
|
|
30241
|
+
if (options.installSignals !== false) {
|
|
30242
|
+
const signalCleanup = () => {
|
|
30243
|
+
exitOnce("standalone-proxy-signal", "Standalone proxy received shutdown signal; exiting.");
|
|
30244
|
+
};
|
|
30245
|
+
process.on("SIGINT", signalCleanup);
|
|
30246
|
+
process.on("SIGTERM", signalCleanup);
|
|
29872
30247
|
}
|
|
29873
|
-
if (
|
|
29874
|
-
|
|
30248
|
+
if (options.installParentWatchdog === false) {
|
|
30249
|
+
return void 0;
|
|
29875
30250
|
}
|
|
30251
|
+
return installParentDeathWatchdog({
|
|
30252
|
+
cleanup: () => exitOnce("standalone-proxy-parent-dead", "Standalone proxy parent process is gone; exiting."),
|
|
30253
|
+
exit: () => void 0,
|
|
30254
|
+
source: "standalone-proxy-parent-dead",
|
|
30255
|
+
message: "Standalone proxy parent process is gone; exiting."
|
|
30256
|
+
});
|
|
29876
30257
|
}
|
|
29877
|
-
|
|
29878
|
-
|
|
29879
|
-
var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r;
|
|
29880
|
-
const verbose = ((_a3 = config2.options) == null ? void 0 : _a3.verbose) ?? false;
|
|
29881
|
-
return {
|
|
29882
|
-
server: {
|
|
29883
|
-
url: config2.server.url,
|
|
29884
|
-
env: config2.server.env || "rnd"
|
|
29885
|
-
},
|
|
29886
|
-
tenant: {
|
|
29887
|
-
project_path: config2.tenant.project_path || ".",
|
|
29888
|
-
user_id: config2.tenant.user_id,
|
|
29889
|
-
project_id: config2.tenant.project_id,
|
|
29890
|
-
custom_fields: config2.tenant.custom_fields
|
|
29891
|
-
},
|
|
29892
|
-
auth: config2.auth,
|
|
29893
|
-
options: {
|
|
29894
|
-
verbose,
|
|
29895
|
-
reconnect_interval: ((_b = config2.options) == null ? void 0 : _b.reconnect_interval) ?? 5e3,
|
|
29896
|
-
request_timeout: ((_c = config2.options) == null ? void 0 : _c.request_timeout) ?? 3e4,
|
|
29897
|
-
tool_call_timeout: ((_d = config2.options) == null ? void 0 : _d.tool_call_timeout) ?? 3e5,
|
|
29898
|
-
// 5 分钟
|
|
29899
|
-
reset_timeout_on_progress: ((_e = config2.options) == null ? void 0 : _e.reset_timeout_on_progress) ?? true,
|
|
29900
|
-
health_check_interval: ((_f = config2.options) == null ? void 0 : _f.health_check_interval) ?? 3e4,
|
|
29901
|
-
enable_cookie_sticky: ((_g = config2.options) == null ? void 0 : _g.enable_cookie_sticky) ?? true,
|
|
29902
|
-
inject_params_per_call: ((_h = config2.options) == null ? void 0 : _h.inject_params_per_call) ?? true,
|
|
29903
|
-
force_inject_progress_token: ((_i = config2.options) == null ? void 0 : _i.force_inject_progress_token) ?? false,
|
|
29904
|
-
exposed_tools: (_j = config2.options) == null ? void 0 : _j.exposed_tools,
|
|
29905
|
-
log: {
|
|
29906
|
-
root: ((_l = (_k = config2.options) == null ? void 0 : _k.log) == null ? void 0 : _l.root) ?? DEFAULT_LOG_ROOT,
|
|
29907
|
-
enabled: ((_n = (_m = config2.options) == null ? void 0 : _m.log) == null ? void 0 : _n.enabled) ?? false,
|
|
29908
|
-
// verbose=true 时自动使用 debug 级别
|
|
29909
|
-
level: verbose ? "debug" : ((_p = (_o = config2.options) == null ? void 0 : _o.log) == null ? void 0 : _p.level) ?? "info",
|
|
29910
|
-
max_days: ((_r = (_q = config2.options) == null ? void 0 : _q.log) == null ? void 0 : _r.max_days) ?? 7
|
|
29911
|
-
}
|
|
29912
|
-
}
|
|
29913
|
-
};
|
|
30258
|
+
function formatError3(error2) {
|
|
30259
|
+
return error2 instanceof Error ? error2.message : String(error2);
|
|
29914
30260
|
}
|
|
29915
30261
|
|
|
29916
30262
|
// src/mcp-proxy/index.ts
|
|
@@ -29931,13 +30277,10 @@ async function main() {
|
|
|
29931
30277
|
console.error(`[Proxy] Verbose: ${(_a3 = config2.options) == null ? void 0 : _a3.verbose}`);
|
|
29932
30278
|
const proxy = new TapTapMCPProxy(config2);
|
|
29933
30279
|
await proxy.start();
|
|
29934
|
-
|
|
29935
|
-
|
|
29936
|
-
proxy.
|
|
29937
|
-
|
|
29938
|
-
};
|
|
29939
|
-
process.on("SIGINT", cleanup);
|
|
29940
|
-
process.on("SIGTERM", cleanup);
|
|
30280
|
+
installStandaloneProxyLifecycleHandlers({
|
|
30281
|
+
proxy,
|
|
30282
|
+
log: (source, message) => proxy.logLifecycleEvent(source, message)
|
|
30283
|
+
});
|
|
29941
30284
|
} catch (error2) {
|
|
29942
30285
|
console.error("[Proxy] Fatal error:", error2 instanceof Error ? error2.message : String(error2));
|
|
29943
30286
|
process.exit(1);
|