From 999a070d088e1087ea0c5e67fb82270c406f9579 Mon Sep 17 00:00:00 2001 From: Roey Ben Arieh Date: Sun, 18 Oct 2026 02:11:27 +0300 Subject: [PATCH] feat(extension): do not steal focus when connecting via token --- packages/extension/src/background.ts | 16 ++++++++++------ packages/extension/src/ui/connect.tsx | 6 ++++-- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/packages/extension/src/background.ts b/packages/extension/src/background.ts index 801f69084c5a4..6f8c24bb1344a 100644 --- a/packages/extension/src/background.ts +++ b/packages/extension/src/background.ts @@ -29,6 +29,8 @@ type PageMessage = { // selection happens. tab?: chrome.tabs.Tab; clientName?: string; + // False when the MCP server asked not to take focus on connect. Absent means true. + focusTab?: boolean; } | { type: 'getConnectionStatus'; } | { @@ -74,7 +76,7 @@ class PlaywrightExtension { // sender.tab and UI-supplied tabs come from chrome.tabs.query / runtime // message sender, where `id` is always defined. const selectedTab = (message.tab ?? sender.tab!) as chrome.tabs.Tab & { id: number }; - this._connectTab(sender.tab!.id!, selectedTab, message.clientName).then( + this._connectTab(sender.tab!.id!, selectedTab, message.clientName, message.focusTab !== false).then( () => sendResponse({ success: true }), (error: any) => sendResponse({ success: false, error: error.message })); return true; // Return true to indicate that the response will be sent asynchronously @@ -99,7 +101,7 @@ class PlaywrightExtension { } } - private async _connectTab(selectorTabId: number, tab: chrome.tabs.Tab & { id: number }, clientName: string | undefined): Promise { + private async _connectTab(selectorTabId: number, tab: chrome.tabs.Tab & { id: number }, clientName: string | undefined, focusTab: boolean): Promise { try { await this._cleanupPromise; this._releaseTab(selectorTabId); @@ -116,10 +118,12 @@ class PlaywrightExtension { group.onclose = () => this._connections.delete(id); this._connections.set(id, group); - await Promise.all([ - chrome.tabs.update(tab.id, { active: true }), - chrome.windows.update(tab.windowId, { focused: true }), - ]).catch(() => {}); + if (focusTab) { + await Promise.all([ + chrome.tabs.update(tab.id, { active: true }), + chrome.windows.update(tab.windowId, { focused: true }), + ]).catch(() => {}); + } if (tab.id !== selectorTabId) await chrome.tabs.remove(selectorTabId).catch(() => {}); diff --git a/packages/extension/src/ui/connect.tsx b/packages/extension/src/ui/connect.tsx index 1385ee17968c3..914f50a21f068 100644 --- a/packages/extension/src/ui/connect.tsx +++ b/packages/extension/src/ui/connect.tsx @@ -102,7 +102,8 @@ const ConnectApp: React.FC = () => { window.history.replaceState(null, '', url); } if (token === expectedToken) { - await handleConnectToTab(); + // Token bypass: no user picked a tab, so do not steal focus. + await handleConnectToTab(undefined, false); return; } if (token) { @@ -134,7 +135,7 @@ const ConnectApp: React.FC = () => { setStatus({ type: 'error', message: 'Failed to load tabs: ' + response.error }); }, []); - const handleConnectToTab = useCallback(async (tab?: chrome.tabs.Tab) => { + const handleConnectToTab = useCallback(async (tab?: chrome.tabs.Tab, focusTab = true) => { setShowTabList(false); try { @@ -142,6 +143,7 @@ const ConnectApp: React.FC = () => { type: 'connectToTab', tab, clientName: clientInfo, + focusTab, }); if (response?.success) {