mcp-remote 0.1.13 → 0.1.15
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-QAIZEZGG.js → chunk-QW4IRS52.js} +268 -113
- package/dist/client.js +1 -1
- package/dist/proxy.js +4 -4
- package/package.json +21 -10
|
@@ -10301,7 +10301,7 @@ var z = /* @__PURE__ */ Object.freeze({
|
|
|
10301
10301
|
ZodError
|
|
10302
10302
|
});
|
|
10303
10303
|
|
|
10304
|
-
// node_modules/.pnpm/@modelcontextprotocol+sdk@
|
|
10304
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@https+++pkg.pr.new+geelen+typescript-sdk+@modelcontextprotocol+sdk@cdf3508/node_modules/@modelcontextprotocol/sdk/dist/esm/types.js
|
|
10305
10305
|
var LATEST_PROTOCOL_VERSION = "2025-03-26";
|
|
10306
10306
|
var SUPPORTED_PROTOCOL_VERSIONS = [
|
|
10307
10307
|
LATEST_PROTOCOL_VERSION,
|
|
@@ -11126,7 +11126,7 @@ var McpError = class extends Error {
|
|
|
11126
11126
|
}
|
|
11127
11127
|
};
|
|
11128
11128
|
|
|
11129
|
-
// node_modules/.pnpm/@modelcontextprotocol+sdk@
|
|
11129
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@https+++pkg.pr.new+geelen+typescript-sdk+@modelcontextprotocol+sdk@cdf3508/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/protocol.js
|
|
11130
11130
|
var DEFAULT_REQUEST_TIMEOUT_MSEC = 6e4;
|
|
11131
11131
|
var Protocol = class {
|
|
11132
11132
|
constructor(_options) {
|
|
@@ -11472,7 +11472,7 @@ function mergeCapabilities(base, additional) {
|
|
|
11472
11472
|
}, { ...base });
|
|
11473
11473
|
}
|
|
11474
11474
|
|
|
11475
|
-
// node_modules/.pnpm/@modelcontextprotocol+sdk@
|
|
11475
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@https+++pkg.pr.new+geelen+typescript-sdk+@modelcontextprotocol+sdk@cdf3508/node_modules/@modelcontextprotocol/sdk/dist/esm/client/index.js
|
|
11476
11476
|
var import_ajv = __toESM(require_ajv(), 1);
|
|
11477
11477
|
var Client = class extends Protocol {
|
|
11478
11478
|
/**
|
|
@@ -11707,7 +11707,7 @@ var Client = class extends Protocol {
|
|
|
11707
11707
|
};
|
|
11708
11708
|
|
|
11709
11709
|
// package.json
|
|
11710
|
-
var version = "0.1.
|
|
11710
|
+
var version = "0.1.15";
|
|
11711
11711
|
|
|
11712
11712
|
// node_modules/.pnpm/pkce-challenge@5.0.0/node_modules/pkce-challenge/dist/index.node.js
|
|
11713
11713
|
var crypto;
|
|
@@ -11748,7 +11748,7 @@ async function pkceChallenge(length) {
|
|
|
11748
11748
|
};
|
|
11749
11749
|
}
|
|
11750
11750
|
|
|
11751
|
-
// node_modules/.pnpm/@modelcontextprotocol+sdk@
|
|
11751
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@https+++pkg.pr.new+geelen+typescript-sdk+@modelcontextprotocol+sdk@cdf3508/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/auth.js
|
|
11752
11752
|
var OAuthProtectedResourceMetadataSchema = z.object({
|
|
11753
11753
|
resource: z.string().url(),
|
|
11754
11754
|
authorization_servers: z.array(z.string().url()).optional(),
|
|
@@ -11830,13 +11830,130 @@ var OAuthTokenRevocationRequestSchema = z.object({
|
|
|
11830
11830
|
token_type_hint: z.string().optional()
|
|
11831
11831
|
}).strip();
|
|
11832
11832
|
|
|
11833
|
-
// node_modules/.pnpm/@modelcontextprotocol+sdk@
|
|
11833
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@https+++pkg.pr.new+geelen+typescript-sdk+@modelcontextprotocol+sdk@cdf3508/node_modules/@modelcontextprotocol/sdk/dist/esm/server/auth/errors.js
|
|
11834
|
+
var OAuthError = class extends Error {
|
|
11835
|
+
constructor(message, errorUri) {
|
|
11836
|
+
super(message);
|
|
11837
|
+
this.errorUri = errorUri;
|
|
11838
|
+
this.errorCode = this.constructor.errorCode;
|
|
11839
|
+
this.name = this.constructor.name;
|
|
11840
|
+
}
|
|
11841
|
+
/**
|
|
11842
|
+
* Converts the error to a standard OAuth error response object
|
|
11843
|
+
*/
|
|
11844
|
+
toResponseObject() {
|
|
11845
|
+
const response = {
|
|
11846
|
+
error: this.errorCode,
|
|
11847
|
+
error_description: this.message
|
|
11848
|
+
};
|
|
11849
|
+
if (this.errorUri) {
|
|
11850
|
+
response.error_uri = this.errorUri;
|
|
11851
|
+
}
|
|
11852
|
+
return response;
|
|
11853
|
+
}
|
|
11854
|
+
};
|
|
11855
|
+
var InvalidRequestError = class extends OAuthError {
|
|
11856
|
+
};
|
|
11857
|
+
InvalidRequestError.errorCode = "invalid_request";
|
|
11858
|
+
var InvalidClientError = class extends OAuthError {
|
|
11859
|
+
};
|
|
11860
|
+
InvalidClientError.errorCode = "invalid_client";
|
|
11861
|
+
var InvalidGrantError = class extends OAuthError {
|
|
11862
|
+
};
|
|
11863
|
+
InvalidGrantError.errorCode = "invalid_grant";
|
|
11864
|
+
var UnauthorizedClientError = class extends OAuthError {
|
|
11865
|
+
};
|
|
11866
|
+
UnauthorizedClientError.errorCode = "unauthorized_client";
|
|
11867
|
+
var UnsupportedGrantTypeError = class extends OAuthError {
|
|
11868
|
+
};
|
|
11869
|
+
UnsupportedGrantTypeError.errorCode = "unsupported_grant_type";
|
|
11870
|
+
var InvalidScopeError = class extends OAuthError {
|
|
11871
|
+
};
|
|
11872
|
+
InvalidScopeError.errorCode = "invalid_scope";
|
|
11873
|
+
var AccessDeniedError = class extends OAuthError {
|
|
11874
|
+
};
|
|
11875
|
+
AccessDeniedError.errorCode = "access_denied";
|
|
11876
|
+
var ServerError = class extends OAuthError {
|
|
11877
|
+
};
|
|
11878
|
+
ServerError.errorCode = "server_error";
|
|
11879
|
+
var TemporarilyUnavailableError = class extends OAuthError {
|
|
11880
|
+
};
|
|
11881
|
+
TemporarilyUnavailableError.errorCode = "temporarily_unavailable";
|
|
11882
|
+
var UnsupportedResponseTypeError = class extends OAuthError {
|
|
11883
|
+
};
|
|
11884
|
+
UnsupportedResponseTypeError.errorCode = "unsupported_response_type";
|
|
11885
|
+
var UnsupportedTokenTypeError = class extends OAuthError {
|
|
11886
|
+
};
|
|
11887
|
+
UnsupportedTokenTypeError.errorCode = "unsupported_token_type";
|
|
11888
|
+
var InvalidTokenError = class extends OAuthError {
|
|
11889
|
+
};
|
|
11890
|
+
InvalidTokenError.errorCode = "invalid_token";
|
|
11891
|
+
var MethodNotAllowedError = class extends OAuthError {
|
|
11892
|
+
};
|
|
11893
|
+
MethodNotAllowedError.errorCode = "method_not_allowed";
|
|
11894
|
+
var TooManyRequestsError = class extends OAuthError {
|
|
11895
|
+
};
|
|
11896
|
+
TooManyRequestsError.errorCode = "too_many_requests";
|
|
11897
|
+
var InvalidClientMetadataError = class extends OAuthError {
|
|
11898
|
+
};
|
|
11899
|
+
InvalidClientMetadataError.errorCode = "invalid_client_metadata";
|
|
11900
|
+
var InsufficientScopeError = class extends OAuthError {
|
|
11901
|
+
};
|
|
11902
|
+
InsufficientScopeError.errorCode = "insufficient_scope";
|
|
11903
|
+
var OAUTH_ERRORS = {
|
|
11904
|
+
[InvalidRequestError.errorCode]: InvalidRequestError,
|
|
11905
|
+
[InvalidClientError.errorCode]: InvalidClientError,
|
|
11906
|
+
[InvalidGrantError.errorCode]: InvalidGrantError,
|
|
11907
|
+
[UnauthorizedClientError.errorCode]: UnauthorizedClientError,
|
|
11908
|
+
[UnsupportedGrantTypeError.errorCode]: UnsupportedGrantTypeError,
|
|
11909
|
+
[InvalidScopeError.errorCode]: InvalidScopeError,
|
|
11910
|
+
[AccessDeniedError.errorCode]: AccessDeniedError,
|
|
11911
|
+
[ServerError.errorCode]: ServerError,
|
|
11912
|
+
[TemporarilyUnavailableError.errorCode]: TemporarilyUnavailableError,
|
|
11913
|
+
[UnsupportedResponseTypeError.errorCode]: UnsupportedResponseTypeError,
|
|
11914
|
+
[UnsupportedTokenTypeError.errorCode]: UnsupportedTokenTypeError,
|
|
11915
|
+
[InvalidTokenError.errorCode]: InvalidTokenError,
|
|
11916
|
+
[MethodNotAllowedError.errorCode]: MethodNotAllowedError,
|
|
11917
|
+
[TooManyRequestsError.errorCode]: TooManyRequestsError,
|
|
11918
|
+
[InvalidClientMetadataError.errorCode]: InvalidClientMetadataError,
|
|
11919
|
+
[InsufficientScopeError.errorCode]: InsufficientScopeError
|
|
11920
|
+
};
|
|
11921
|
+
|
|
11922
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@https+++pkg.pr.new+geelen+typescript-sdk+@modelcontextprotocol+sdk@cdf3508/node_modules/@modelcontextprotocol/sdk/dist/esm/client/auth.js
|
|
11834
11923
|
var UnauthorizedError = class extends Error {
|
|
11835
11924
|
constructor(message) {
|
|
11836
11925
|
super(message !== null && message !== void 0 ? message : "Unauthorized");
|
|
11837
11926
|
}
|
|
11838
11927
|
};
|
|
11839
|
-
async function
|
|
11928
|
+
async function parseErrorResponse(input) {
|
|
11929
|
+
const statusCode = input instanceof Response ? input.status : void 0;
|
|
11930
|
+
const body = input instanceof Response ? await input.text() : input;
|
|
11931
|
+
try {
|
|
11932
|
+
const result = OAuthErrorResponseSchema.parse(JSON.parse(body));
|
|
11933
|
+
const { error, error_description, error_uri } = result;
|
|
11934
|
+
const errorClass = OAUTH_ERRORS[error] || ServerError;
|
|
11935
|
+
return new errorClass(error_description || "", error_uri);
|
|
11936
|
+
} catch (error) {
|
|
11937
|
+
const errorMessage = `${statusCode ? `HTTP ${statusCode}: ` : ""}Invalid OAuth error response: ${error}. Raw body: ${body}`;
|
|
11938
|
+
return new ServerError(errorMessage);
|
|
11939
|
+
}
|
|
11940
|
+
}
|
|
11941
|
+
async function auth(provider, options) {
|
|
11942
|
+
var _a, _b;
|
|
11943
|
+
try {
|
|
11944
|
+
return await authInternal(provider, options);
|
|
11945
|
+
} catch (error) {
|
|
11946
|
+
if (error instanceof InvalidClientError || error instanceof UnauthorizedClientError) {
|
|
11947
|
+
await ((_a = provider.invalidateCredentials) === null || _a === void 0 ? void 0 : _a.call(provider, "all"));
|
|
11948
|
+
return await authInternal(provider, options);
|
|
11949
|
+
} else if (error instanceof InvalidGrantError) {
|
|
11950
|
+
await ((_b = provider.invalidateCredentials) === null || _b === void 0 ? void 0 : _b.call(provider, "tokens"));
|
|
11951
|
+
return await authInternal(provider, options);
|
|
11952
|
+
}
|
|
11953
|
+
throw error;
|
|
11954
|
+
}
|
|
11955
|
+
}
|
|
11956
|
+
async function authInternal(provider, { serverUrl, authorizationCode, scope, resourceMetadataUrl }) {
|
|
11840
11957
|
let authorizationServerUrl = serverUrl;
|
|
11841
11958
|
try {
|
|
11842
11959
|
const resourceMetadata = await discoverOAuthProtectedResourceMetadata(resourceMetadataUrl || serverUrl);
|
|
@@ -11885,7 +12002,12 @@ async function auth(provider, { serverUrl, authorizationCode, scope, resourceMet
|
|
|
11885
12002
|
await provider.saveTokens(newTokens);
|
|
11886
12003
|
return "AUTHORIZED";
|
|
11887
12004
|
} catch (error) {
|
|
11888
|
-
|
|
12005
|
+
if (!(error instanceof OAuthError) || error instanceof ServerError) {
|
|
12006
|
+
console.error("Could not refresh OAuth tokens:", error);
|
|
12007
|
+
} else {
|
|
12008
|
+
console.warn(`OAuth token refresh failed: ${JSON.stringify(error.toResponseObject())}`);
|
|
12009
|
+
throw error;
|
|
12010
|
+
}
|
|
11889
12011
|
}
|
|
11890
12012
|
}
|
|
11891
12013
|
const state = provider.state ? await provider.state() : void 0;
|
|
@@ -12037,7 +12159,7 @@ async function exchangeAuthorization(authorizationServerUrl, { metadata, clientI
|
|
|
12037
12159
|
body: params
|
|
12038
12160
|
});
|
|
12039
12161
|
if (!response.ok) {
|
|
12040
|
-
throw
|
|
12162
|
+
throw await parseErrorResponse(response);
|
|
12041
12163
|
}
|
|
12042
12164
|
return OAuthTokensSchema.parse(await response.json());
|
|
12043
12165
|
}
|
|
@@ -12068,7 +12190,7 @@ async function refreshAuthorization(authorizationServerUrl, { metadata, clientIn
|
|
|
12068
12190
|
body: params
|
|
12069
12191
|
});
|
|
12070
12192
|
if (!response.ok) {
|
|
12071
|
-
throw
|
|
12193
|
+
throw await parseErrorResponse(response);
|
|
12072
12194
|
}
|
|
12073
12195
|
return OAuthTokensSchema.parse({ refresh_token: refreshToken, ...await response.json() });
|
|
12074
12196
|
}
|
|
@@ -12090,7 +12212,7 @@ async function registerClient(authorizationServerUrl, { metadata, clientMetadata
|
|
|
12090
12212
|
body: JSON.stringify(clientMetadata)
|
|
12091
12213
|
});
|
|
12092
12214
|
if (!response.ok) {
|
|
12093
|
-
throw
|
|
12215
|
+
throw await parseErrorResponse(response);
|
|
12094
12216
|
}
|
|
12095
12217
|
return OAuthClientInformationFullSchema.parse(await response.json());
|
|
12096
12218
|
}
|
|
@@ -12495,7 +12617,7 @@ function getBaseURL() {
|
|
|
12495
12617
|
return doc && typeof doc == "object" && "baseURI" in doc && typeof doc.baseURI == "string" ? doc.baseURI : void 0;
|
|
12496
12618
|
}
|
|
12497
12619
|
|
|
12498
|
-
// node_modules/.pnpm/@modelcontextprotocol+sdk@
|
|
12620
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@https+++pkg.pr.new+geelen+typescript-sdk+@modelcontextprotocol+sdk@cdf3508/node_modules/@modelcontextprotocol/sdk/dist/esm/client/sse.js
|
|
12499
12621
|
var SseError = class extends Error {
|
|
12500
12622
|
constructor(code, message, event) {
|
|
12501
12623
|
super(`SSE error: ${message}`);
|
|
@@ -12678,7 +12800,7 @@ var EventSourceParserStream = class extends TransformStream {
|
|
|
12678
12800
|
}
|
|
12679
12801
|
};
|
|
12680
12802
|
|
|
12681
|
-
// node_modules/.pnpm/@modelcontextprotocol+sdk@
|
|
12803
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@https+++pkg.pr.new+geelen+typescript-sdk+@modelcontextprotocol+sdk@cdf3508/node_modules/@modelcontextprotocol/sdk/dist/esm/client/streamableHttp.js
|
|
12682
12804
|
var DEFAULT_STREAMABLE_HTTP_RECONNECTION_OPTIONS = {
|
|
12683
12805
|
initialReconnectionDelay: 1e3,
|
|
12684
12806
|
maxReconnectionDelay: 3e4,
|
|
@@ -13082,9 +13204,9 @@ async function writeTextFile(serverUrlHash, filename, text) {
|
|
|
13082
13204
|
import express from "express";
|
|
13083
13205
|
import net from "net";
|
|
13084
13206
|
import crypto2 from "crypto";
|
|
13085
|
-
import fs2
|
|
13207
|
+
import fs2 from "fs";
|
|
13208
|
+
import { readFile, rm } from "fs/promises";
|
|
13086
13209
|
import path2 from "path";
|
|
13087
|
-
import os2 from "os";
|
|
13088
13210
|
var REASON_AUTH_NEEDED = "authentication-needed";
|
|
13089
13211
|
var REASON_TRANSPORT_FALLBACK = "falling-back-to-alternate-transport";
|
|
13090
13212
|
var pid = process.pid;
|
|
@@ -13093,7 +13215,7 @@ function getTimestamp() {
|
|
|
13093
13215
|
const now = /* @__PURE__ */ new Date();
|
|
13094
13216
|
return now.toISOString();
|
|
13095
13217
|
}
|
|
13096
|
-
|
|
13218
|
+
function debugLog(message, ...args) {
|
|
13097
13219
|
if (!DEBUG) return;
|
|
13098
13220
|
const serverUrlHash = global.currentServerUrlHash;
|
|
13099
13221
|
if (!serverUrlHash) {
|
|
@@ -13103,12 +13225,12 @@ async function debugLog(message, ...args) {
|
|
|
13103
13225
|
try {
|
|
13104
13226
|
const formattedMessage = `[${getTimestamp()}][${pid}] ${message}`;
|
|
13105
13227
|
console.error(formattedMessage, ...args);
|
|
13106
|
-
const configDir =
|
|
13107
|
-
|
|
13228
|
+
const configDir = getConfigDir();
|
|
13229
|
+
fs2.mkdirSync(configDir, { recursive: true });
|
|
13108
13230
|
const logPath = path2.join(configDir, `${serverUrlHash}_debug.log`);
|
|
13109
13231
|
const logMessage = `${formattedMessage} ${args.map((arg) => typeof arg === "object" ? JSON.stringify(arg) : String(arg)).join(" ")}
|
|
13110
13232
|
`;
|
|
13111
|
-
|
|
13233
|
+
fs2.appendFileSync(logPath, logMessage, { encoding: "utf8" });
|
|
13112
13234
|
} catch (error) {
|
|
13113
13235
|
console.error(`[DEBUG LOG ERROR] ${error}`);
|
|
13114
13236
|
}
|
|
@@ -13116,8 +13238,7 @@ async function debugLog(message, ...args) {
|
|
|
13116
13238
|
function log(str, ...rest) {
|
|
13117
13239
|
console.error(`[${pid}] ${str}`, ...rest);
|
|
13118
13240
|
if (DEBUG && global.currentServerUrlHash) {
|
|
13119
|
-
debugLog(str, ...rest)
|
|
13120
|
-
});
|
|
13241
|
+
debugLog(str, ...rest);
|
|
13121
13242
|
}
|
|
13122
13243
|
}
|
|
13123
13244
|
function mcpProxy({ transportToClient, transportToServer }) {
|
|
@@ -13131,7 +13252,6 @@ function mcpProxy({ transportToClient, transportToServer }) {
|
|
|
13131
13252
|
method: message.method,
|
|
13132
13253
|
id: message.id,
|
|
13133
13254
|
params: message.params ? JSON.stringify(message.params).substring(0, 500) : void 0
|
|
13134
|
-
}).catch(() => {
|
|
13135
13255
|
});
|
|
13136
13256
|
}
|
|
13137
13257
|
if (message.method === "initialize") {
|
|
@@ -13139,8 +13259,7 @@ function mcpProxy({ transportToClient, transportToServer }) {
|
|
|
13139
13259
|
if (clientInfo) clientInfo.name = `${clientInfo.name} (via mcp-remote ${version})`;
|
|
13140
13260
|
log(JSON.stringify(message, null, 2));
|
|
13141
13261
|
if (DEBUG) {
|
|
13142
|
-
debugLog("Initialize message with modified client info", { clientInfo })
|
|
13143
|
-
});
|
|
13262
|
+
debugLog("Initialize message with modified client info", { clientInfo });
|
|
13144
13263
|
}
|
|
13145
13264
|
}
|
|
13146
13265
|
transportToServer.send(message).catch(onServerError);
|
|
@@ -13154,7 +13273,6 @@ function mcpProxy({ transportToClient, transportToServer }) {
|
|
|
13154
13273
|
id: message.id,
|
|
13155
13274
|
result: message.result ? "result-present" : void 0,
|
|
13156
13275
|
error: message.error
|
|
13157
|
-
}).catch(() => {
|
|
13158
13276
|
});
|
|
13159
13277
|
}
|
|
13160
13278
|
transportToClient.send(message).catch(onClientError);
|
|
@@ -13164,8 +13282,7 @@ function mcpProxy({ transportToClient, transportToServer }) {
|
|
|
13164
13282
|
return;
|
|
13165
13283
|
}
|
|
13166
13284
|
transportToClientClosed = true;
|
|
13167
|
-
if (DEBUG) debugLog("Local transport closed, closing remote transport")
|
|
13168
|
-
});
|
|
13285
|
+
if (DEBUG) debugLog("Local transport closed, closing remote transport");
|
|
13169
13286
|
transportToServer.close().catch(onServerError);
|
|
13170
13287
|
};
|
|
13171
13288
|
transportToServer.onclose = () => {
|
|
@@ -13173,21 +13290,18 @@ function mcpProxy({ transportToClient, transportToServer }) {
|
|
|
13173
13290
|
return;
|
|
13174
13291
|
}
|
|
13175
13292
|
transportToServerClosed = true;
|
|
13176
|
-
if (DEBUG) debugLog("Remote transport closed, closing local transport")
|
|
13177
|
-
});
|
|
13293
|
+
if (DEBUG) debugLog("Remote transport closed, closing local transport");
|
|
13178
13294
|
transportToClient.close().catch(onClientError);
|
|
13179
13295
|
};
|
|
13180
13296
|
transportToClient.onerror = onClientError;
|
|
13181
13297
|
transportToServer.onerror = onServerError;
|
|
13182
13298
|
function onClientError(error) {
|
|
13183
13299
|
log("Error from local client:", error);
|
|
13184
|
-
if (DEBUG) debugLog("Error from local client", {
|
|
13185
|
-
});
|
|
13300
|
+
if (DEBUG) debugLog("Error from local client", { stack: error.stack });
|
|
13186
13301
|
}
|
|
13187
13302
|
function onServerError(error) {
|
|
13188
13303
|
log("Error from remote server:", error);
|
|
13189
|
-
if (DEBUG) debugLog("Error from remote server", {
|
|
13190
|
-
});
|
|
13304
|
+
if (DEBUG) debugLog("Error from remote server", { stack: error.stack });
|
|
13191
13305
|
}
|
|
13192
13306
|
}
|
|
13193
13307
|
async function connectToRemoteServer(client, serverUrl, authProvider, headers, authInitializer, transportStrategy = "http-first", recursionReasons = /* @__PURE__ */ new Set()) {
|
|
@@ -13220,22 +13334,21 @@ async function connectToRemoteServer(client, serverUrl, authProvider, headers, a
|
|
|
13220
13334
|
requestInit: { headers }
|
|
13221
13335
|
});
|
|
13222
13336
|
try {
|
|
13223
|
-
if (DEBUG)
|
|
13337
|
+
if (DEBUG) debugLog("Attempting to connect to remote server", { sseTransport });
|
|
13224
13338
|
if (client) {
|
|
13225
|
-
if (DEBUG)
|
|
13339
|
+
if (DEBUG) debugLog("Connecting client to transport");
|
|
13226
13340
|
await client.connect(transport);
|
|
13227
13341
|
} else {
|
|
13228
|
-
if (DEBUG)
|
|
13342
|
+
if (DEBUG) debugLog("Starting transport directly");
|
|
13229
13343
|
await transport.start();
|
|
13230
13344
|
if (!sseTransport) {
|
|
13231
|
-
if (DEBUG)
|
|
13345
|
+
if (DEBUG) debugLog("Creating test transport for HTTP-only connection test");
|
|
13232
13346
|
const testTransport = new StreamableHTTPClientTransport(url, { authProvider, requestInit: { headers } });
|
|
13233
13347
|
const testClient = new Client({ name: "mcp-remote-fallback-test", version: "0.0.0" }, { capabilities: {} });
|
|
13234
13348
|
await testClient.connect(testTransport);
|
|
13235
13349
|
}
|
|
13236
13350
|
}
|
|
13237
13351
|
log(`Connected to remote server using ${transport.constructor.name}`);
|
|
13238
|
-
if (DEBUG) await debugLog(`Connected to remote server successfully`, { transportType: transport.constructor.name });
|
|
13239
13352
|
return transport;
|
|
13240
13353
|
} catch (error) {
|
|
13241
13354
|
if (error instanceof Error && shouldAttemptFallback && (error.message.includes("405") || error.message.includes("Method Not Allowed") || error.message.includes("404") || error.message.includes("Not Found"))) {
|
|
@@ -13259,47 +13372,52 @@ async function connectToRemoteServer(client, serverUrl, authProvider, headers, a
|
|
|
13259
13372
|
} else if (error instanceof UnauthorizedError || error instanceof Error && error.message.includes("Unauthorized")) {
|
|
13260
13373
|
log("Authentication required. Initializing auth...");
|
|
13261
13374
|
if (DEBUG) {
|
|
13262
|
-
|
|
13375
|
+
debugLog("Authentication error detected", {
|
|
13376
|
+
errorCode: error instanceof OAuthError ? error.errorCode : void 0,
|
|
13263
13377
|
errorMessage: error.message,
|
|
13264
13378
|
stack: error.stack
|
|
13265
13379
|
});
|
|
13266
13380
|
}
|
|
13267
|
-
if (DEBUG)
|
|
13381
|
+
if (DEBUG) debugLog("Calling authInitializer to start auth flow");
|
|
13268
13382
|
const { waitForAuthCode, skipBrowserAuth } = await authInitializer();
|
|
13269
13383
|
if (skipBrowserAuth) {
|
|
13270
13384
|
log("Authentication required but skipping browser auth - using shared auth");
|
|
13271
|
-
if (DEBUG) await debugLog("Authentication required but skipping browser auth - using shared auth");
|
|
13272
13385
|
} else {
|
|
13273
13386
|
log("Authentication required. Waiting for authorization...");
|
|
13274
|
-
if (DEBUG) await debugLog("Authentication required. Waiting for authorization...");
|
|
13275
13387
|
}
|
|
13276
|
-
if (DEBUG)
|
|
13388
|
+
if (DEBUG) debugLog("Waiting for auth code from callback server");
|
|
13277
13389
|
const code = await waitForAuthCode();
|
|
13278
|
-
if (DEBUG)
|
|
13390
|
+
if (DEBUG) debugLog("Received auth code from callback server");
|
|
13279
13391
|
try {
|
|
13280
13392
|
log("Completing authorization...");
|
|
13281
|
-
if (DEBUG) await debugLog("Completing authorization with transport.finishAuth");
|
|
13282
13393
|
await transport.finishAuth(code);
|
|
13283
|
-
if (DEBUG)
|
|
13394
|
+
if (DEBUG) debugLog("Authorization completed successfully");
|
|
13284
13395
|
if (recursionReasons.has(REASON_AUTH_NEEDED)) {
|
|
13285
13396
|
const errorMessage = `Already attempted reconnection for reason: ${REASON_AUTH_NEEDED}. Giving up.`;
|
|
13286
13397
|
log(errorMessage);
|
|
13287
|
-
if (DEBUG)
|
|
13398
|
+
if (DEBUG)
|
|
13399
|
+
debugLog("Already attempted auth reconnection, giving up", {
|
|
13400
|
+
recursionReasons: Array.from(recursionReasons)
|
|
13401
|
+
});
|
|
13288
13402
|
throw new Error(errorMessage);
|
|
13289
13403
|
}
|
|
13290
13404
|
recursionReasons.add(REASON_AUTH_NEEDED);
|
|
13291
13405
|
log(`Recursively reconnecting for reason: ${REASON_AUTH_NEEDED}`);
|
|
13292
|
-
if (DEBUG)
|
|
13406
|
+
if (DEBUG) debugLog("Recursively reconnecting after auth", { recursionReasons: Array.from(recursionReasons) });
|
|
13293
13407
|
return connectToRemoteServer(client, serverUrl, authProvider, headers, authInitializer, transportStrategy, recursionReasons);
|
|
13294
13408
|
} catch (authError) {
|
|
13295
13409
|
log("Authorization error:", authError);
|
|
13296
|
-
if (DEBUG)
|
|
13410
|
+
if (DEBUG)
|
|
13411
|
+
debugLog("Authorization error during finishAuth", {
|
|
13412
|
+
errorMessage: authError.message,
|
|
13413
|
+
stack: authError.stack
|
|
13414
|
+
});
|
|
13297
13415
|
throw authError;
|
|
13298
13416
|
}
|
|
13299
13417
|
} else {
|
|
13300
13418
|
log("Connection error:", error);
|
|
13301
13419
|
if (DEBUG)
|
|
13302
|
-
|
|
13420
|
+
debugLog("Connection error", {
|
|
13303
13421
|
errorMessage: error.message,
|
|
13304
13422
|
stack: error.stack,
|
|
13305
13423
|
transportType: transport.constructor.name
|
|
@@ -13497,8 +13615,7 @@ async function parseCommandLineArgs(args, usage) {
|
|
|
13497
13615
|
const serverUrlHash = getServerUrlHash(serverUrl);
|
|
13498
13616
|
global.currentServerUrlHash = serverUrlHash;
|
|
13499
13617
|
if (DEBUG) {
|
|
13500
|
-
debugLog(`Starting mcp-remote with server URL: ${serverUrl}`)
|
|
13501
|
-
});
|
|
13618
|
+
debugLog(`Starting mcp-remote with server URL: ${serverUrl}`);
|
|
13502
13619
|
}
|
|
13503
13620
|
const defaultPort = calculateDefaultPort(serverUrlHash);
|
|
13504
13621
|
const [existingClientPort, availablePort] = await Promise.all([findExistingClientPort(serverUrlHash), findAvailablePort(defaultPort)]);
|
|
@@ -13508,7 +13625,7 @@ async function parseCommandLineArgs(args, usage) {
|
|
|
13508
13625
|
log(
|
|
13509
13626
|
`Warning! Specified callback port of ${specifiedPort}, which conflicts with existing client registration port ${existingClientPort}. Deleting existing client data to force reregistration.`
|
|
13510
13627
|
);
|
|
13511
|
-
await
|
|
13628
|
+
await rm(getConfigFilePath(serverUrlHash, "client_info.json"));
|
|
13512
13629
|
}
|
|
13513
13630
|
log(`Using specified callback port: ${specifiedPort}`);
|
|
13514
13631
|
callbackPort = specifiedPort;
|
|
@@ -13552,6 +13669,26 @@ function setupSignalHandlers(cleanup) {
|
|
|
13552
13669
|
function getServerUrlHash(serverUrl) {
|
|
13553
13670
|
return crypto2.createHash("md5").update(serverUrl).digest("hex");
|
|
13554
13671
|
}
|
|
13672
|
+
function sanitizeUrl(raw) {
|
|
13673
|
+
const abort = () => {
|
|
13674
|
+
throw new Error(`Invalid url to pass to open(): ${raw}`);
|
|
13675
|
+
};
|
|
13676
|
+
let url;
|
|
13677
|
+
try {
|
|
13678
|
+
url = new URL(raw);
|
|
13679
|
+
} catch (_) {
|
|
13680
|
+
abort();
|
|
13681
|
+
}
|
|
13682
|
+
if (url.protocol !== "https:" && url.protocol !== "http:") abort();
|
|
13683
|
+
if (url.hostname !== encodeURIComponent(url.hostname)) abort();
|
|
13684
|
+
url.pathname = url.pathname.slice(0, 1) + encodeURIComponent(url.pathname.slice(1)).replace(/%2f/ig, "/");
|
|
13685
|
+
url.search = url.search.slice(0, 1) + Array.from(url.searchParams.entries()).map(sanitizeParam).join("&");
|
|
13686
|
+
url.hash = url.hash.slice(0, 1) + encodeURIComponent(url.hash.slice(1));
|
|
13687
|
+
return url.href;
|
|
13688
|
+
}
|
|
13689
|
+
function sanitizeParam([k, v]) {
|
|
13690
|
+
return `${encodeURIComponent(k)}${v.length > 0 ? `=${encodeURIComponent(v)}` : ""}`;
|
|
13691
|
+
}
|
|
13555
13692
|
|
|
13556
13693
|
// src/lib/node-oauth-client-provider.ts
|
|
13557
13694
|
import open from "open";
|
|
@@ -13606,9 +13743,9 @@ var NodeOAuthClientProvider = class {
|
|
|
13606
13743
|
* @returns The client information or undefined
|
|
13607
13744
|
*/
|
|
13608
13745
|
async clientInformation() {
|
|
13609
|
-
if (DEBUG)
|
|
13746
|
+
if (DEBUG) debugLog("Reading client info");
|
|
13610
13747
|
if (this.staticOAuthClientInfo) {
|
|
13611
|
-
if (DEBUG)
|
|
13748
|
+
if (DEBUG) debugLog("Returning static client info");
|
|
13612
13749
|
return this.staticOAuthClientInfo;
|
|
13613
13750
|
}
|
|
13614
13751
|
const clientInfo = await readJsonFile(
|
|
@@ -13616,7 +13753,7 @@ var NodeOAuthClientProvider = class {
|
|
|
13616
13753
|
"client_info.json",
|
|
13617
13754
|
OAuthClientInformationFullSchema
|
|
13618
13755
|
);
|
|
13619
|
-
if (DEBUG)
|
|
13756
|
+
if (DEBUG) debugLog("Client info result:", clientInfo ? "Found" : "Not found");
|
|
13620
13757
|
return clientInfo;
|
|
13621
13758
|
}
|
|
13622
13759
|
/**
|
|
@@ -13624,7 +13761,7 @@ var NodeOAuthClientProvider = class {
|
|
|
13624
13761
|
* @param clientInformation The client information to save
|
|
13625
13762
|
*/
|
|
13626
13763
|
async saveClientInformation(clientInformation) {
|
|
13627
|
-
if (DEBUG)
|
|
13764
|
+
if (DEBUG) debugLog("Saving client info", { client_id: clientInformation.client_id });
|
|
13628
13765
|
await writeJsonFile(this.serverUrlHash, "client_info.json", clientInformation);
|
|
13629
13766
|
}
|
|
13630
13767
|
/**
|
|
@@ -13633,21 +13770,21 @@ var NodeOAuthClientProvider = class {
|
|
|
13633
13770
|
*/
|
|
13634
13771
|
async tokens() {
|
|
13635
13772
|
if (DEBUG) {
|
|
13636
|
-
|
|
13637
|
-
|
|
13773
|
+
debugLog("Reading OAuth tokens");
|
|
13774
|
+
debugLog("Token request stack trace:", new Error().stack);
|
|
13638
13775
|
}
|
|
13639
13776
|
const tokens = await readJsonFile(this.serverUrlHash, "tokens.json", OAuthTokensSchema);
|
|
13640
13777
|
if (DEBUG) {
|
|
13641
13778
|
if (tokens) {
|
|
13642
13779
|
const timeLeft = tokens.expires_in || 0;
|
|
13643
13780
|
if (typeof tokens.expires_in !== "number" || tokens.expires_in < 0) {
|
|
13644
|
-
|
|
13781
|
+
debugLog("\u26A0\uFE0F WARNING: Invalid expires_in detected while reading tokens \u26A0\uFE0F", {
|
|
13645
13782
|
expiresIn: tokens.expires_in,
|
|
13646
13783
|
tokenObject: JSON.stringify(tokens),
|
|
13647
13784
|
stack: new Error("Invalid expires_in value").stack
|
|
13648
13785
|
});
|
|
13649
13786
|
}
|
|
13650
|
-
|
|
13787
|
+
debugLog("Token result:", {
|
|
13651
13788
|
found: true,
|
|
13652
13789
|
hasAccessToken: !!tokens.access_token,
|
|
13653
13790
|
hasRefreshToken: !!tokens.refresh_token,
|
|
@@ -13656,7 +13793,7 @@ var NodeOAuthClientProvider = class {
|
|
|
13656
13793
|
expiresInValue: tokens.expires_in
|
|
13657
13794
|
});
|
|
13658
13795
|
} else {
|
|
13659
|
-
|
|
13796
|
+
debugLog("Token result: Not found");
|
|
13660
13797
|
}
|
|
13661
13798
|
}
|
|
13662
13799
|
return tokens;
|
|
@@ -13669,13 +13806,13 @@ var NodeOAuthClientProvider = class {
|
|
|
13669
13806
|
if (DEBUG) {
|
|
13670
13807
|
const timeLeft = tokens.expires_in || 0;
|
|
13671
13808
|
if (typeof tokens.expires_in !== "number" || tokens.expires_in < 0) {
|
|
13672
|
-
|
|
13809
|
+
debugLog("\u26A0\uFE0F WARNING: Invalid expires_in detected in tokens \u26A0\uFE0F", {
|
|
13673
13810
|
expiresIn: tokens.expires_in,
|
|
13674
13811
|
tokenObject: JSON.stringify(tokens),
|
|
13675
13812
|
stack: new Error("Invalid expires_in value").stack
|
|
13676
13813
|
});
|
|
13677
13814
|
}
|
|
13678
|
-
|
|
13815
|
+
debugLog("Saving tokens", {
|
|
13679
13816
|
hasAccessToken: !!tokens.access_token,
|
|
13680
13817
|
hasRefreshToken: !!tokens.refresh_token,
|
|
13681
13818
|
expiresIn: `${timeLeft} seconds`,
|
|
@@ -13693,14 +13830,13 @@ var NodeOAuthClientProvider = class {
|
|
|
13693
13830
|
Please authorize this client by visiting:
|
|
13694
13831
|
${authorizationUrl.toString()}
|
|
13695
13832
|
`);
|
|
13696
|
-
if (DEBUG)
|
|
13833
|
+
if (DEBUG) debugLog("Redirecting to authorization URL", authorizationUrl.toString());
|
|
13697
13834
|
try {
|
|
13698
|
-
await open(authorizationUrl.toString());
|
|
13835
|
+
await open(sanitizeUrl(authorizationUrl.toString()));
|
|
13699
13836
|
log("Browser opened automatically.");
|
|
13700
|
-
if (DEBUG) await debugLog(this.serverUrlHash, "Browser opened automatically");
|
|
13701
13837
|
} catch (error) {
|
|
13702
13838
|
log("Could not open browser automatically. Please copy and paste the URL above into your browser.");
|
|
13703
|
-
if (DEBUG)
|
|
13839
|
+
if (DEBUG) debugLog("Failed to open browser", error);
|
|
13704
13840
|
}
|
|
13705
13841
|
}
|
|
13706
13842
|
/**
|
|
@@ -13708,7 +13844,7 @@ ${authorizationUrl.toString()}
|
|
|
13708
13844
|
* @param codeVerifier The code verifier to save
|
|
13709
13845
|
*/
|
|
13710
13846
|
async saveCodeVerifier(codeVerifier) {
|
|
13711
|
-
if (DEBUG)
|
|
13847
|
+
if (DEBUG) debugLog("Saving code verifier");
|
|
13712
13848
|
await writeTextFile(this.serverUrlHash, "code_verifier.txt", codeVerifier);
|
|
13713
13849
|
}
|
|
13714
13850
|
/**
|
|
@@ -13716,11 +13852,42 @@ ${authorizationUrl.toString()}
|
|
|
13716
13852
|
* @returns The code verifier
|
|
13717
13853
|
*/
|
|
13718
13854
|
async codeVerifier() {
|
|
13719
|
-
if (DEBUG)
|
|
13855
|
+
if (DEBUG) debugLog("Reading code verifier");
|
|
13720
13856
|
const verifier = await readTextFile(this.serverUrlHash, "code_verifier.txt", "No code verifier saved for session");
|
|
13721
|
-
if (DEBUG)
|
|
13857
|
+
if (DEBUG) debugLog("Code verifier found:", !!verifier);
|
|
13722
13858
|
return verifier;
|
|
13723
13859
|
}
|
|
13860
|
+
/**
|
|
13861
|
+
* Invalidates the specified credentials
|
|
13862
|
+
* @param scope The scope of credentials to invalidate
|
|
13863
|
+
*/
|
|
13864
|
+
async invalidateCredentials(scope) {
|
|
13865
|
+
if (DEBUG) debugLog(`Invalidating credentials: ${scope}`);
|
|
13866
|
+
switch (scope) {
|
|
13867
|
+
case "all":
|
|
13868
|
+
await Promise.all([
|
|
13869
|
+
deleteConfigFile(this.serverUrlHash, "client_info.json"),
|
|
13870
|
+
deleteConfigFile(this.serverUrlHash, "tokens.json"),
|
|
13871
|
+
deleteConfigFile(this.serverUrlHash, "code_verifier.txt")
|
|
13872
|
+
]);
|
|
13873
|
+
if (DEBUG) debugLog("All credentials invalidated");
|
|
13874
|
+
break;
|
|
13875
|
+
case "client":
|
|
13876
|
+
await deleteConfigFile(this.serverUrlHash, "client_info.json");
|
|
13877
|
+
if (DEBUG) debugLog("Client information invalidated");
|
|
13878
|
+
break;
|
|
13879
|
+
case "tokens":
|
|
13880
|
+
await deleteConfigFile(this.serverUrlHash, "tokens.json");
|
|
13881
|
+
if (DEBUG) debugLog("OAuth tokens invalidated");
|
|
13882
|
+
break;
|
|
13883
|
+
case "verifier":
|
|
13884
|
+
await deleteConfigFile(this.serverUrlHash, "code_verifier.txt");
|
|
13885
|
+
if (DEBUG) debugLog("Code verifier invalidated");
|
|
13886
|
+
break;
|
|
13887
|
+
default:
|
|
13888
|
+
throw new Error(`Unknown credential scope: ${scope}`);
|
|
13889
|
+
}
|
|
13890
|
+
}
|
|
13724
13891
|
};
|
|
13725
13892
|
|
|
13726
13893
|
// src/lib/coordination.ts
|
|
@@ -13729,20 +13896,20 @@ import { unlinkSync } from "fs";
|
|
|
13729
13896
|
async function isPidRunning(pid2) {
|
|
13730
13897
|
try {
|
|
13731
13898
|
process.kill(pid2, 0);
|
|
13732
|
-
if (DEBUG)
|
|
13899
|
+
if (DEBUG) debugLog(`Process ${pid2} is running`);
|
|
13733
13900
|
return true;
|
|
13734
13901
|
} catch (err) {
|
|
13735
|
-
if (DEBUG)
|
|
13902
|
+
if (DEBUG) debugLog(`Process ${pid2} is not running`, err);
|
|
13736
13903
|
return false;
|
|
13737
13904
|
}
|
|
13738
13905
|
}
|
|
13739
13906
|
async function isLockValid(lockData) {
|
|
13740
|
-
if (DEBUG)
|
|
13907
|
+
if (DEBUG) debugLog("Checking if lockfile is valid", lockData);
|
|
13741
13908
|
const MAX_LOCK_AGE = 30 * 60 * 1e3;
|
|
13742
13909
|
if (Date.now() - lockData.timestamp > MAX_LOCK_AGE) {
|
|
13743
13910
|
log("Lockfile is too old");
|
|
13744
13911
|
if (DEBUG)
|
|
13745
|
-
|
|
13912
|
+
debugLog("Lockfile is too old", {
|
|
13746
13913
|
age: Date.now() - lockData.timestamp,
|
|
13747
13914
|
maxAge: MAX_LOCK_AGE
|
|
13748
13915
|
});
|
|
@@ -13750,11 +13917,11 @@ async function isLockValid(lockData) {
|
|
|
13750
13917
|
}
|
|
13751
13918
|
if (!await isPidRunning(lockData.pid)) {
|
|
13752
13919
|
log("Process from lockfile is not running");
|
|
13753
|
-
if (DEBUG)
|
|
13920
|
+
if (DEBUG) debugLog("Process from lockfile is not running", { pid: lockData.pid });
|
|
13754
13921
|
return false;
|
|
13755
13922
|
}
|
|
13756
13923
|
try {
|
|
13757
|
-
if (DEBUG)
|
|
13924
|
+
if (DEBUG) debugLog("Checking if endpoint is accessible", { port: lockData.port });
|
|
13758
13925
|
const controller = new AbortController();
|
|
13759
13926
|
const timeout = setTimeout(() => controller.abort(), 1e3);
|
|
13760
13927
|
const response = await fetch(`http://127.0.0.1:${lockData.port}/wait-for-auth?poll=false`, {
|
|
@@ -13762,49 +13929,45 @@ async function isLockValid(lockData) {
|
|
|
13762
13929
|
});
|
|
13763
13930
|
clearTimeout(timeout);
|
|
13764
13931
|
const isValid2 = response.status === 200 || response.status === 202;
|
|
13765
|
-
if (DEBUG)
|
|
13766
|
-
await debugLog(global.currentServerUrlHash, `Endpoint check result: ${isValid2 ? "valid" : "invalid"}`, { status: response.status });
|
|
13932
|
+
if (DEBUG) debugLog(`Endpoint check result: ${isValid2 ? "valid" : "invalid"}`, { status: response.status });
|
|
13767
13933
|
return isValid2;
|
|
13768
13934
|
} catch (error) {
|
|
13769
13935
|
log(`Error connecting to auth server: ${error.message}`);
|
|
13770
|
-
if (DEBUG)
|
|
13936
|
+
if (DEBUG) debugLog("Error connecting to auth server", error);
|
|
13771
13937
|
return false;
|
|
13772
13938
|
}
|
|
13773
13939
|
}
|
|
13774
13940
|
async function waitForAuthentication(port) {
|
|
13775
13941
|
log(`Waiting for authentication from the server on port ${port}...`);
|
|
13776
|
-
if (DEBUG) await debugLog(global.currentServerUrlHash, `Waiting for authentication from server on port ${port}`);
|
|
13777
13942
|
try {
|
|
13778
13943
|
let attempts = 0;
|
|
13779
13944
|
while (true) {
|
|
13780
13945
|
attempts++;
|
|
13781
13946
|
const url = `http://127.0.0.1:${port}/wait-for-auth`;
|
|
13782
13947
|
log(`Querying: ${url}`);
|
|
13783
|
-
if (DEBUG)
|
|
13948
|
+
if (DEBUG) debugLog(`Poll attempt ${attempts}`);
|
|
13784
13949
|
try {
|
|
13785
13950
|
const response = await fetch(url);
|
|
13786
|
-
if (DEBUG)
|
|
13951
|
+
if (DEBUG) debugLog(`Poll response status: ${response.status}`);
|
|
13787
13952
|
if (response.status === 200) {
|
|
13788
13953
|
log(`Authentication completed by other instance`);
|
|
13789
|
-
if (DEBUG) await debugLog(global.currentServerUrlHash, `Authentication completed by other instance`);
|
|
13790
13954
|
return true;
|
|
13791
13955
|
} else if (response.status === 202) {
|
|
13792
13956
|
log(`Authentication still in progress`);
|
|
13793
|
-
if (DEBUG)
|
|
13957
|
+
if (DEBUG) debugLog(`Will retry in 1s`);
|
|
13794
13958
|
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
13795
13959
|
} else {
|
|
13796
13960
|
log(`Unexpected response status: ${response.status}`);
|
|
13797
|
-
if (DEBUG) await debugLog(global.currentServerUrlHash, `Unexpected response status`, { status: response.status });
|
|
13798
13961
|
return false;
|
|
13799
13962
|
}
|
|
13800
13963
|
} catch (fetchError) {
|
|
13801
|
-
if (DEBUG)
|
|
13964
|
+
if (DEBUG) debugLog(`Fetch error during poll`, fetchError);
|
|
13802
13965
|
await new Promise((resolve) => setTimeout(resolve, 2e3));
|
|
13803
13966
|
}
|
|
13804
13967
|
}
|
|
13805
13968
|
} catch (error) {
|
|
13806
13969
|
log(`Error waiting for authentication: ${error.message}`);
|
|
13807
|
-
if (DEBUG)
|
|
13970
|
+
if (DEBUG) debugLog(`Error waiting for authentication`, error);
|
|
13808
13971
|
return false;
|
|
13809
13972
|
}
|
|
13810
13973
|
}
|
|
@@ -13813,43 +13976,39 @@ function createLazyAuthCoordinator(serverUrlHash, callbackPort, events) {
|
|
|
13813
13976
|
return {
|
|
13814
13977
|
initializeAuth: async () => {
|
|
13815
13978
|
if (authState) {
|
|
13816
|
-
if (DEBUG)
|
|
13979
|
+
if (DEBUG) debugLog("Auth already initialized, reusing existing state");
|
|
13817
13980
|
return authState;
|
|
13818
13981
|
}
|
|
13819
13982
|
log("Initializing auth coordination on-demand");
|
|
13820
|
-
if (DEBUG)
|
|
13983
|
+
if (DEBUG) debugLog("Initializing auth coordination on-demand", { serverUrlHash, callbackPort });
|
|
13821
13984
|
authState = await coordinateAuth(serverUrlHash, callbackPort, events);
|
|
13822
|
-
if (DEBUG)
|
|
13985
|
+
if (DEBUG) debugLog("Auth coordination completed", { skipBrowserAuth: authState.skipBrowserAuth });
|
|
13823
13986
|
return authState;
|
|
13824
13987
|
}
|
|
13825
13988
|
};
|
|
13826
13989
|
}
|
|
13827
13990
|
async function coordinateAuth(serverUrlHash, callbackPort, events) {
|
|
13828
|
-
if (DEBUG)
|
|
13991
|
+
if (DEBUG) debugLog("Coordinating authentication", { serverUrlHash, callbackPort });
|
|
13829
13992
|
const lockData = process.platform === "win32" ? null : await checkLockfile(serverUrlHash);
|
|
13830
13993
|
if (DEBUG) {
|
|
13831
13994
|
if (process.platform === "win32") {
|
|
13832
|
-
|
|
13995
|
+
debugLog("Skipping lockfile check on Windows");
|
|
13833
13996
|
} else {
|
|
13834
|
-
|
|
13997
|
+
debugLog("Lockfile check result", { found: !!lockData, lockData });
|
|
13835
13998
|
}
|
|
13836
13999
|
}
|
|
13837
14000
|
if (lockData && await isLockValid(lockData)) {
|
|
13838
|
-
log(`Another instance is handling authentication on port ${lockData.port}`);
|
|
13839
|
-
if (DEBUG) await debugLog(serverUrlHash, "Another instance is handling authentication", { port: lockData.port, pid: lockData.pid });
|
|
14001
|
+
log(`Another instance is handling authentication on port ${lockData.port} (pid: ${lockData.pid})`);
|
|
13840
14002
|
try {
|
|
13841
|
-
if (DEBUG)
|
|
14003
|
+
if (DEBUG) debugLog("Waiting for authentication from other instance");
|
|
13842
14004
|
const authCompleted = await waitForAuthentication(lockData.port);
|
|
13843
14005
|
if (authCompleted) {
|
|
13844
|
-
log("Authentication completed by another instance");
|
|
13845
|
-
if (DEBUG) await debugLog(serverUrlHash, "Authentication completed by another instance, will use tokens from disk");
|
|
14006
|
+
log("Authentication completed by another instance. Using tokens from disk");
|
|
13846
14007
|
const dummyServer = express2().listen(0);
|
|
13847
14008
|
const dummyPort = dummyServer.address().port;
|
|
13848
|
-
if (DEBUG)
|
|
14009
|
+
if (DEBUG) debugLog("Started dummy server", { port: dummyPort });
|
|
13849
14010
|
const dummyWaitForAuthCode = () => {
|
|
13850
14011
|
log("WARNING: waitForAuthCode called in secondary instance - this is unexpected");
|
|
13851
|
-
if (DEBUG) debugLog(serverUrlHash, "WARNING: waitForAuthCode called in secondary instance - this is unexpected").catch(() => {
|
|
13852
|
-
});
|
|
13853
14012
|
return new Promise(() => {
|
|
13854
14013
|
});
|
|
13855
14014
|
};
|
|
@@ -13860,20 +14019,18 @@ async function coordinateAuth(serverUrlHash, callbackPort, events) {
|
|
|
13860
14019
|
};
|
|
13861
14020
|
} else {
|
|
13862
14021
|
log("Taking over authentication process...");
|
|
13863
|
-
if (DEBUG) await debugLog(serverUrlHash, "Taking over authentication process");
|
|
13864
14022
|
}
|
|
13865
14023
|
} catch (error) {
|
|
13866
14024
|
log(`Error waiting for authentication: ${error}`);
|
|
13867
|
-
if (DEBUG)
|
|
14025
|
+
if (DEBUG) debugLog("Error waiting for authentication", error);
|
|
13868
14026
|
}
|
|
13869
|
-
if (DEBUG)
|
|
14027
|
+
if (DEBUG) debugLog("Other instance did not complete auth successfully, deleting lockfile");
|
|
13870
14028
|
await deleteLockfile(serverUrlHash);
|
|
13871
14029
|
} else if (lockData) {
|
|
13872
14030
|
log("Found invalid lockfile, deleting it");
|
|
13873
|
-
if (DEBUG) await debugLog(serverUrlHash, "Found invalid lockfile, deleting it");
|
|
13874
14031
|
await deleteLockfile(serverUrlHash);
|
|
13875
14032
|
}
|
|
13876
|
-
if (DEBUG)
|
|
14033
|
+
if (DEBUG) debugLog("Setting up OAuth callback server", { port: callbackPort });
|
|
13877
14034
|
const { server, waitForAuthCode, authCompletedPromise } = setupOAuthCallbackServerWithLongPoll({
|
|
13878
14035
|
port: callbackPort,
|
|
13879
14036
|
path: "/oauth/callback",
|
|
@@ -13881,18 +14038,16 @@ async function coordinateAuth(serverUrlHash, callbackPort, events) {
|
|
|
13881
14038
|
});
|
|
13882
14039
|
const address = server.address();
|
|
13883
14040
|
const actualPort = address.port;
|
|
13884
|
-
if (DEBUG)
|
|
14041
|
+
if (DEBUG) debugLog("OAuth callback server running", { port: actualPort });
|
|
13885
14042
|
log(`Creating lockfile for server ${serverUrlHash} with process ${process.pid} on port ${actualPort}`);
|
|
13886
|
-
if (DEBUG) await debugLog(serverUrlHash, "Creating lockfile", { serverUrlHash, pid: process.pid, port: actualPort });
|
|
13887
14043
|
await createLockfile(serverUrlHash, process.pid, actualPort);
|
|
13888
14044
|
const cleanupHandler = async () => {
|
|
13889
14045
|
try {
|
|
13890
14046
|
log(`Cleaning up lockfile for server ${serverUrlHash}`);
|
|
13891
|
-
if (DEBUG) await debugLog(serverUrlHash, "Cleaning up lockfile");
|
|
13892
14047
|
await deleteLockfile(serverUrlHash);
|
|
13893
14048
|
} catch (error) {
|
|
13894
14049
|
log(`Error cleaning up lockfile: ${error}`);
|
|
13895
|
-
if (DEBUG)
|
|
14050
|
+
if (DEBUG) debugLog("Error cleaning up lockfile", error);
|
|
13896
14051
|
}
|
|
13897
14052
|
};
|
|
13898
14053
|
process.once("exit", () => {
|
|
@@ -13905,10 +14060,10 @@ async function coordinateAuth(serverUrlHash, callbackPort, events) {
|
|
|
13905
14060
|
}
|
|
13906
14061
|
});
|
|
13907
14062
|
process.once("SIGINT", async () => {
|
|
13908
|
-
if (DEBUG)
|
|
14063
|
+
if (DEBUG) debugLog("Received SIGINT signal, cleaning up");
|
|
13909
14064
|
await cleanupHandler();
|
|
13910
14065
|
});
|
|
13911
|
-
if (DEBUG)
|
|
14066
|
+
if (DEBUG) debugLog("Auth coordination complete, returning primary instance handlers");
|
|
13912
14067
|
return {
|
|
13913
14068
|
server,
|
|
13914
14069
|
waitForAuthCode,
|
package/dist/client.js
CHANGED
package/dist/proxy.js
CHANGED
|
@@ -9,15 +9,15 @@ import {
|
|
|
9
9
|
mcpProxy,
|
|
10
10
|
parseCommandLineArgs,
|
|
11
11
|
setupSignalHandlers
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-QW4IRS52.js";
|
|
13
13
|
|
|
14
14
|
// src/proxy.ts
|
|
15
15
|
import { EventEmitter } from "events";
|
|
16
16
|
|
|
17
|
-
// node_modules/.pnpm/@modelcontextprotocol+sdk@
|
|
17
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@https+++pkg.pr.new+geelen+typescript-sdk+@modelcontextprotocol+sdk@cdf3508/node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
|
|
18
18
|
import process2 from "node:process";
|
|
19
19
|
|
|
20
|
-
// node_modules/.pnpm/@modelcontextprotocol+sdk@
|
|
20
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@https+++pkg.pr.new+geelen+typescript-sdk+@modelcontextprotocol+sdk@cdf3508/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/stdio.js
|
|
21
21
|
var ReadBuffer = class {
|
|
22
22
|
append(chunk) {
|
|
23
23
|
this._buffer = this._buffer ? Buffer.concat([this._buffer, chunk]) : chunk;
|
|
@@ -45,7 +45,7 @@ function serializeMessage(message) {
|
|
|
45
45
|
return JSON.stringify(message) + "\n";
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
// node_modules/.pnpm/@modelcontextprotocol+sdk@
|
|
48
|
+
// node_modules/.pnpm/@modelcontextprotocol+sdk@https+++pkg.pr.new+geelen+typescript-sdk+@modelcontextprotocol+sdk@cdf3508/node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
|
|
49
49
|
var StdioServerTransport = class {
|
|
50
50
|
constructor(_stdin = process2.stdin, _stdout = process2.stdout) {
|
|
51
51
|
this._stdin = _stdin;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcp-remote",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.15",
|
|
4
4
|
"description": "Remote proxy for Model Context Protocol, allowing local-only clients to connect to remote servers using oAuth",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mcp",
|
|
@@ -22,18 +22,27 @@
|
|
|
22
22
|
"mcp-remote": "dist/proxy.js",
|
|
23
23
|
"mcp-remote-client": "dist/client.js"
|
|
24
24
|
},
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "tsup",
|
|
27
|
+
"build:watch": "tsup --watch",
|
|
28
|
+
"check": "prettier --check . && tsc",
|
|
29
|
+
"lint-fix": "prettier --check . --write",
|
|
30
|
+
"test:unit": "vitest run",
|
|
31
|
+
"test:unit:watch": "vitest"
|
|
32
|
+
},
|
|
25
33
|
"dependencies": {
|
|
26
34
|
"express": "^4.21.2",
|
|
27
35
|
"open": "^10.1.0"
|
|
28
36
|
},
|
|
29
37
|
"devDependencies": {
|
|
30
|
-
"@modelcontextprotocol/sdk": "
|
|
38
|
+
"@modelcontextprotocol/sdk": "https://pkg.pr.new/geelen/typescript-sdk/@modelcontextprotocol/sdk@cdf3508",
|
|
31
39
|
"@types/express": "^5.0.0",
|
|
32
40
|
"@types/node": "^22.13.10",
|
|
33
41
|
"prettier": "^3.5.3",
|
|
34
42
|
"tsup": "^8.4.0",
|
|
35
43
|
"tsx": "^4.19.3",
|
|
36
|
-
"typescript": "^5.8.2"
|
|
44
|
+
"typescript": "^5.8.2",
|
|
45
|
+
"vitest": "^3.2.3"
|
|
37
46
|
},
|
|
38
47
|
"tsup": {
|
|
39
48
|
"entry": [
|
|
@@ -48,10 +57,12 @@
|
|
|
48
57
|
"outDir": "dist",
|
|
49
58
|
"external": []
|
|
50
59
|
},
|
|
51
|
-
"
|
|
52
|
-
"
|
|
53
|
-
"
|
|
54
|
-
"
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
}
|
|
60
|
+
"vitest": {
|
|
61
|
+
"environment": "node",
|
|
62
|
+
"globals": true,
|
|
63
|
+
"include": [
|
|
64
|
+
"src/**/*.test.ts"
|
|
65
|
+
]
|
|
66
|
+
},
|
|
67
|
+
"packageManager": "pnpm@10.11.0+sha512.6540583f41cc5f628eb3d9773ecee802f4f9ef9923cc45b69890fb47991d4b092964694ec3a4f738a420c918a333062c8b925d312f42e4f0c263eb603551f977"
|
|
68
|
+
}
|