diff --git a/packages/core/src/agents/browser/browserManager.test.ts b/packages/core/src/agents/browser/browserManager.test.ts index d60f6ab982..6c25181afe 100644 --- a/packages/core/src/agents/browser/browserManager.test.ts +++ b/packages/core/src/agents/browser/browserManager.test.ts @@ -31,6 +31,7 @@ vi.mock('@modelcontextprotocol/sdk/client/index.js', () => ({ vi.mock('@modelcontextprotocol/sdk/client/stdio.js', () => ({ StdioClientTransport: vi.fn().mockImplementation(() => ({ close: vi.fn().mockResolvedValue(undefined), + stderr: null, })), })); @@ -144,14 +145,16 @@ describe('BrowserManager', () => { await manager.ensureConnection(); // Verify StdioClientTransport was created with correct args - expect(StdioClientTransport).toHaveBeenCalledWith({ - command: 'npx', - args: expect.arrayContaining([ - '-y', - expect.stringMatching(/chrome-devtools-mcp@/), - '--experimental-vision', - ]), - }); + expect(StdioClientTransport).toHaveBeenCalledWith( + expect.objectContaining({ + command: 'npx', + args: expect.arrayContaining([ + '-y', + expect.stringMatching(/chrome-devtools-mcp@/), + '--experimental-vision', + ]), + }), + ); // Persistent mode should NOT include --isolated or --autoConnect const args = vi.mocked(StdioClientTransport).mock.calls[0]?.[0] ?.args as string[]; @@ -180,10 +183,12 @@ describe('BrowserManager', () => { const manager = new BrowserManager(headlessConfig); await manager.ensureConnection(); - expect(StdioClientTransport).toHaveBeenCalledWith({ - command: 'npx', - args: expect.arrayContaining(['--headless']), - }); + expect(StdioClientTransport).toHaveBeenCalledWith( + expect.objectContaining({ + command: 'npx', + args: expect.arrayContaining(['--headless']), + }), + ); }); it('should pass profilePath as --userDataDir when configured', async () => { @@ -203,10 +208,12 @@ describe('BrowserManager', () => { const manager = new BrowserManager(profileConfig); await manager.ensureConnection(); - expect(StdioClientTransport).toHaveBeenCalledWith({ - command: 'npx', - args: expect.arrayContaining(['--userDataDir', '/path/to/profile']), - }); + expect(StdioClientTransport).toHaveBeenCalledWith( + expect.objectContaining({ + command: 'npx', + args: expect.arrayContaining(['--userDataDir', '/path/to/profile']), + }), + ); }); it('should pass --isolated when sessionMode is isolated', async () => { diff --git a/packages/core/src/agents/browser/browserManager.ts b/packages/core/src/agents/browser/browserManager.ts index 6abaa6b233..205eb11a1f 100644 --- a/packages/core/src/agents/browser/browserManager.ts +++ b/packages/core/src/agents/browser/browserManager.ts @@ -279,12 +279,25 @@ export class BrowserManager { `Launching chrome-devtools-mcp (${sessionMode} mode) with args: ${mcpArgs.join(' ')}`, ); - // Create stdio transport to npx chrome-devtools-mcp + // Create stdio transport to npx chrome-devtools-mcp. + // stderr is piped (not inherited) to prevent MCP server banners and + // warnings from corrupting the UI in alternate buffer mode. this.mcpTransport = new StdioClientTransport({ command: 'npx', args: mcpArgs, + stderr: 'pipe', }); + // Forward piped stderr to debugLogger so it's visible with --debug. + const stderrStream = this.mcpTransport.stderr; + if (stderrStream) { + stderrStream.on('data', (chunk: Buffer) => { + debugLogger.log( + `[chrome-devtools-mcp stderr] ${chunk.toString().trimEnd()}`, + ); + }); + } + this.mcpTransport.onclose = () => { debugLogger.error( 'chrome-devtools-mcp transport closed unexpectedly. ' +