diff --git a/src/client.ts b/src/client.ts index 80b2dd4..7cf4db0 100644 --- a/src/client.ts +++ b/src/client.ts @@ -42,9 +42,9 @@ async function runClient(serverUrl: string, callbackPort: number, clean: boolean clean, }) - // If we got auth from another instance, pre-populate with the received code + // If auth was completed by another instance, just log that we'll use the auth from disk if (skipBrowserAuth) { - log('Using auth code from another instance') + log('Authentication was completed by another instance - will use tokens from disk') } // Create the client diff --git a/src/lib/coordination.ts b/src/lib/coordination.ts index a0568d7..c173e7a 100644 --- a/src/lib/coordination.ts +++ b/src/lib/coordination.ts @@ -58,9 +58,9 @@ export async function isLockValid(lockData: LockfileData): Promise { /** * Waits for authentication from another server instance * @param port The port to connect to - * @returns The auth code if successful, false otherwise + * @returns True if authentication completed successfully, false otherwise */ -export async function waitForAuthentication(port: number): Promise { +export async function waitForAuthentication(port: number): Promise { log(`Waiting for authentication from the server on port ${port}...`) try { @@ -70,11 +70,13 @@ export async function waitForAuthentication(port: number): Promise setTimeout(resolve, 1000)) } else { log(`Unexpected response status: ${response.status}`) return false @@ -97,7 +99,7 @@ export async function coordinateAuth( serverUrlHash: string, callbackPort: number, events: EventEmitter, -): Promise<{ server: Server; waitForAuthCode: () => Promise; skipBrowserAuth: boolean; authCode?: string }> { +): Promise<{ server: Server; waitForAuthCode: () => Promise; skipBrowserAuth: boolean }> { // Check for a lockfile const lockData = await checkLockfile(serverUrlHash) @@ -107,19 +109,24 @@ export async function coordinateAuth( try { // Try to wait for the authentication to complete - const code = await waitForAuthentication(lockData.port) - if (code) { + const authCompleted = await waitForAuthentication(lockData.port) + if (authCompleted) { log('Authentication completed by another instance') - // Setup a dummy server and return a pre-resolved promise for the auth code + // Setup a dummy server - the client will use tokens directly from disk const dummyServer = express().listen(0) // Listen on any available port - const dummyWaitForAuthCode = () => Promise.resolve(code) + + // This shouldn't actually be called in normal operation, but provide it for API compatibility + const dummyWaitForAuthCode = () => { + log('WARNING: waitForAuthCode called in secondary instance - this is unexpected') + // Return a promise that never resolves - the client should use the tokens from disk instead + return new Promise(() => {}) + } return { server: dummyServer, waitForAuthCode: dummyWaitForAuthCode, skipBrowserAuth: true, - authCode: code, } } else { log('Taking over authentication process...') @@ -176,6 +183,6 @@ export async function coordinateAuth( return { server, waitForAuthCode, - skipBrowserAuth: false, + skipBrowserAuth: false } } diff --git a/src/lib/utils.ts b/src/lib/utils.ts index fa0360e..a37fe61 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -135,9 +135,10 @@ export function setupOAuthCallbackServerWithLongPoll(options: OAuthCallbackServe // Long-polling endpoint app.get('/wait-for-auth', (req, res) => { if (authCode) { - // Auth already completed - log('Auth already completed, returning immediately') - res.status(200).send(authCode) + // Auth already completed - just return 200 without the actual code + // Secondary instances will read tokens from disk + log('Auth already completed, returning 200') + res.status(200).send('Authentication completed') return } @@ -155,11 +156,11 @@ export function setupOAuthCallbackServerWithLongPoll(options: OAuthCallbackServe // If auth completes while we're waiting, send the response immediately authCompletedPromise - .then((code) => { + .then(() => { clearTimeout(longPollTimeout) if (!res.headersSent) { log('Auth completed during long poll, responding with 200') - res.status(200).send(code) + res.status(200).send('Authentication completed') } }) .catch(() => { diff --git a/src/proxy.ts b/src/proxy.ts index d578abd..cbaaf5d 100644 --- a/src/proxy.ts +++ b/src/proxy.ts @@ -38,6 +38,11 @@ async function runProxy(serverUrl: string, callbackPort: number, clean: boolean clientName: 'MCP CLI Proxy', clean, }) + + // 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') + } // Create the STDIO transport for local connections const localTransport = new StdioServerTransport()