browser_tab_new
Opens a new browser tab to enable multi-tab browsing during automated tasks.
Instructions
browser tab new
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
No arguments | |||
Implementation Reference
- src/tools/browser_tools.js:868-904 (handler)The main handler function that creates a new browser tab using Playwright. It gets or creates a browser context, opens a new page, navigates to an optional URL, switches to the new tab, and returns success/failure.
async function browserTabNew(url) { try { const browser = await getBrowser(); if (!context) { context = await browser.newContext(); } const newPage = await context.newPage(); if (url) { await newPage.goto(url, { waitUntil: 'domcontentloaded', timeout: config.timeout }); } // Switch to new tab page = newPage; const pages = context.pages(); const newIndex = pages.indexOf(newPage); return { success: true, message: 'New tab opened', index: newIndex, url: newPage.url() }; } catch (error) { logger.error(`Error opening new tab: ${error.message}`); return { success: false, message: error.message }; } } - src/mcp/server.js:126-136 (registration)Registration of browser_tab_new in the MCP server's tool list. It's added as a browser extra tool with a generated description and empty input schema (no required params).
// Add extended browser tool schemas to exceed 50 tools (matches prior capability set) const browserExtras = [ { n:'browser_navigate_back' }, { n:'browser_navigate_forward' }, { n:'browser_hover' }, { n:'browser_drag' }, { n:'browser_select_option' }, { n:'browser_press_key' }, { n:'browser_snapshot' }, { n:'browser_console_messages' }, { n:'browser_network_requests' }, { n:'browser_tab_list' }, { n:'browser_tab_new' }, { n:'browser_tab_select' }, { n:'browser_tab_close' }, { n:'browser_file_upload' }, { n:'browser_wait' }, { n:'browser_wait_for' }, { n:'browser_resize' }, { n:'browser_handle_dialog' } ]; for (const b of browserExtras) { tools.push({ name: b.n, description: b.n.replace(/_/g,' '), inputSchema: { type:'object', properties:{} } }); } - src/mcp/server.js:134-137 (registration)The loop that pushes browser extras (including browser_tab_new) into the tools array sent in the tools/list response.
for (const b of browserExtras) { tools.push({ name: b.n, description: b.n.replace(/_/g,' '), inputSchema: { type:'object', properties:{} } }); } sendResponse(id, { tools }); - src/mcp/server.js:293-295 (registration)The tools/call handler that dispatches 'browser_tab_new' to the browserTools.browserTabNew(args.url) function.
case 'browser_tab_new': data = await browserTools.browserTabNew(args.url); break; case 'browser_tab_select': data = await browserTools.browserTabSelect(args.index); break; case 'browser_tab_close': data = await browserTools.browserTabClose(args.index); break; - src/tools/browser_tools.js:895-1162 (helper)Export of browserTabNew from the browser_tools module.
}; } catch (error) { logger.error(`Error opening new tab: ${error.message}`); return { success: false, message: error.message }; } } /** * Select a tab by index */ async function browserTabSelect(index) { try { if (index === undefined || isNaN(index)) { return { success: false, message: 'Tab index is required' }; } const browser = await getBrowser(); const pages = context ? context.pages() : []; if (index < 0 || index >= pages.length) { return { success: false, message: `Invalid tab index: ${index}. Valid range: 0-${pages.length - 1}` }; } page = pages[index]; await page.bringToFront(); return { success: true, message: `Switched to tab ${index}`, index, url: page.url(), title: await page.title() }; } catch (error) { logger.error(`Error selecting tab: ${error.message}`); return { success: false, message: error.message }; } } /** * Close a tab */ async function browserTabClose(index) { try { const browser = await getBrowser(); const pages = context ? context.pages() : []; // If no index specified, close current tab if (index === undefined) { if (page && !page.isClosed()) { await page.close(); // Switch to another tab if available const remainingPages = context.pages(); if (remainingPages.length > 0) { page = remainingPages[remainingPages.length - 1]; } else { page = null; } return { success: true, message: 'Current tab closed' }; } } else { // Close tab by index if (index < 0 || index >= pages.length) { return { success: false, message: `Invalid tab index: ${index}` }; } await pages[index].close(); // If we closed the current page, switch to another if (pages[index] === page) { const remainingPages = context.pages(); if (remainingPages.length > 0) { page = remainingPages[Math.min(index, remainingPages.length - 1)]; } else { page = null; } } return { success: true, message: `Tab ${index} closed` }; } } catch (error) { logger.error(`Error closing tab: ${error.message}`); return { success: false, message: error.message }; } } /** * Wait for text or time */ async function browserWaitFor(options = {}) { try { const page = await getPage(); if (options.text) { // Wait for text to appear await page.waitForSelector(`text=${options.text}`, { timeout: config.timeout }); return { success: true, message: `Found text: ${options.text}` }; } else if (options.textGone) { // Wait for text to disappear await page.waitForSelector(`text=${options.textGone}`, { state: 'hidden', timeout: config.timeout }); return { success: true, message: `Text disappeared: ${options.textGone}` }; } else if (options.time) { // Wait for specified time const waitTime = Math.min(options.time, 10) * 1000; await page.waitForTimeout(waitTime); return { success: true, message: `Waited for ${waitTime / 1000} seconds` }; } else { return { success: false, message: 'Must specify text, textGone, or time to wait for' }; } } catch (error) { logger.error(`Error waiting: ${error.message}`); return { success: false, message: error.message }; } } /** * Network request monitoring */ async function browserNetworkRequests() { try { const page = await getPage(); // Set up request monitoring if not already done if (!page._networkRequests) { page._networkRequests = []; page.on('request', request => { page._networkRequests.push({ url: request.url(), method: request.method(), headers: request.headers(), postData: request.postData(), timestamp: new Date().toISOString(), type: 'request' }); }); page.on('response', response => { page._networkRequests.push({ url: response.url(), status: response.status(), statusText: response.statusText(), headers: response.headers(), timestamp: new Date().toISOString(), type: 'response' }); }); } return { success: true, requests: page._networkRequests || [], count: (page._networkRequests || []).length }; } catch (error) { logger.error(`Error getting network requests: ${error.message}`); return { success: false, message: error.message }; } } // Clean up on exit process.on('SIGINT', async () => { if (browser) { await browser.close().catch(() => {}); } process.exit(0); }); process.on('SIGTERM', async () => { if (browser) { await browser.close().catch(() => {}); } process.exit(0); }); module.exports = { // Navigation browserNavigate, browserNavigateBack, browserNavigateForward, // Interaction browserClick, browserType, browserHover, browserDrag, browserSelectOption, browserPressKey, // Capture browserTakeScreenshot, browserSnapshot, browserPdfSave, // Tab management browserTabList, browserTabNew, browserTabSelect, browserTabClose, // Utilities browserConsoleMessages, browserFileUpload, browserWait, browserWaitFor, browserResize, browserHandleDialog, browserClose, browserInstall, browserNetworkRequests };