align-mcp-remote 0.1.38 → 0.1.40
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-MMS4PSEI.js → chunk-X7AWYUMO.js} +114 -18
- package/dist/client.js +21 -3
- package/dist/proxy.js +21 -3
- package/package.json +1 -1
|
@@ -15632,7 +15632,7 @@ var Client = class extends Protocol {
|
|
|
15632
15632
|
};
|
|
15633
15633
|
|
|
15634
15634
|
// package.json
|
|
15635
|
-
var version2 = "0.1.
|
|
15635
|
+
var version2 = "0.1.39";
|
|
15636
15636
|
|
|
15637
15637
|
// node_modules/pkce-challenge/dist/index.node.js
|
|
15638
15638
|
var crypto;
|
|
@@ -16410,6 +16410,17 @@ async function executeTokenRequest(authorizationServerUrl, { metadata, tokenRequ
|
|
|
16410
16410
|
}
|
|
16411
16411
|
return OAuthTokensSchema.parse(await response.json());
|
|
16412
16412
|
}
|
|
16413
|
+
async function exchangeAuthorization(authorizationServerUrl, { metadata, clientInformation, authorizationCode, codeVerifier, redirectUri, resource, addClientAuthentication, fetchFn }) {
|
|
16414
|
+
const tokenRequestParams = prepareAuthorizationCodeRequest(authorizationCode, codeVerifier, redirectUri);
|
|
16415
|
+
return executeTokenRequest(authorizationServerUrl, {
|
|
16416
|
+
metadata,
|
|
16417
|
+
tokenRequestParams,
|
|
16418
|
+
clientInformation,
|
|
16419
|
+
addClientAuthentication,
|
|
16420
|
+
resource,
|
|
16421
|
+
fetchFn
|
|
16422
|
+
});
|
|
16423
|
+
}
|
|
16413
16424
|
async function refreshAuthorization(authorizationServerUrl, { metadata, clientInformation, refreshToken, resource, addClientAuthentication, fetchFn }) {
|
|
16414
16425
|
const tokenRequestParams = new URLSearchParams({
|
|
16415
16426
|
grant_type: "refresh_token",
|
|
@@ -18072,41 +18083,109 @@ async function discoverOAuthServerInfo2(serverUrl, headers = {}) {
|
|
|
18072
18083
|
debugLog("No Protected Resource Metadata found, falling back to server URL as authorization server");
|
|
18073
18084
|
}
|
|
18074
18085
|
const authorizationServerMetadata = await fetchAuthorizationServerMetadata(authorizationServerUrl);
|
|
18086
|
+
const downstreamTokenHeader = protectedResourceMetadata?.x_downstream_resource?.token_header ?? "X-Downstream-Authorization";
|
|
18075
18087
|
return {
|
|
18076
18088
|
authorizationServerUrl,
|
|
18077
18089
|
authorizationServerMetadata,
|
|
18078
18090
|
protectedResourceMetadata,
|
|
18079
|
-
wwwAuthenticateScope
|
|
18091
|
+
wwwAuthenticateScope,
|
|
18092
|
+
downstreamTokenHeader: protectedResourceMetadata?.x_downstream_resource ? downstreamTokenHeader : void 0
|
|
18080
18093
|
};
|
|
18081
18094
|
}
|
|
18082
|
-
async function
|
|
18095
|
+
async function performDownstreamAuth(authProvider, downstreamResource, callbackPort) {
|
|
18096
|
+
debugLog("Starting downstream OAuth flow", { downstreamResource });
|
|
18097
|
+
const downstreamAs = downstreamResource.authorization_servers[0];
|
|
18098
|
+
if (!downstreamAs) {
|
|
18099
|
+
throw new Error("x_downstream_resource.authorization_servers is empty");
|
|
18100
|
+
}
|
|
18101
|
+
const downstreamServerMetadata = await fetchAuthorizationServerMetadata(downstreamAs);
|
|
18102
|
+
if (!downstreamServerMetadata) {
|
|
18103
|
+
throw new Error(`Failed to fetch downstream authorization server metadata from ${downstreamAs}`);
|
|
18104
|
+
}
|
|
18105
|
+
const downstreamCallbackPort = await findAvailablePort(callbackPort + 1);
|
|
18106
|
+
const downstreamEvents = new (await import("events")).EventEmitter();
|
|
18107
|
+
const { server: downstreamServer, waitForAuthCode: waitForDownstreamCode } = setupOAuthCallbackServerWithLongPoll({
|
|
18108
|
+
port: downstreamCallbackPort,
|
|
18109
|
+
path: "/oauth/callback",
|
|
18110
|
+
events: downstreamEvents,
|
|
18111
|
+
authTimeoutMs: 3e5
|
|
18112
|
+
});
|
|
18113
|
+
const host = authProvider.options.host || "localhost";
|
|
18114
|
+
const redirectUrl = `http://${host}:${downstreamCallbackPort}/oauth/callback`;
|
|
18115
|
+
const scope = downstreamResource.scopes_required?.join(" ") ?? "";
|
|
18116
|
+
const { authorizationUrl, codeVerifier } = await startAuthorization(downstreamAs, {
|
|
18117
|
+
metadata: downstreamServerMetadata,
|
|
18118
|
+
clientInformation: await authProvider.clientInformation(),
|
|
18119
|
+
redirectUrl,
|
|
18120
|
+
scope,
|
|
18121
|
+
resource: new URL(downstreamResource.resource)
|
|
18122
|
+
});
|
|
18123
|
+
log(`
|
|
18124
|
+
Please authorize the downstream resource by visiting:
|
|
18125
|
+
${authorizationUrl.toString()}
|
|
18126
|
+
`);
|
|
18127
|
+
try {
|
|
18128
|
+
const { default: open2 } = await import("open");
|
|
18129
|
+
await open2(authorizationUrl.toString());
|
|
18130
|
+
log("Browser opened automatically for downstream authorization.");
|
|
18131
|
+
} catch {
|
|
18132
|
+
log("Could not open browser automatically. Please copy and paste the URL above.");
|
|
18133
|
+
}
|
|
18134
|
+
try {
|
|
18135
|
+
const code = await waitForDownstreamCode();
|
|
18136
|
+
const tokens = await exchangeAuthorization(downstreamAs, {
|
|
18137
|
+
metadata: downstreamServerMetadata,
|
|
18138
|
+
clientInformation: await authProvider.clientInformation(),
|
|
18139
|
+
authorizationCode: code,
|
|
18140
|
+
codeVerifier,
|
|
18141
|
+
redirectUri: redirectUrl
|
|
18142
|
+
});
|
|
18143
|
+
await authProvider.saveDownstreamTokens(tokens);
|
|
18144
|
+
debugLog("Downstream OAuth flow completed, tokens saved");
|
|
18145
|
+
} finally {
|
|
18146
|
+
downstreamServer.close();
|
|
18147
|
+
}
|
|
18148
|
+
}
|
|
18149
|
+
async function connectToRemoteServer(client, serverUrl, authProvider, headers, authInitializer, transportStrategy = "http-first", downstreamTokenHeader, recursionReasons = /* @__PURE__ */ new Set()) {
|
|
18083
18150
|
log(`[${pid}] Connecting to remote server: ${serverUrl}`);
|
|
18084
18151
|
const url2 = new URL(serverUrl);
|
|
18152
|
+
const resolveDownstreamHeader = async () => {
|
|
18153
|
+
if (!downstreamTokenHeader) return {};
|
|
18154
|
+
const provider = authProvider;
|
|
18155
|
+
if (typeof provider.downstreamTokens !== "function") return {};
|
|
18156
|
+
const downstreamTokens = await provider.downstreamTokens();
|
|
18157
|
+
if (downstreamTokens?.access_token) {
|
|
18158
|
+
return { [downstreamTokenHeader]: `Bearer ${downstreamTokens.access_token}` };
|
|
18159
|
+
}
|
|
18160
|
+
return {};
|
|
18161
|
+
};
|
|
18085
18162
|
const eventSourceInit = {
|
|
18086
|
-
fetch: (url3, init) => {
|
|
18087
|
-
|
|
18088
|
-
|
|
18089
|
-
|
|
18090
|
-
|
|
18091
|
-
|
|
18092
|
-
|
|
18093
|
-
|
|
18094
|
-
|
|
18095
|
-
|
|
18096
|
-
}
|
|
18097
|
-
);
|
|
18163
|
+
fetch: async (url3, init) => {
|
|
18164
|
+
const [tokens, downstreamHeader2] = await Promise.all([authProvider?.tokens?.(), resolveDownstreamHeader()]);
|
|
18165
|
+
return fetch2(url3, {
|
|
18166
|
+
...init,
|
|
18167
|
+
headers: {
|
|
18168
|
+
...init?.headers instanceof Headers2 ? Object.fromEntries(init?.headers.entries()) : init?.headers || {},
|
|
18169
|
+
...headers,
|
|
18170
|
+
...tokens?.access_token ? { Authorization: `Bearer ${tokens.access_token}` } : {},
|
|
18171
|
+
...downstreamHeader2,
|
|
18172
|
+
Accept: "text/event-stream"
|
|
18173
|
+
}
|
|
18174
|
+
});
|
|
18098
18175
|
}
|
|
18099
18176
|
};
|
|
18100
18177
|
log(`Using transport strategy: ${transportStrategy}`);
|
|
18101
18178
|
const shouldAttemptFallback2 = transportStrategy === "http-first" || transportStrategy === "sse-first";
|
|
18102
18179
|
const sseTransport = transportStrategy === "sse-only" || transportStrategy === "sse-first";
|
|
18180
|
+
const downstreamHeader = await resolveDownstreamHeader();
|
|
18181
|
+
const mergedHeaders = { ...headers, ...downstreamHeader };
|
|
18103
18182
|
const transport = sseTransport ? new SSEClientTransport(url2, {
|
|
18104
18183
|
authProvider,
|
|
18105
|
-
requestInit: { headers },
|
|
18184
|
+
requestInit: { headers: mergedHeaders },
|
|
18106
18185
|
eventSourceInit
|
|
18107
18186
|
}) : new StreamableHTTPClientTransport(url2, {
|
|
18108
18187
|
authProvider,
|
|
18109
|
-
requestInit: { headers }
|
|
18188
|
+
requestInit: { headers: mergedHeaders }
|
|
18110
18189
|
});
|
|
18111
18190
|
try {
|
|
18112
18191
|
debugLog("Attempting to connect to remote server", { sseTransport });
|
|
@@ -18145,6 +18224,7 @@ async function connectToRemoteServer(client, serverUrl, authProvider, headers, a
|
|
|
18145
18224
|
headers,
|
|
18146
18225
|
authInitializer,
|
|
18147
18226
|
sseTransport ? "http-only" : "sse-only",
|
|
18227
|
+
downstreamTokenHeader,
|
|
18148
18228
|
recursionReasons
|
|
18149
18229
|
);
|
|
18150
18230
|
} else if (error2 instanceof UnauthorizedError || error2 instanceof Error && error2.message.includes("Unauthorized")) {
|
|
@@ -18179,7 +18259,7 @@ async function connectToRemoteServer(client, serverUrl, authProvider, headers, a
|
|
|
18179
18259
|
recursionReasons.add(REASON_AUTH_NEEDED);
|
|
18180
18260
|
log(`Recursively reconnecting for reason: ${REASON_AUTH_NEEDED}`);
|
|
18181
18261
|
debugLog("Recursively reconnecting after auth", { recursionReasons: Array.from(recursionReasons) });
|
|
18182
|
-
return connectToRemoteServer(client, serverUrl, authProvider, headers, authInitializer, transportStrategy, recursionReasons);
|
|
18262
|
+
return connectToRemoteServer(client, serverUrl, authProvider, headers, authInitializer, transportStrategy, downstreamTokenHeader, recursionReasons);
|
|
18183
18263
|
} catch (authError) {
|
|
18184
18264
|
log("Authorization error:", authError);
|
|
18185
18265
|
debugLog("Authorization error during finishAuth", {
|
|
@@ -18759,6 +18839,20 @@ ${authorizationUrl.toString()}
|
|
|
18759
18839
|
debugLog("Code verifier found:", !!verifier);
|
|
18760
18840
|
return verifier;
|
|
18761
18841
|
}
|
|
18842
|
+
/**
|
|
18843
|
+
* Gets the downstream OAuth tokens (Layer 2) if they exist
|
|
18844
|
+
*/
|
|
18845
|
+
async downstreamTokens() {
|
|
18846
|
+
debugLog("Reading downstream OAuth tokens");
|
|
18847
|
+
return readJsonFile(this.serverUrlHash, "downstream_tokens.json", OAuthTokensSchema);
|
|
18848
|
+
}
|
|
18849
|
+
/**
|
|
18850
|
+
* Saves downstream OAuth tokens (Layer 2)
|
|
18851
|
+
*/
|
|
18852
|
+
async saveDownstreamTokens(tokens) {
|
|
18853
|
+
debugLog("Saving downstream tokens", { hasAccessToken: !!tokens.access_token });
|
|
18854
|
+
await writeJsonFile(this.serverUrlHash, "downstream_tokens.json", tokens);
|
|
18855
|
+
}
|
|
18762
18856
|
/**
|
|
18763
18857
|
* Invalidates the specified credentials
|
|
18764
18858
|
* @param scope The scope of credentials to invalidate
|
|
@@ -18770,6 +18864,7 @@ ${authorizationUrl.toString()}
|
|
|
18770
18864
|
await Promise.all([
|
|
18771
18865
|
deleteConfigFile(this.serverUrlHash, "client_info.json"),
|
|
18772
18866
|
deleteConfigFile(this.serverUrlHash, "tokens.json"),
|
|
18867
|
+
deleteConfigFile(this.serverUrlHash, "downstream_tokens.json"),
|
|
18773
18868
|
deleteConfigFile(this.serverUrlHash, "code_verifier.txt")
|
|
18774
18869
|
]);
|
|
18775
18870
|
this._clientInfo = void 0;
|
|
@@ -18990,6 +19085,7 @@ export {
|
|
|
18990
19085
|
log,
|
|
18991
19086
|
mcpProxy,
|
|
18992
19087
|
discoverOAuthServerInfo2 as discoverOAuthServerInfo,
|
|
19088
|
+
performDownstreamAuth,
|
|
18993
19089
|
connectToRemoteServer,
|
|
18994
19090
|
parseCommandLineArgs,
|
|
18995
19091
|
setupSignalHandlers,
|
package/dist/client.js
CHANGED
|
@@ -10,9 +10,10 @@ import {
|
|
|
10
10
|
discoverOAuthServerInfo,
|
|
11
11
|
log,
|
|
12
12
|
parseCommandLineArgs,
|
|
13
|
+
performDownstreamAuth,
|
|
13
14
|
setupSignalHandlers,
|
|
14
15
|
version
|
|
15
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-X7AWYUMO.js";
|
|
16
17
|
|
|
17
18
|
// src/client.ts
|
|
18
19
|
import { EventEmitter } from "events";
|
|
@@ -52,6 +53,7 @@ async function runClient(serverUrl, callbackPort, headers, transportStrategy = "
|
|
|
52
53
|
capabilities: {}
|
|
53
54
|
}
|
|
54
55
|
);
|
|
56
|
+
const downstreamResource = discoveryResult.protectedResourceMetadata?.x_downstream_resource;
|
|
55
57
|
let server = null;
|
|
56
58
|
const authInitializer = async () => {
|
|
57
59
|
const authState = await authCoordinator.initializeAuth();
|
|
@@ -61,12 +63,28 @@ async function runClient(serverUrl, callbackPort, headers, transportStrategy = "
|
|
|
61
63
|
await new Promise((res) => setTimeout(res, 1e3));
|
|
62
64
|
}
|
|
63
65
|
return {
|
|
64
|
-
waitForAuthCode:
|
|
66
|
+
waitForAuthCode: async () => {
|
|
67
|
+
const code = await authState.waitForAuthCode();
|
|
68
|
+
if (downstreamResource && !authState.skipBrowserAuth) {
|
|
69
|
+
log("Layer 1 auth complete. Starting downstream (Layer 2) OAuth flow...");
|
|
70
|
+
await performDownstreamAuth(authProvider, downstreamResource, callbackPort);
|
|
71
|
+
log("Layer 2 auth complete.");
|
|
72
|
+
}
|
|
73
|
+
return code;
|
|
74
|
+
},
|
|
65
75
|
skipBrowserAuth: authState.skipBrowserAuth
|
|
66
76
|
};
|
|
67
77
|
};
|
|
68
78
|
try {
|
|
69
|
-
const transport = await connectToRemoteServer(
|
|
79
|
+
const transport = await connectToRemoteServer(
|
|
80
|
+
client,
|
|
81
|
+
serverUrl,
|
|
82
|
+
authProvider,
|
|
83
|
+
headers,
|
|
84
|
+
authInitializer,
|
|
85
|
+
transportStrategy,
|
|
86
|
+
discoveryResult.downstreamTokenHeader
|
|
87
|
+
);
|
|
70
88
|
transport.onmessage = (message) => {
|
|
71
89
|
log("Received message:", JSON.stringify(message, null, 2));
|
|
72
90
|
};
|
package/dist/proxy.js
CHANGED
|
@@ -9,8 +9,9 @@ import {
|
|
|
9
9
|
log,
|
|
10
10
|
mcpProxy,
|
|
11
11
|
parseCommandLineArgs,
|
|
12
|
+
performDownstreamAuth,
|
|
12
13
|
setupSignalHandlers
|
|
13
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-X7AWYUMO.js";
|
|
14
15
|
|
|
15
16
|
// src/proxy.ts
|
|
16
17
|
import { EventEmitter } from "events";
|
|
@@ -138,6 +139,7 @@ async function runProxy(serverUrl, callbackPort, headers, transportStrategy = "h
|
|
|
138
139
|
});
|
|
139
140
|
const localTransport = new StdioServerTransport();
|
|
140
141
|
let server = null;
|
|
142
|
+
const downstreamResource = discoveryResult.protectedResourceMetadata?.x_downstream_resource;
|
|
141
143
|
const authInitializer = async () => {
|
|
142
144
|
const authState = await authCoordinator.initializeAuth();
|
|
143
145
|
server = authState.server;
|
|
@@ -146,12 +148,28 @@ async function runProxy(serverUrl, callbackPort, headers, transportStrategy = "h
|
|
|
146
148
|
await new Promise((res) => setTimeout(res, 1e3));
|
|
147
149
|
}
|
|
148
150
|
return {
|
|
149
|
-
waitForAuthCode:
|
|
151
|
+
waitForAuthCode: async () => {
|
|
152
|
+
const code = await authState.waitForAuthCode();
|
|
153
|
+
if (downstreamResource && !authState.skipBrowserAuth) {
|
|
154
|
+
log("Layer 1 auth complete. Starting downstream (Layer 2) OAuth flow...");
|
|
155
|
+
await performDownstreamAuth(authProvider, downstreamResource, callbackPort);
|
|
156
|
+
log("Layer 2 auth complete.");
|
|
157
|
+
}
|
|
158
|
+
return code;
|
|
159
|
+
},
|
|
150
160
|
skipBrowserAuth: authState.skipBrowserAuth
|
|
151
161
|
};
|
|
152
162
|
};
|
|
153
163
|
try {
|
|
154
|
-
const remoteTransport = await connectToRemoteServer(
|
|
164
|
+
const remoteTransport = await connectToRemoteServer(
|
|
165
|
+
null,
|
|
166
|
+
serverUrl,
|
|
167
|
+
authProvider,
|
|
168
|
+
headers,
|
|
169
|
+
authInitializer,
|
|
170
|
+
transportStrategy,
|
|
171
|
+
discoveryResult.downstreamTokenHeader
|
|
172
|
+
);
|
|
155
173
|
mcpProxy({
|
|
156
174
|
transportToClient: localTransport,
|
|
157
175
|
transportToServer: remoteTransport,
|