up-mcp-bridge 1.0.21 → 1.0.22
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/{chunk-AEDNEZ76.js → chunk-FN3ZSOWT.js} +53 -14
- package/dist/client.js +1 -1
- package/dist/proxy.js +7 -4
- package/package.json +1 -1
|
@@ -20163,13 +20163,9 @@ function mcpProxy({
|
|
|
20163
20163
|
let inPersistentRetry = false;
|
|
20164
20164
|
let connectionHealthy = true;
|
|
20165
20165
|
let mcpSessionInitialized = false;
|
|
20166
|
-
const
|
|
20166
|
+
const PRE_INIT_METHODS = /* @__PURE__ */ new Set([
|
|
20167
20167
|
"initialize",
|
|
20168
20168
|
"notifications/initialized",
|
|
20169
|
-
"tools/list",
|
|
20170
|
-
"resources/list",
|
|
20171
|
-
"prompts/list",
|
|
20172
|
-
"resources/templates/list",
|
|
20173
20169
|
"ping"
|
|
20174
20170
|
]);
|
|
20175
20171
|
const pendingMessages = [];
|
|
@@ -20195,6 +20191,7 @@ function mcpProxy({
|
|
|
20195
20191
|
const maxDelayMs = reconnectOptions.maxDelayMs ?? 15e3;
|
|
20196
20192
|
const connectionTimeoutMs = reconnectOptions.connectionTimeoutMs ?? 5e3;
|
|
20197
20193
|
const persistentRetryDelayMs = reconnectOptions.persistentRetryDelayMs ?? 3e4;
|
|
20194
|
+
const maxReconnectDurationMs = reconnectOptions.maxReconnectDurationMs ?? 3e5;
|
|
20198
20195
|
const messageTimeoutMs = 6e4;
|
|
20199
20196
|
const requestTimeoutMs = 5e3;
|
|
20200
20197
|
const maxConsecutiveTimeouts = 3;
|
|
@@ -20654,11 +20651,21 @@ function mcpProxy({
|
|
|
20654
20651
|
log(`Remote transport closed. Starting reconnection loop...`);
|
|
20655
20652
|
debugLog("Remote transport closed, starting reconnection loop", { attempt: reconnectAttempts + 1 });
|
|
20656
20653
|
isReconnecting = true;
|
|
20654
|
+
let persistentStartTime;
|
|
20657
20655
|
while (!transportToClientClosed) {
|
|
20658
20656
|
reconnectAttempts++;
|
|
20659
20657
|
if (!inPersistentRetry && reconnectAttempts > reconnectOptions.maxAttempts) {
|
|
20660
20658
|
inPersistentRetry = true;
|
|
20661
|
-
|
|
20659
|
+
persistentStartTime = Date.now();
|
|
20660
|
+
log(`[Persistent] Entering persistent retry mode after ${reconnectOptions.maxAttempts} fast attempts. Will retry every ${persistentRetryDelayMs / 1e3}s for up to ${maxReconnectDurationMs / 1e3}s before self-destruct.`);
|
|
20661
|
+
}
|
|
20662
|
+
if (inPersistentRetry && persistentStartTime && Date.now() - persistentStartTime > maxReconnectDurationMs) {
|
|
20663
|
+
const elapsedSec = Math.round((Date.now() - persistentStartTime) / 1e3);
|
|
20664
|
+
log(`[BUG-006 Self-destruct] Reconnection failed for ${elapsedSec}s (limit: ${maxReconnectDurationMs / 1e3}s). Exiting process for clean restart.`);
|
|
20665
|
+
flushAllPendingMessagesWithError("Bridge self-destructing after prolonged reconnection failure");
|
|
20666
|
+
clearInterval(statusInterval);
|
|
20667
|
+
stopBackgroundHeartbeat();
|
|
20668
|
+
process.exit(1);
|
|
20662
20669
|
}
|
|
20663
20670
|
let delay;
|
|
20664
20671
|
let logThisAttempt;
|
|
@@ -20735,8 +20742,10 @@ function mcpProxy({
|
|
|
20735
20742
|
log(`[Queue] Flush complete: ${flushedCount} sent, ${expiredCount} expired`);
|
|
20736
20743
|
return;
|
|
20737
20744
|
} catch (error2) {
|
|
20738
|
-
|
|
20739
|
-
|
|
20745
|
+
const errorCode = error2?.code || error2?.event?.code || "unknown";
|
|
20746
|
+
const errorStr = String(error2).substring(0, 200);
|
|
20747
|
+
log(`Reconnection attempt ${reconnectAttempts} failed (HTTP ${errorCode}): ${errorStr}`);
|
|
20748
|
+
debugLog("Reconnection attempt failed", { error: error2, errorCode, attempts: reconnectAttempts, serverUrl });
|
|
20740
20749
|
}
|
|
20741
20750
|
}
|
|
20742
20751
|
log(`Reconnection loop ended: client disconnected after ${reconnectAttempts} attempts.`);
|
|
@@ -20853,12 +20862,12 @@ function mcpProxy({
|
|
|
20853
20862
|
});
|
|
20854
20863
|
return;
|
|
20855
20864
|
}
|
|
20856
|
-
if (!mcpSessionInitialized && !
|
|
20865
|
+
if (!mcpSessionInitialized && !PRE_INIT_METHODS.has(message.method)) {
|
|
20857
20866
|
log(`[BUG-005] Session not initialized, queuing message ${message.id || "(no id)"} (${message.method})`);
|
|
20858
20867
|
log("[Local\u2192Remote] (queuing - session not initialized)", message.method || message.id);
|
|
20859
20868
|
queueMessageForRetry(message);
|
|
20860
20869
|
if (pendingMessages.length === 1) {
|
|
20861
|
-
log("[BUG-005] Messages will be sent after
|
|
20870
|
+
log("[BUG-005] Messages will be sent after notifications/initialized confirms session.");
|
|
20862
20871
|
}
|
|
20863
20872
|
return;
|
|
20864
20873
|
}
|
|
@@ -20880,10 +20889,28 @@ function mcpProxy({
|
|
|
20880
20889
|
log(`[BUG-003 SendSlow] Message ${message.id || "(no id)"} (${message.method}) send() took ${sendDuration}ms`);
|
|
20881
20890
|
}
|
|
20882
20891
|
if (message.method === "notifications/initialized") {
|
|
20883
|
-
|
|
20892
|
+
mcpSessionInitialized = true;
|
|
20893
|
+
log("[MCP Init] notifications/initialized sent to server, session marked as initialized");
|
|
20884
20894
|
const queueSize = pendingMessages.length;
|
|
20885
20895
|
if (queueSize > 0) {
|
|
20886
|
-
log(`[MCP Init] ${queueSize}
|
|
20896
|
+
log(`[MCP Init] Flushing ${queueSize} queued messages after session confirmed`);
|
|
20897
|
+
let flushedCount = 0;
|
|
20898
|
+
while (pendingMessages.length > 0) {
|
|
20899
|
+
const pending = pendingMessages.shift();
|
|
20900
|
+
if (pending.message.id) {
|
|
20901
|
+
queuedMessageIds.delete(pending.message.id);
|
|
20902
|
+
}
|
|
20903
|
+
if (Date.now() - pending.timestamp < messageTimeoutMs) {
|
|
20904
|
+
log(`[MCP Init] Sending queued message ${pending.message.id || "(no id)"} (${pending.message.method})`);
|
|
20905
|
+
trackRequest(pending.message);
|
|
20906
|
+
currentTransportToServer.send(pending.message).catch(onServerError);
|
|
20907
|
+
flushedCount++;
|
|
20908
|
+
} else {
|
|
20909
|
+
log(`[MCP Init] Message ${pending.message.id} expired during init wait`);
|
|
20910
|
+
sendErrorForPendingMessage(pending, "Request timed out waiting for MCP session initialization");
|
|
20911
|
+
}
|
|
20912
|
+
}
|
|
20913
|
+
log(`[MCP Init] Flush complete: ${flushedCount} messages sent`);
|
|
20887
20914
|
}
|
|
20888
20915
|
}
|
|
20889
20916
|
}).catch((error2) => {
|
|
@@ -21318,16 +21345,28 @@ async function parseCommandLineArgs(args, usage) {
|
|
|
21318
21345
|
log(`Warning: Ignoring invalid --persistent-retry-delay value: ${args[persistentRetryDelayIndex + 1]}. Must be a positive number.`);
|
|
21319
21346
|
}
|
|
21320
21347
|
}
|
|
21348
|
+
let maxReconnectDurationMs = 3e5;
|
|
21349
|
+
const maxReconnectDurationIndex = args.indexOf("--max-reconnect-duration");
|
|
21350
|
+
if (maxReconnectDurationIndex !== -1 && maxReconnectDurationIndex < args.length - 1) {
|
|
21351
|
+
const value = parseInt(args[maxReconnectDurationIndex + 1], 10);
|
|
21352
|
+
if (!isNaN(value) && value > 0) {
|
|
21353
|
+
maxReconnectDurationMs = value;
|
|
21354
|
+
log(`Using max reconnect duration: ${maxReconnectDurationMs}ms (${maxReconnectDurationMs / 1e3}s)`);
|
|
21355
|
+
} else {
|
|
21356
|
+
log(`Warning: Ignoring invalid --max-reconnect-duration value: ${args[maxReconnectDurationIndex + 1]}. Must be a positive number.`);
|
|
21357
|
+
}
|
|
21358
|
+
}
|
|
21321
21359
|
const reconnectOptions = {
|
|
21322
21360
|
enabled: autoReconnect,
|
|
21323
21361
|
maxAttempts: maxReconnectAttempts,
|
|
21324
21362
|
baseDelayMs: reconnectDelayMs,
|
|
21325
21363
|
maxDelayMs: maxReconnectDelayMs,
|
|
21326
21364
|
connectionTimeoutMs,
|
|
21327
|
-
persistentRetryDelayMs
|
|
21365
|
+
persistentRetryDelayMs,
|
|
21366
|
+
maxReconnectDurationMs
|
|
21328
21367
|
};
|
|
21329
21368
|
if (autoReconnect) {
|
|
21330
|
-
log(`Auto-reconnect enabled: fast phase: ${maxReconnectAttempts} attempts (${reconnectDelayMs}ms\u2192${maxReconnectDelayMs}ms backoff), persistent phase: every ${persistentRetryDelayMs / 1e3}s
|
|
21369
|
+
log(`Auto-reconnect enabled: fast phase: ${maxReconnectAttempts} attempts (${reconnectDelayMs}ms\u2192${maxReconnectDelayMs}ms backoff), persistent phase: every ${persistentRetryDelayMs / 1e3}s for up to ${maxReconnectDurationMs / 1e3}s`);
|
|
21331
21370
|
}
|
|
21332
21371
|
if (!serverUrl) {
|
|
21333
21372
|
log(usage);
|
package/dist/client.js
CHANGED
package/dist/proxy.js
CHANGED
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
parseCommandLineArgs,
|
|
12
12
|
setupSignalHandlers,
|
|
13
13
|
version
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-FN3ZSOWT.js";
|
|
15
15
|
|
|
16
16
|
// src/proxy.ts
|
|
17
17
|
import { EventEmitter } from "events";
|
|
@@ -131,6 +131,7 @@ Options:
|
|
|
131
131
|
--reconnect-delay N Base delay between fast attempts in ms (default: 1000)
|
|
132
132
|
--max-reconnect-delay N Maximum delay in fast phase in ms (default: 15000)
|
|
133
133
|
--persistent-retry-delay N Fixed delay in persistent phase in ms (default: 30000)
|
|
134
|
+
--max-reconnect-duration N Max time in persistent phase before self-destruct in ms (default: 300000)
|
|
134
135
|
--connection-timeout N Connection timeout in ms (default: 5000)
|
|
135
136
|
--transport STRATEGY Transport strategy: sse-only, http-only, sse-first, http-first
|
|
136
137
|
--header "Key: Value" Add custom header (can be repeated)
|
|
@@ -138,8 +139,10 @@ Options:
|
|
|
138
139
|
|
|
139
140
|
Reconnection behavior (two-phase):
|
|
140
141
|
Fast phase: Attempts 1-N with exponential backoff (1s\u21922s\u21924s\u2192...\u219215s)
|
|
141
|
-
Persistent phase: After N attempts, retries every 30s
|
|
142
|
-
|
|
142
|
+
Persistent phase: After N attempts, retries every 30s for up to 5 minutes
|
|
143
|
+
(configurable via --max-reconnect-duration). If the gateway
|
|
144
|
+
doesn't recover, the bridge exits so the MCP client can
|
|
145
|
+
spawn a fresh process that connects cleanly.
|
|
143
146
|
|
|
144
147
|
Example:
|
|
145
148
|
npx up-mcp-bridge http://localhost:3000/sse --auto-reconnect
|
|
@@ -203,7 +206,7 @@ async function runProxy(serverUrl, callbackPort, headers, transportStrategy = "h
|
|
|
203
206
|
log("Local STDIO server running");
|
|
204
207
|
log(`Proxy established successfully between local STDIO and remote ${remoteTransport.constructor.name}`);
|
|
205
208
|
if (reconnectOptions.enabled) {
|
|
206
|
-
log(`Auto-reconnect enabled (fast: ${reconnectOptions.maxAttempts} attempts, persistent: every ${(reconnectOptions.persistentRetryDelayMs ?? 3e4) / 1e3}s,
|
|
209
|
+
log(`Auto-reconnect enabled (fast: ${reconnectOptions.maxAttempts} attempts, persistent: every ${(reconnectOptions.persistentRetryDelayMs ?? 3e4) / 1e3}s, max duration: ${(reconnectOptions.maxReconnectDurationMs ?? 3e5) / 1e3}s)`);
|
|
207
210
|
}
|
|
208
211
|
log("Press Ctrl+C to exit");
|
|
209
212
|
const cleanup = async () => {
|