Skip to main content
Glama
arslankhanali

Apple Notes MCP Server

list_notes

Retrieve and display Apple Notes from specific accounts or folders to organize and access your information.

Instructions

List all notes or notes from a specific account/folder.

Args:
    account: Optional account name (e.g., "iCloud", "On My Mac")
    folder: Optional folder name within the account

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
accountNo
folderNo

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
resultYes

Implementation Reference

  • The handler function decorated with @mcp.tool() that implements the list_notes tool. It generates AppleScript based on optional account and folder parameters, executes it using run_applescript, parses the output, and formats a list of notes with names, IDs, and modification dates.
    @mcp.tool()
    async def list_notes(account: Optional[str] = None, folder: Optional[str] = None) -> str:
        """List all notes or notes from a specific account/folder.
        
        Args:
            account: Optional account name (e.g., "iCloud", "On My Mac")
            folder: Optional folder name within the account
        """
        if account and folder:
            script = f'''
            tell application "Notes"
                set accountName to "{escape_applescript_string(account)}"
                set folderName to "{escape_applescript_string(folder)}"
                set noteList to {{}}
                try
                    set targetAccount to account accountName
                    set targetFolder to folder folderName of targetAccount
                    repeat with aNote in notes of targetFolder
                        set end of noteList to (name of aNote) & "|" & (id of aNote) & "|" & (modification date of aNote as string)
                    end repeat
                end try
                return noteList
            end tell
            '''
        elif account:
            script = f'''
            tell application "Notes"
                set accountName to "{escape_applescript_string(account)}"
                set noteList to {{}}
                try
                    set targetAccount to account accountName
                    repeat with aNote in notes of targetAccount
                        set end of noteList to (name of aNote) & "|" & (id of aNote) & "|" & (modification date of aNote as string)
                    end repeat
                end try
                return noteList
            end tell
            '''
        else:
            script = '''
            tell application "Notes"
                set noteList to {}
                repeat with anAccount in accounts
                    repeat with aNote in notes of anAccount
                        set end of noteList to (name of anAccount) & "::" & (name of aNote) & "|" & (id of aNote) & "|" & (modification date of aNote as string)
                    end repeat
                end repeat
                return noteList
            end tell
            '''
        
        output, success = run_applescript(script)
        if not success:
            return output
        
        # Parse the output
        if not output or output == "{}":
            return "No notes found."
        
        # AppleScript returns a list like: {"Note 1|id1|date1", "Note 2|id2|date2"}
        # Parse it
        notes = []
        for item in output.split(", "):
            item = item.strip().strip('"').strip("'")
            if "|" in item:
                parts = item.split("|")
                if len(parts) >= 3:
                    notes.append({
                        "name": parts[0],
                        "id": parts[1],
                        "modified": parts[2]
                    })
        
        if not notes:
            return "No notes found."
        
        result = "Found notes:\n"
        for i, note in enumerate(notes, 1):
            result += f"{i}. {note['name']} (ID: {note['id']}, Modified: {note['modified']})\n"
        
        return result
  • Helper function used by list_notes to execute AppleScript commands via subprocess and return output or error.
    def run_applescript(script: str) -> tuple[str, bool]:
        """Run an AppleScript command and return the output."""
        try:
            result = subprocess.run(
                ["osascript", "-e", script],
                capture_output=True,
                text=True,
                timeout=30
            )
            if result.returncode == 0:
                return result.stdout.strip(), True
            else:
                error_msg = result.stderr.strip() or result.stdout.strip()
                return f"Error: {error_msg}", False
        except subprocess.TimeoutExpired:
            return "Error: AppleScript execution timed out", False
        except Exception as e:
            return f"Error: {str(e)}", False
  • Helper function used by list_notes to properly escape strings for safe inclusion in AppleScript.
    def escape_applescript_string(text: str) -> str:
        """Escape special characters for AppleScript strings."""
        # Replace backslashes, quotes, and newlines
        text = text.replace("\\", "\\\\")
        text = text.replace('"', '\\"')
        text = text.replace("\n", "\\n")
        return text
  • apple_notes.py:46-46 (registration)
    The @mcp.tool() decorator registers the list_notes function as an MCP tool.
    @mcp.tool()
  • Docstring defining the input schema (parameters) for the list_notes tool.
    """List all notes or notes from a specific account/folder.
    
    Args:
        account: Optional account name (e.g., "iCloud", "On My Mac")
        folder: Optional folder name within the account
    """
Behavior2/5

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

With no annotations provided, the description carries full burden for behavioral disclosure. It states the tool lists notes but doesn't describe what 'list' entails (e.g., format, pagination, sorting, permissions needed, or rate limits). For a read operation with zero annotation coverage, this leaves significant behavioral gaps.

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 appropriately sized and front-loaded with the core purpose in the first sentence. The parameter explanations are brief but could be more integrated; overall, it avoids unnecessary verbosity while maintaining clarity.

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

Completeness3/5

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

Given the tool's low complexity (2 optional parameters) and the presence of an output schema (which handles return values), the description is minimally adequate. However, with no annotations and incomplete parameter documentation, it lacks sufficient context for optimal agent use, especially regarding behavioral aspects.

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

Parameters3/5

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

Schema description coverage is 0%, so the description must compensate. It explains that parameters are optional and provides examples ('iCloud', 'On My Mac'), adding meaning beyond the bare schema. However, it doesn't fully document parameter constraints or interactions, resulting in adequate but incomplete coverage.

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

Purpose4/5

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

The description clearly states the tool's purpose with a specific verb ('List') and resource ('notes'), and distinguishes between listing all notes or filtered by account/folder. However, it doesn't explicitly differentiate from sibling tools like 'search_notes' or 'list_accounts', which prevents a perfect score.

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 like 'search_notes' or 'list_accounts'. It mentions optional filtering but doesn't explain when filtering is appropriate or what happens when no parameters are provided, leaving usage decisions unclear.

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/arslankhanali/apple-notes-mcp'

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