From 28b2e652146cdb2ffe4353bf17b67d8f74023177 Mon Sep 17 00:00:00 2001 From: Emilis Baliukonis Date: Fri, 25 Apr 2025 16:46:53 +0300 Subject: [PATCH 1/3] Skip auth if there's a valid lockfile and saved tokens --- src/client.ts | 8 +++++--- src/lib/coordination.ts | 4 +++- src/proxy.ts | 7 ++++--- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/client.ts b/src/client.ts index d620884..27c41ef 100644 --- a/src/client.ts +++ b/src/client.ts @@ -28,9 +28,6 @@ async function runClient(serverUrl: string, callbackPort: number, headers: Recor // Get the server URL hash for lockfile operations const serverUrlHash = getServerUrlHash(serverUrl) - // Coordinate authentication with other instances - const { server, waitForAuthCode, skipBrowserAuth } = await coordinateAuth(serverUrlHash, callbackPort, events) - // Create the OAuth client provider const authProvider = new NodeOAuthClientProvider({ serverUrl, @@ -38,6 +35,10 @@ async function runClient(serverUrl: string, callbackPort: number, headers: Recor clientName: 'MCP CLI Client', }) + // Coordinate authentication with other instances + const hasSavedTokens = !!(await authProvider.tokens()) + const { server, waitForAuthCode, skipBrowserAuth } = await coordinateAuth(serverUrlHash, callbackPort, events, hasSavedTokens) + // If auth was completed by another instance, just log that we'll use the auth from disk if (skipBrowserAuth) { log('Authentication was completed by another instance - will use tokens from disk...') @@ -99,6 +100,7 @@ async function runClient(serverUrl: string, callbackPort: number, headers: Recor // Wait for the authorization code from the callback or another instance const code = await waitForAuthCode() + console.log('~~~ CLIENT - AUTH CODE ~~~', code) try { log('Completing authorization...') diff --git a/src/lib/coordination.ts b/src/lib/coordination.ts index ad1d2f6..a38ad35 100644 --- a/src/lib/coordination.ts +++ b/src/lib/coordination.ts @@ -93,12 +93,14 @@ export async function waitForAuthentication(port: number): Promise { * @param serverUrlHash The hash of the server URL * @param callbackPort The port to use for the callback server * @param events The event emitter to use for signaling + * @param hasSavedTokens Whether the client has saved tokens * @returns An object with the server, waitForAuthCode function, and a flag indicating if browser auth can be skipped */ export async function coordinateAuth( serverUrlHash: string, callbackPort: number, events: EventEmitter, + hasSavedTokens: boolean, ): Promise<{ server: Server; waitForAuthCode: () => Promise; skipBrowserAuth: boolean }> { // Check for a lockfile (disabled on Windows for the time being) const lockData = process.platform === 'win32' ? null : await checkLockfile(serverUrlHash) @@ -109,7 +111,7 @@ export async function coordinateAuth( try { // Try to wait for the authentication to complete - const authCompleted = await waitForAuthentication(lockData.port) + const authCompleted = hasSavedTokens || (await waitForAuthentication(lockData.port)) if (authCompleted) { log('Authentication completed by another instance') diff --git a/src/proxy.ts b/src/proxy.ts index 9fd87d1..227b91a 100644 --- a/src/proxy.ts +++ b/src/proxy.ts @@ -25,9 +25,6 @@ async function runProxy(serverUrl: string, callbackPort: number, headers: Record // Get the server URL hash for lockfile operations const serverUrlHash = getServerUrlHash(serverUrl) - // Coordinate authentication with other instances - const { server, waitForAuthCode, skipBrowserAuth } = await coordinateAuth(serverUrlHash, callbackPort, events) - // Create the OAuth client provider const authProvider = new NodeOAuthClientProvider({ serverUrl, @@ -35,6 +32,10 @@ async function runProxy(serverUrl: string, callbackPort: number, headers: Record clientName: 'MCP CLI Proxy', }) + // Coordinate authentication with other instances + const hasSavedTokens = !!(await authProvider.tokens()) + const { server, waitForAuthCode, skipBrowserAuth } = await coordinateAuth(serverUrlHash, callbackPort, events, hasSavedTokens) + // If auth was completed by another instance, just log that we'll use the auth from disk if (skipBrowserAuth) { log('Authentication was completed by another instance - will use tokens from disk') From 5a7fd6fe4d5937839c173172edd17ec5715c4d4c Mon Sep 17 00:00:00 2001 From: Emilis Baliukonis Date: Fri, 25 Apr 2025 16:47:54 +0300 Subject: [PATCH 2/3] Remove lockfile timestamp check because it causes issues with multiple processes --- src/lib/coordination.ts | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/lib/coordination.ts b/src/lib/coordination.ts index a38ad35..da6355e 100644 --- a/src/lib/coordination.ts +++ b/src/lib/coordination.ts @@ -25,13 +25,6 @@ export async function isPidRunning(pid: number): Promise { * @returns True if the lockfile is valid, false otherwise */ export async function isLockValid(lockData: LockfileData): Promise { - // Check if the lockfile is too old (over 30 minutes) - const MAX_LOCK_AGE = 30 * 60 * 1000 // 30 minutes - if (Date.now() - lockData.timestamp > MAX_LOCK_AGE) { - log('Lockfile is too old') - return false - } - // Check if the process is still running if (!(await isPidRunning(lockData.pid))) { log('Process from lockfile is not running') From 564983fea598be6fcde128934feaf7cac00a1303 Mon Sep 17 00:00:00 2001 From: Emilis Baliukonis Date: Fri, 25 Apr 2025 16:49:13 +0300 Subject: [PATCH 3/3] Remove debug log --- src/client.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/client.ts b/src/client.ts index 27c41ef..b87a156 100644 --- a/src/client.ts +++ b/src/client.ts @@ -100,7 +100,6 @@ async function runClient(serverUrl: string, callbackPort: number, headers: Recor // Wait for the authorization code from the callback or another instance const code = await waitForAuthCode() - console.log('~~~ CLIENT - AUTH CODE ~~~', code) try { log('Completing authorization...')