From 2cc0c1a8081c193645b4d6bacaafdbdafa67bdc0 Mon Sep 17 00:00:00 2001 From: Shreya Keshive Date: Mon, 15 Sep 2025 19:22:31 -0400 Subject: [PATCH] feat(ide): add auth token support to IdeClient (#8490) Co-authored-by: Jack Wotherspoon --- packages/core/src/ide/ide-client.test.ts | 30 ++++++++++++++++++++++++ packages/core/src/ide/ide-client.ts | 10 ++++++++ 2 files changed, 40 insertions(+) diff --git a/packages/core/src/ide/ide-client.test.ts b/packages/core/src/ide/ide-client.test.ts index fa1c948dba..7dff81bda6 100644 --- a/packages/core/src/ide/ide-client.test.ts +++ b/packages/core/src/ide/ide-client.test.ts @@ -656,4 +656,34 @@ describe('IdeClient', () => { expect(ideClient.isDiffingEnabled()).toBe(true); }); }); + + describe('authentication', () => { + it('should connect with an auth token if provided in the discovery file', async () => { + const authToken = 'test-auth-token'; + const config = { port: '8080', authToken }; + vi.mocked(fs.promises.readFile).mockResolvedValue(JSON.stringify(config)); + ( + vi.mocked(fs.promises.readdir) as Mock< + (path: fs.PathLike) => Promise + > + ).mockResolvedValue([]); + + const ideClient = await IdeClient.getInstance(); + await ideClient.connect(); + + expect(StreamableHTTPClientTransport).toHaveBeenCalledWith( + new URL('http://localhost:8080/mcp'), + expect.objectContaining({ + requestInit: { + headers: { + Authorization: `Bearer ${authToken}`, + }, + }, + }), + ); + expect(ideClient.getConnectionStatus().status).toBe( + IDEConnectionStatus.Connected, + ); + }); + }); }); diff --git a/packages/core/src/ide/ide-client.ts b/packages/core/src/ide/ide-client.ts index 494d1182f0..abd774687d 100644 --- a/packages/core/src/ide/ide-client.ts +++ b/packages/core/src/ide/ide-client.ts @@ -60,6 +60,7 @@ type StdioConfig = { type ConnectionConfig = { port?: string; stdio?: StdioConfig; + authToken?: string; }; function getRealPath(path: string): string { @@ -86,6 +87,7 @@ export class IdeClient { private currentIde: DetectedIde | undefined; private currentIdeDisplayName: string | undefined; private ideProcessInfo: { pid: number; command: string } | undefined; + private authToken: string | undefined; private diffResponses = new Map void>(); private statusListeners = new Set<(state: IDEConnectionState) => void>(); private trustChangeListeners = new Set<(isTrusted: boolean) => void>(); @@ -145,6 +147,9 @@ export class IdeClient { this.setState(IDEConnectionStatus.Connecting); const configFromFile = await this.getConnectionConfigFromFile(); + if (configFromFile?.authToken) { + this.authToken = configFromFile.authToken; + } const workspacePath = configFromFile?.workspacePath ?? process.env['GEMINI_CLI_IDE_WORKSPACE_PATH']; @@ -772,6 +777,11 @@ export class IdeClient { new URL(`http://${getIdeServerHost()}:${port}/mcp`), { fetch: this.createProxyAwareFetch(), + requestInit: { + headers: this.authToken + ? { Authorization: `Bearer ${this.authToken}` } + : {}, + }, }, ); await this.client.connect(transport);