Skip to main content
Glama
carterlasalle

mac-messages-mcp

tool_check_addressbook

Diagnose AddressBook access issues on macOS to resolve problems with the Messages app functionality.

Instructions

Diagnose AddressBook access issues.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault

No arguments

Implementation Reference

  • The handler function for tool_check_addressbook. It is decorated with @mcp.tool() for registration and calls check_addressbook_access() to diagnose AddressBook access.
    @mcp.tool()
    def tool_check_addressbook(ctx: Context) -> str:
        """
        Diagnose AddressBook access issues.
        """
        logger.info("Checking AddressBook access")
        try:
            return check_addressbook_access()
        except Exception as e:
            logger.error(f"Error checking AddressBook: {str(e)}")
            return f"Error checking AddressBook: {str(e)}"
  • Core helper function that performs detailed checks on AddressBook database accessibility, file permissions, table presence, and retrieves sample contacts.
    def check_addressbook_access() -> str:
        """Check if the AddressBook database is accessible and return detailed information."""
        try:
            home_dir = os.path.expanduser("~")
            sources_path = os.path.join(home_dir, "Library/Application Support/AddressBook/Sources")
            status = []
            
            # Check if the directory exists
            if not os.path.exists(sources_path):
                return f"ERROR: AddressBook Sources directory not found at {sources_path} PLEASE TELL THE USER TO GRANT FULL DISK ACCESS TO THE TERMINAL APPLICATION(CURSOR, TERMINAL, CLAUDE, ETC.) AND RESTART THE APPLICATION. DO NOT RETRY UNTIL NEXT MESSAGE."
            
            status.append(f"AddressBook Sources directory exists at: {sources_path}")
            
            # Find database files
            db_paths = glob.glob(os.path.join(sources_path, "*/AddressBook-v22.abcddb"))
            
            if not db_paths:
                return f"ERROR: No AddressBook database files found in {sources_path} PLEASE TELL THE USER TO GRANT FULL DISK ACCESS TO THE TERMINAL APPLICATION(CURSOR, TERMINAL, CLAUDE, ETC.) AND RESTART THE APPLICATION. DO NOT RETRY UNTIL NEXT MESSAGE."
            
            status.append(f"Found {len(db_paths)} AddressBook database files:")
            for path in db_paths:
                status.append(f" - {path}")
            
            # Check file permissions for each database
            for db_path in db_paths:
                try:
                    with open(db_path, 'rb') as f:
                        # Just try to read a byte to confirm access
                        f.read(1)
                    status.append(f"File is readable: {db_path}")
                except PermissionError:
                    status.append(f"ERROR: Permission denied when trying to read {db_path} PLEASE TELL THE USER TO GRANT FULL DISK ACCESS TO THE TERMINAL APPLICATION(CURSOR, TERMINAL, CLAUDE, ETC.) AND RESTART THE APPLICATION. DO NOT RETRY UNTIL NEXT MESSAGE.")
                    continue
                except Exception as e:
                    status.append(f"ERROR: Unknown error reading file {db_path}: {str(e)} PLEASE TELL THE USER TO GRANT FULL DISK ACCESS TO THE TERMINAL APPLICATION(CURSOR, TERMINAL, CLAUDE, ETC.) AND RESTART THE APPLICATION. DO NOT RETRY UNTIL NEXT MESSAGE.")
                    continue
                
                # Try to connect to the database
                try:
                    conn = sqlite3.connect(db_path)
                    status.append(f"Successfully connected to database: {db_path}")
                    
                    # Test a simple query
                    cursor = conn.cursor()
                    cursor.execute("SELECT count(*) FROM sqlite_master")
                    count = cursor.fetchone()[0]
                    status.append(f"Database contains {count} tables")
                    
                    # Check if the necessary tables exist
                    cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name IN ('ZABCDRECORD', 'ZABCDPHONENUMBER')")
                    tables = [row[0] for row in cursor.fetchall()]
                    if 'ZABCDRECORD' in tables and 'ZABCDPHONENUMBER' in tables:
                        status.append("Required tables (ZABCDRECORD, ZABCDPHONENUMBER) are present")
                    else:
                        status.append(f"WARNING: Some required tables are missing. Found: {', '.join(tables)}")
                    
                    # Get a count of contacts
                    try:
                        cursor.execute("SELECT COUNT(*) FROM ZABCDRECORD")
                        contact_count = cursor.fetchone()[0]
                        status.append(f"Database contains {contact_count} contacts")
                    except sqlite3.OperationalError:
                        status.append("Could not query contact count PLEASE TELL THE USER TO GRANT FULL DISK ACCESS TO THE TERMINAL APPLICATION(CURSOR, TERMINAL, CLAUDE, ETC.) AND RESTART THE APPLICATION. DO NOT RETRY UNTIL NEXT MESSAGE.")
                    
                    conn.close()
                except sqlite3.OperationalError as e:
                    status.append(f"ERROR: Database connection error for {db_path}: {str(e)} PLEASE TELL THE USER TO GRANT FULL DISK ACCESS TO THE TERMINAL APPLICATION(CURSOR, TERMINAL, CLAUDE, ETC.) AND RESTART THE APPLICATION. DO NOT RETRY UNTIL NEXT MESSAGE.")
            
            # Try to get actual contacts
            contacts = get_addressbook_contacts()
            if contacts:
                status.append(f"Successfully retrieved {len(contacts)} contacts with phone numbers")
            else:
                status.append("WARNING: No contacts with phone numbers found. PLEASE TELL THE USER TO GRANT FULL DISK ACCESS TO THE TERMINAL APPLICATION(CURSOR, TERMINAL, CLAUDE, ETC.) AND RESTART THE APPLICATION. DO NOT RETRY UNTIL NEXT MESSAGE.")
            
            return "\n".join(status)
        except Exception as e:
            return f"ERROR: Unexpected error during database access check: {str(e)} PLEASE TELL THE USER TO GRANT FULL DISK ACCESS TO THE TERMINAL APPLICATION(CURSOR, TERMINAL, CLAUDE, ETC.) AND RESTART THE APPLICATION. DO NOT RETRY UNTIL NEXT MESSAGE."
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure. It states the tool diagnoses issues but does not specify what 'diagnose' entails—e.g., whether it performs read-only checks, requires permissions, returns error details, or has side effects. This leaves critical behavioral traits unclear for safe and effective use.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, efficient sentence ('Diagnose AddressBook access issues.') that is front-loaded and wastes no words. It could be slightly improved by adding context or usage hints, but it effectively conveys the core purpose without unnecessary elaboration, earning a high score for conciseness.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's diagnostic nature, lack of annotations, and no output schema, the description is incomplete. It does not explain what the diagnosis returns, how results are structured, or any behavioral constraints. For a tool that likely involves system checks, more context is needed to ensure the agent understands its operation and outputs.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool has 0 parameters, and schema description coverage is 100%, meaning no parameters need documentation. The description does not add parameter details, which is appropriate here. A baseline score of 4 is assigned as the description does not need to compensate for any parameter gaps, aligning with the rule for zero parameters.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose3/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description 'Diagnose AddressBook access issues' clearly states the tool's purpose with a specific verb ('diagnose') and target ('AddressBook access issues'), avoiding tautology. However, it does not distinguish this from sibling tools like 'tool_check_contacts' or 'tool_check_db_access', which might have overlapping diagnostic functions, leaving room for ambiguity in tool selection.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides no guidance on when to use this tool versus alternatives. It does not mention prerequisites, context for diagnosing access issues, or refer to sibling tools for related tasks, such as 'tool_check_contacts' for contact-specific checks. This lack of usage context could lead to incorrect tool selection by an agent.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other 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/carterlasalle/mac_messages_mcp'

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