Skip to main content
Glama
kazuph

MCP Browser Tabs Server

by kazuph

get_tabs

Retrieve all open Google Chrome tabs with unique, persistent IDs for reliable identification and management. Output includes both display format and Tab ID for consistent operations via the MCP Browser Tabs Server.

Instructions

Get all open tabs from Google Chrome browser with unique tab IDs. Each tab has a stable, unique ID that persists across browser operations. Output shows both display format (1-1, 1-2) and Tab ID [Tab ID: 1234567890] for each tab. ALWAYS use the Tab ID number for reliable operations.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault

No arguments

Implementation Reference

  • Handler for executing the 'get_tabs' tool: fetches Chrome tabs using getChromeTabsWithIds(), formats them with unique Tab IDs and safety instructions, returns formatted text response.
    if (name === "get_tabs") { const windows = await getChromeTabsWithIds(); const formattedOutput = windows .map((window) => { const activeTab = window.tabs.find(tab => tab.isActive); const activeIndicator = activeTab ? ` (Active: Tab ID ${activeTab.id})` : ""; return `Window ${window.windowIndex}${activeIndicator}: ${window.tabs .map((tab) => { const activeMarker = tab.isActive ? " ★" : ""; return ` ${window.windowIndex}-${tab.tabIndex}. ${tab.title}${activeMarker} ${tab.url} [Tab ID: ${tab.id}]${activeMarker}`; }) .join("\n")}`; }) .join("\n\n"); const totalTabs = windows.reduce((sum, window) => sum + window.tabs.length, 0); return { content: [ { type: "text", text: `Found ${totalTabs} open tabs in Chrome: ${formattedOutput} 🔥 CRITICAL INSTRUCTIONS FOR AI: 1. ALWAYS use Tab ID (numbers in [Tab ID: xxxxx]) for tab operations 2. NEVER use display numbers (1-1, 1-2) - these are just for human reference 3. Use close_tab_by_id or activate_tab_by_id with the Tab ID number 4. Example: If you see "[Tab ID: 1594670961]", use tabId: 1594670961 ⚠️ DANGER: Window-Tab index changes when tabs are reordered/closed ✅ SAFE: Tab ID never changes and is unique across all tabs`, }, ], }; }
  • src/index.ts:235-239 (registration)
    Registration of the 'get_tabs' tool in the listTools response, including name, description, and empty input schema (no parameters required).
    { name: "get_tabs", description: "Get all open tabs from Google Chrome browser with unique tab IDs. Each tab has a stable, unique ID that persists across browser operations. Output shows both display format (1-1, 1-2) and Tab ID [Tab ID: 1234567890] for each tab. ALWAYS use the Tab ID number for reliable operations.", inputSchema: zodToJsonSchema(z.object({})), },
  • Input schema for get_tabs tool: empty object since no input parameters are needed.
    inputSchema: zodToJsonSchema(z.object({})), },
  • Core helper function that runs AppleScript to fetch all Chrome tabs with unique IDs, parses the pipe-delimited output, groups by window, and returns structured ChromeWindow[] data used by the get_tabs handler.
    async function getChromeTabsWithIds(): Promise<ChromeWindow[]> { const script = ` tell application "Google Chrome" set windowList to windows set output to "" repeat with windowIndex from 1 to count of windowList set theWindow to item windowIndex of windowList set windowID to id of theWindow set activeTabIndex to active tab index of theWindow set tabList to tabs of theWindow repeat with tabIndexInWindow from 1 to count of tabList set theTab to item tabIndexInWindow of tabList set tabID to id of theTab set isActive to (tabIndexInWindow = activeTabIndex) set output to output & windowID & "|||" & windowIndex & "|||" & tabID & "|||" & tabIndexInWindow & "|||" & isActive & "|||" & (title of theTab) & "|||" & (URL of theTab) & "\\n" end repeat end repeat return output end tell `; try { const { stdout } = await execAsync(`osascript -e '${script}'`); const tabsData = stdout .trim() .split("\n") .filter((line) => line.length > 0) .map((line) => { const [windowId, windowIndex, tabId, tabIndex, isActive, title, url] = line.split("|||"); return { windowId: Number.parseInt(windowId, 10), windowIndex: Number.parseInt(windowIndex, 10), tabId: Number.parseInt(tabId, 10), tabIndex: Number.parseInt(tabIndex, 10), isActive: isActive === "true", title: title || "", url: url || "", }; }); // Group by windows const windowMap = new Map<number, ChromeWindow>(); for (const tabData of tabsData) { if (!windowMap.has(tabData.windowId)) { windowMap.set(tabData.windowId, { windowId: tabData.windowId, windowIndex: tabData.windowIndex, tabs: [], }); } const window = windowMap.get(tabData.windowId)!; window.tabs.push({ id: tabData.tabId, windowId: tabData.windowId, title: tabData.title, url: tabData.url, isActive: tabData.isActive, windowIndex: tabData.windowIndex, tabIndex: tabData.tabIndex, }); } return Array.from(windowMap.values()); } catch (error) { throw new Error( `Failed to get Chrome tabs: ${error instanceof Error ? error.message : String(error)}` ); } }
  • Type interfaces for ChromeTab and ChromeWindow used throughout the get_tabs implementation.
    interface ChromeTab { id: number; // Unique Chrome tab ID windowId: number; // Window ID title: string; url: string; isActive: boolean; windowIndex: number; // For backward compatibility tabIndex: number; // For backward compatibility }

Other Tools

Related Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/kazuph/mcp-browser-tabs'

If you have feedback or need assistance with the MCP directory API, please join our Discord server