Skip to main content
Glama

Bookmark Geni MCP Server

by droidnext
browser_detector.py10.7 kB
""" Browser path detection for multiple browsers across different operating systems. """ import json import os import platform import logging logger = logging.getLogger(__name__) def home(): """Get user home directory.""" return os.path.expanduser("~") def get_os(): """Detect operating system.""" system = platform.system().lower() if "windows" in system: return "windows" if "darwin" in system: return "mac" if "linux" in system: return "linux" return "unknown" def build_chromium_paths(base): """Build list of bookmark paths for Chromium-based browsers.""" logger.debug(f"Checking Chromium base path: {base}") if not os.path.exists(base): logger.debug(f"Base path does not exist: {base}") return [] profiles = ["Default", "Profile 1", "Profile 2", "Profile 3"] results = [] for profile in profiles: path = os.path.join(base, profile, "Bookmarks") logger.debug(f"Checking bookmark path: {path}") if os.path.exists(path): logger.info(f"Found bookmark file: {path}") results.append(path) else: logger.debug(f"Bookmark file not found: {path}") return results def chrome_paths(): """Get Chrome bookmark paths.""" osname = get_os() logger.debug(f"Detecting Chrome bookmark paths on {osname}") paths = [] if osname == "windows": base = os.path.join(home(), "AppData", "Local", "Google", "Chrome", "User Data") logger.info(f"Chrome (Windows): Checking base path: {base}") paths = build_chromium_paths(base) elif osname == "mac": # macOS Chrome uses Default profile by default path = os.path.join(home(), "Library", "Application Support", "Google", "Chrome", "Default", "Bookmarks") logger.info(f"Chrome (macOS): Checking bookmark path: {path}") if os.path.exists(path): logger.info(f"Chrome (macOS): Found bookmark file: {path}") paths = [path] else: logger.debug(f"Chrome (macOS): Bookmark file not found: {path}") elif osname == "linux": base = os.path.join(home(), ".config", "google-chrome") logger.info(f"Chrome (Linux): Checking base path: {base}") paths = build_chromium_paths(base) logger.info(f"Chrome: Found {len(paths)} bookmark file(s)") return paths def edge_paths(): """Get Microsoft Edge bookmark paths.""" osname = get_os() logger.debug(f"Detecting Edge bookmark paths on {osname}") base = None if osname == "windows": base = os.path.join(home(), "AppData", "Local", "Microsoft", "Edge", "User Data") logger.info(f"Edge (Windows): Checking base path: {base}") elif osname == "mac": base = os.path.join(home(), "Library", "Application Support", "Microsoft Edge") logger.info(f"Edge (macOS): Checking base path: {base}") elif osname == "linux": base = os.path.join(home(), ".config", "microsoft-edge") logger.info(f"Edge (Linux): Checking base path: {base}") else: logger.debug(f"Edge: Unsupported OS: {osname}") return [] paths = build_chromium_paths(base) logger.info(f"Edge: Found {len(paths)} bookmark file(s)") return paths def opera_paths(): """Get Opera bookmark paths.""" osname = get_os() logger.debug(f"Detecting Opera bookmark paths on {osname}") base = None if osname == "windows": base = os.path.join(home(), "AppData", "Roaming", "Opera Software", "Opera Stable") bookmark_file = os.path.join(base, "Bookmarks") logger.info(f"Opera (Windows): Checking bookmark path: {bookmark_file}") if os.path.exists(bookmark_file): logger.info(f"Opera (Windows): Found bookmark file: {bookmark_file}") return [bookmark_file] else: logger.debug(f"Opera (Windows): Bookmark file not found: {bookmark_file}") return [] elif osname == "mac": base = os.path.join(home(), "Library", "Application Support", "com.operasoftware.Opera") logger.info(f"Opera (macOS): Checking base path: {base}") elif osname == "linux": base = os.path.join(home(), ".config", "opera") logger.info(f"Opera (Linux): Checking base path: {base}") else: logger.debug(f"Opera: Unsupported OS: {osname}") return [] bookmark_file = os.path.join(base, "Bookmarks") logger.info(f"Opera ({osname}): Checking bookmark path: {bookmark_file}") if os.path.exists(bookmark_file): logger.info(f"Opera ({osname}): Found bookmark file: {bookmark_file}") return [bookmark_file] else: logger.debug(f"Opera ({osname}): Bookmark file not found: {bookmark_file}") return [] def firefox_paths(): """Get Firefox bookmark paths (SQLite databases).""" osname = get_os() logger.debug(f"Detecting Firefox bookmark paths on {osname}") if osname == "windows": base = os.path.join(home(), "AppData", "Roaming", "Mozilla", "Firefox", "Profiles") logger.info(f"Firefox (Windows): Checking profiles directory: {base}") elif osname == "mac": base = os.path.join(home(), "Library", "Application Support", "Firefox", "Profiles") logger.info(f"Firefox (macOS): Checking profiles directory: {base}") elif osname == "linux": base = os.path.join(home(), ".mozilla", "firefox") logger.info(f"Firefox (Linux): Checking profiles directory: {base}") else: logger.debug(f"Firefox: Unsupported OS: {osname}") return [] paths = [] if os.path.exists(base): logger.debug(f"Firefox: Profiles directory exists, scanning for places.sqlite files") for folder in os.listdir(base): db = os.path.join(base, folder, "places.sqlite") logger.debug(f"Firefox: Checking database path: {db}") if os.path.exists(db): logger.info(f"Firefox: Found bookmark database: {db}") paths.append(db) else: logger.debug(f"Firefox: Profiles directory does not exist: {base}") logger.info(f"Firefox: Found {len(paths)} bookmark database(s)") return paths # Safari support removed - reading Bookmarks.plist requires special macOS permissions # def safari_paths(): # """Get Safari bookmark paths (macOS only).""" # if get_os() != "mac": # return [] # path = os.path.join(home(), "Library", "Safari", "Bookmarks.plist") # return [path] if os.path.exists(path) else [] def atlas_paths(): """Get ChatGPT Atlas bookmark paths (macOS only, Chromium-based).""" osname = get_os() logger.debug(f"Detecting ChatGPT Atlas bookmark paths on {osname}") if osname != "mac": logger.debug(f"Atlas: Only supported on macOS, current OS: {osname}") return [] candidates = [ os.path.join(home(), "Library", "Application Support", "ChatGPT Atlas", "Default", "Bookmarks"), os.path.join(home(), "Library", "Application Support", "ChatGPT Atlas", "Profile 1", "Bookmarks"), os.path.join(home(), "Library", "Application Support", "Atlas", "Default", "Bookmarks"), ] paths = [] for candidate in candidates: logger.info(f"Atlas (macOS): Checking bookmark path: {candidate}") if os.path.exists(candidate): logger.info(f"Atlas (macOS): Found bookmark file: {candidate}") paths.append(candidate) else: logger.debug(f"Atlas (macOS): Bookmark file not found: {candidate}") logger.info(f"Atlas: Found {len(paths)} bookmark file(s)") return paths def comet_paths(): """Get Perplexity Comet bookmark paths (Chromium-based).""" osname = get_os() logger.debug(f"Detecting Comet bookmark paths on {osname}") paths = [] if osname == "windows": base = os.path.join(home(), "AppData", "Local", "Perplexity", "Comet", "User Data") logger.info(f"Comet (Windows): Checking base path: {base}") paths = build_chromium_paths(base) elif osname == "mac": # macOS Comet uses Default profile with singular "Bookmark" filename path = os.path.join(home(), "Library", "Application Support", "Comet", "Default", "Bookmark") logger.info(f"Comet (macOS): Checking bookmark path: {path}") if os.path.exists(path): logger.info(f"Comet (macOS): Found bookmark file: {path}") paths = [path] else: logger.debug(f"Comet (macOS): Bookmark file not found: {path}") elif osname == "linux": base = os.path.join(home(), ".config", "perplexity-comet") logger.info(f"Comet (Linux): Checking base path: {base}") paths = build_chromium_paths(base) logger.info(f"Comet: Found {len(paths)} bookmark file(s)") return paths # Browser registry mapping browser names to their path detection functions # Note: Safari support removed - reading Bookmarks.plist requires special macOS permissions BROWSERS = { "Chrome": chrome_paths, "Edge": edge_paths, "Opera": opera_paths, "Firefox": firefox_paths, # "Safari": safari_paths, # Removed - requires macOS permissions "ChatGPT Atlas": atlas_paths, "Perplexity Comet": comet_paths, } def get_available_browsers(custom_paths_config=None): """ Get list of browsers with detected bookmark paths. Args: custom_paths_config: Optional dictionary mapping browser names to list of custom paths e.g. {"Chrome": ["/path/to/bookmarks"]} """ available = {} custom_paths_config = custom_paths_config or {} for browser_name, path_fn in BROWSERS.items(): # Check for custom paths first if browser_name in custom_paths_config and custom_paths_config[browser_name]: paths = custom_paths_config[browser_name] logger.info(f"{browser_name}: Using custom paths from config: {paths}") available[browser_name] = paths continue # Fallback to auto-detection paths = path_fn() if paths: available[browser_name] = paths return available def get_browser_paths(browser_name, custom_paths=None): """ Get bookmark paths for a specific browser. Args: browser_name: Name of the browser custom_paths: Optional list of custom paths to use instead of auto-detection """ if custom_paths: logger.info(f"{browser_name}: Using custom paths from config: {custom_paths}") return custom_paths if browser_name not in BROWSERS: return [] return BROWSERS[browser_name]()

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/droidnext/bookmark_geni_mcp'

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