Skip to main content
Glama

@pokutuna/mcp-chrome-tabs

by pokutuna
safari.ts3.75 kB
import type { BrowserInterface, TabRef, Tab, TabContent } from "./browser.js"; import { escapeAppleScript, executeAppleScript, separator, } from "./osascript.js"; async function getSafariTabList(applicationName: string): Promise<Tab[]> { const sep = separator(); const appleScript = ` tell application "${applicationName}" set output to "" repeat with aWindow in (every window) set windowId to id of aWindow repeat with aTab in (every tab of aWindow) set tabIndex to index of aTab set tabTitle to name of aTab set tabURL to URL of aTab set output to output & windowId & "${sep}" & tabIndex & "${sep}" & tabTitle & "${sep}" & tabURL & "\\n" end repeat end repeat return output end tell `; const result = await executeAppleScript(appleScript); const lines = result.trim().split("\n"); const tabs: Tab[] = []; for (const line of lines) { const [wId, tId, title, url] = line.split(sep); if (!/^https?:\/\//.test(url)) continue; // Note: Safari tab IDs are volatile indices that change when tabs are closed // Unlike Chrome, Safari doesn't provide stable unique tab identifiers tabs.push({ windowId: wId, tabId: tId, title: title.trim(), url: url.trim(), }); } return tabs; } async function getPageContent( applicationName: string, tab?: TabRef | null ): Promise<TabContent> { const sep = separator(); const inner = ` set tabTitle to name set tabURL to URL set tabContent to do JavaScript "document.documentElement.outerHTML" return tabTitle & "${sep}" & tabURL & "${sep}" & tabContent `; const appleScript = tab ? ` try tell application "${applicationName}" tell window id "${tab.windowId}" tell tab ${tab.tabId} with timeout of 3 seconds ${inner} end timeout end tell end tell end tell on error errMsg return "ERROR" & "${sep}" & errMsg end try ` : ` try tell application "${applicationName}" tell front window set t to current tab if URL of t is not "about:blank" then tell t with timeout of 3 seconds ${inner} end timeout end tell else error "No active tab found" end if end tell end tell on error errMsg return "ERROR" & "${sep}" & errMsg end try `; const scriptResult = await executeAppleScript(appleScript); if (scriptResult.startsWith(`ERROR${sep}`)) { throw new Error(scriptResult.split(sep)[1]); } const parts = scriptResult.split(sep).map((part) => part.trim()); if (parts.length < 3) { throw new Error("Failed to read the tab content"); } const [title, url, content] = parts; return { title, url, content, }; } async function openURL(applicationName: string, url: string): Promise<TabRef> { const escapedUrl = escapeAppleScript(url); const sep = separator(); const appleScript = ` tell application "${applicationName}" tell front window set newTab to (make new tab with properties {URL:"${escapedUrl}"}) set windowId to id set tabIndex to index of newTab return (windowId as string) & "${sep}" & (tabIndex as string) end tell end tell `; const result = await executeAppleScript(appleScript); const [windowId, tabId] = result.trim().split(sep); return { windowId, tabId }; } export const safariBrowser: BrowserInterface = { getTabList: getSafariTabList, getPageContent, openURL, };

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/pokutuna/mcp-chrome-tabs'

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