From 32998325f71a3d9b0962a2f211911b09b888159c Mon Sep 17 00:00:00 2001 From: Christopher Date: Fri, 15 May 2026 14:16:07 +1000 Subject: [PATCH] fix(mcp): use native Windows browser opener --- src/core/mcp-http-stdio-proxy.ts | 24 ++++++++++++-------- tests/unit/core/mcp-http-stdio-proxy.test.ts | 13 +++++++++++ 2 files changed, 28 insertions(+), 9 deletions(-) create mode 100644 tests/unit/core/mcp-http-stdio-proxy.test.ts diff --git a/src/core/mcp-http-stdio-proxy.ts b/src/core/mcp-http-stdio-proxy.ts index d5357ac..979e627 100644 --- a/src/core/mcp-http-stdio-proxy.ts +++ b/src/core/mcp-http-stdio-proxy.ts @@ -129,16 +129,22 @@ function findFreePort(): Promise { }); } +export function getBrowserOpenCommands( + url: string, + platform: NodeJS.Platform = process.platform, +): Array<{ command: string; args: string[] }> { + return platform === 'darwin' + ? [{ command: 'open', args: [url] }] + : platform === 'win32' + ? [{ command: 'explorer.exe', args: [url] }] + : [ + { command: 'xdg-open', args: [url] }, + { command: 'gio', args: ['open', url] }, + ]; +} + function tryOpenBrowser(url: string): Promise { - const commands: Array<{ command: string; args: string[] }> = - process.platform === 'darwin' - ? [{ command: 'open', args: [url] }] - : process.platform === 'win32' - ? [{ command: 'cmd', args: ['/c', 'start', '', url] }] - : [ - { command: 'xdg-open', args: [url] }, - { command: 'gio', args: ['open', url] }, - ]; + const commands = getBrowserOpenCommands(url); return new Promise((resolve) => { const tryCommand = (index: number) => { diff --git a/tests/unit/core/mcp-http-stdio-proxy.test.ts b/tests/unit/core/mcp-http-stdio-proxy.test.ts new file mode 100644 index 0000000..ed7e2ea --- /dev/null +++ b/tests/unit/core/mcp-http-stdio-proxy.test.ts @@ -0,0 +1,13 @@ +import { describe, expect, test } from 'bun:test'; +import { getBrowserOpenCommands } from '../../../src/core/mcp-http-stdio-proxy.js'; + +describe('getBrowserOpenCommands', () => { + test('uses explorer on Windows so OAuth URLs are not parsed by cmd', () => { + const url = + 'https://idp.example/auth?response_type=code&client_id=test&state=abc'; + + expect(getBrowserOpenCommands(url, 'win32')).toEqual([ + { command: 'explorer.exe', args: [url] }, + ]); + }); +}); \ No newline at end of file