
Security News
Axios Supply Chain Attack Reaches OpenAI macOS Signing Pipeline, Forces Certificate Rotation
OpenAI rotated macOS signing certificates after a malicious Axios package reached its CI pipeline in a broader software supply chain attack.
apple-notes-mcp
Advanced tools
MCP server for Apple Notes - create, search, update, and manage notes via Claude
A Model Context Protocol (MCP) server that enables AI assistants like Claude to read, create, search, and manage notes in Apple Notes on macOS.
This server acts as a bridge between AI assistants and Apple Notes. Once configured, you can ask Claude (or any MCP-compatible AI) to:
The AI assistant communicates with this server, which then uses AppleScript to interact with the Notes app on your Mac. All data stays local on your machine.
If you're using Claude Code (in Terminal or VS Code), just ask Claude to install it:
Install the sweetrb/apple-notes-mcp MCP server so you can help me manage my Apple Notes
Claude will handle the installation and configuration automatically.
Install as a Claude Code plugin for automatic configuration and enhanced AI behavior:
/plugin marketplace add sweetrb/apple-notes-mcp
/plugin install apple-notes
This method also installs a skill that teaches Claude when and how to use Apple Notes effectively.
1. Install the server:
npm install -g github:sweetrb/apple-notes-mcp
2. Add to Claude Desktop (~/Library/Application Support/Claude/claude_desktop_config.json):
{
"mcpServers": {
"apple-notes": {
"command": "npx",
"args": ["apple-notes-mcp"]
}
}
}
3. Restart Claude Desktop and start using natural language:
"Create a note called 'Ideas' with my brainstorming thoughts"
On first use, macOS will ask for permission to automate Notes.app. Click "OK" to allow.
| Feature | Description |
|---|---|
| Create Notes | Create notes with titles, content, and optional folder/account targeting |
| Search Notes | Find notes by title or search within note content |
| Read Notes | Retrieve note content and metadata |
| Update Notes | Modify existing notes (title and/or content) |
| Delete Notes | Remove notes (moves to Recently Deleted) |
| Move Notes | Organize notes into folders (supports nested paths) |
| Folder Management | Create, list, and delete folders with full hierarchical path support |
| Multi-Account | Work with iCloud, Gmail, Exchange, or any configured account |
| Batch Operations | Delete or move multiple notes at once |
| Checklist State | Read checklist done/undone state directly from the Notes database |
| Export | Export all notes as JSON or get individual notes as Markdown |
| Attachments | List attachments in notes |
| Sync Awareness | Detect iCloud sync in progress, warn about incomplete results |
| Collaboration | Detect shared notes, warn before modifying |
| Diagnostics | Health check, sync status, and statistics tools |
This section documents all available tools. AI agents should use these tool names and parameters exactly as specified.
create-noteCreates a new note in Apple Notes.
| Parameter | Type | Required | Description |
|---|---|---|---|
title | string | Yes | The title of the note. Automatically prepended as <h1> — do NOT include the title in content |
content | string | Yes | The body content of the note (do not repeat the title here) |
tags | string[] | No | Tags for organization (stored in metadata) |
folder | string | No | Folder to create the note in. Supports nested paths like "Work/Clients". Defaults to account root |
account | string | No | Account name (defaults to iCloud) |
format | string | No | Content format: "plaintext" (default) or "html". In both formats, the title is automatically prepended as <h1>. In plaintext mode, newlines become <br>, tabs become <br>, and backslashes are preserved as HTML entities |
Example:
{
"title": "Meeting Notes",
"content": "Discussed Q4 roadmap and budget allocation",
"tags": ["work", "meetings"]
}
Example - Create in a specific folder:
{
"title": "Client Meeting",
"content": "Discussed project timeline",
"folder": "Work/Clients"
}
Example - HTML formatting:
{
"title": "Status Report",
"content": "<h2>Summary</h2><p>All tasks <b>on track</b>.</p><ul><li>Feature A: complete</li><li>Feature B: in progress</li></ul>",
"format": "html"
}
Note: The title is automatically prepended as
<h1>in both plaintext and HTML formats. Do not include a<h1>title tag in thecontentparameter, or the title will appear twice.
Returns: Confirmation message with note title and ID. Save the ID for subsequent operations like update-note, delete-note, etc.
search-notesSearches for notes by title or content.
| Parameter | Type | Required | Description |
|---|---|---|---|
query | string | Yes | Text to search for |
searchContent | boolean | No | If true, searches note body; if false (default), searches titles only |
account | string | No | Account to search in (defaults to iCloud) |
folder | string | No | Limit search to a specific folder (supports nested paths like "Work/Clients") |
modifiedSince | string | No | ISO 8601 date string to filter notes modified on or after this date (e.g., "2025-01-01") |
limit | number | No | Maximum number of results to return |
Example - Search titles:
{
"query": "meeting"
}
Example - Search content:
{
"query": "budget allocation",
"searchContent": true
}
Example - Search recent notes with limit:
{
"query": "todo",
"searchContent": true,
"modifiedSince": "2025-01-01",
"limit": 10
}
Returns: List of matching notes with titles, folder names, and IDs. Use the returned ID for subsequent operations like get-note-content, update-note, etc.
get-note-contentRetrieves the full content of a specific note.
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | No | Note ID (preferred - more reliable than title) |
title | string | No | Note title (use id instead when available) |
account | string | No | Account containing the note (defaults to iCloud, ignored if id is provided) |
Note: Either id or title must be provided. Using id is recommended as it's unique and avoids issues with duplicate titles.
Example - Using ID (recommended):
{
"id": "x-coredata://ABC123/ICNote/p456"
}
Example - Using title:
{
"title": "Shopping List"
}
Returns: The HTML content of the note, or error if not found.
get-note-detailsRetrieves metadata about a note (without full content).
| Parameter | Type | Required | Description |
|---|---|---|---|
title | string | Yes | Exact title of the note |
account | string | No | Account containing the note (defaults to iCloud) |
Example:
{
"title": "Project Plan"
}
Returns: JSON with note metadata:
{
"id": "x-coredata://...",
"title": "Project Plan",
"created": "2025-01-15T10:30:00.000Z",
"modified": "2025-01-20T14:22:00.000Z",
"shared": false,
"passwordProtected": false,
"account": "iCloud"
}
get-note-by-idRetrieves a note using its unique CoreData identifier.
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | The CoreData URL identifier (e.g., x-coredata://...) |
Returns: JSON with note metadata, or error if not found.
update-noteUpdates an existing note's content and/or title.
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | No | Note ID (preferred - more reliable than title) |
title | string | No | Current title of the note to update (use id instead when available) |
newTitle | string | No | New title (if changing the title; ignored when format is "html") |
newContent | string | Yes | New content for the note body |
account | string | No | Account containing the note (defaults to iCloud, ignored if id is provided) |
format | string | No | Content format: "plaintext" (default) or "html". When "html", content replaces the entire note body as raw HTML and newTitle is ignored (the first HTML element serves as the title) |
Note: Either id or title must be provided. Using id is recommended.
Example - Using ID (recommended):
{
"id": "x-coredata://ABC123/ICNote/p456",
"newContent": "Updated content here"
}
Example - Update content only:
{
"title": "Shopping List",
"newContent": "- Milk\n- Eggs\n- Bread\n- Butter"
}
Example - Update title and content:
{
"title": "Draft",
"newTitle": "Final Version",
"newContent": "This is the completed document."
}
Example - Update with HTML formatting:
{
"id": "x-coredata://ABC123/ICNote/p456",
"newContent": "<p>New findings with <b>bold</b> emphasis.</p><pre><code>console.log('hello');</code></pre>",
"format": "html"
}
Returns: Confirmation message, or error if note not found.
delete-noteDeletes a note (moves to Recently Deleted in Notes.app).
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | No | Note ID (preferred - more reliable than title) |
title | string | No | Exact title of the note to delete (use id instead when available) |
account | string | No | Account containing the note (defaults to iCloud, ignored if id is provided) |
Note: Either id or title must be provided. Using id is recommended.
Example - Using ID (recommended):
{
"id": "x-coredata://ABC123/ICNote/p456"
}
Example - Using title:
{
"title": "Old Draft"
}
Returns: Confirmation message, or error if note not found.
move-noteMoves a note to a different folder.
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | No | Note ID (preferred - more reliable than title) |
title | string | No | Title of the note to move (use id instead when available) |
folder | string | Yes | Destination folder name or nested path (e.g., "Work/Clients") |
account | string | No | Account containing the note (defaults to iCloud, ignored if id is provided) |
Note: Either id or title must be provided. Using id is recommended.
Example - Using ID (recommended):
{
"id": "x-coredata://ABC123/ICNote/p456",
"folder": "Archive"
}
Example - Using title:
{
"title": "Completed Task",
"folder": "Archive"
}
Returns: Confirmation message, or error if note or folder not found.
Note: This operation copies the note to the new folder then deletes the original. If the delete fails, the note will exist in both locations.
list-notesLists all notes, optionally filtered by folder, date, and limit.
| Parameter | Type | Required | Description |
|---|---|---|---|
account | string | No | Account to list notes from (defaults to iCloud) |
folder | string | No | Filter to notes in this folder only (supports nested paths like "Work/Clients") |
modifiedSince | string | No | ISO 8601 date string to filter notes modified on or after this date (e.g., "2025-01-01") |
limit | number | No | Maximum number of notes to return |
Example - All notes:
{}
Example - Notes in a folder:
{
"folder": "Work"
}
Example - Recent notes with limit:
{
"modifiedSince": "2025-06-01",
"limit": 20
}
Returns: List of note titles.
list-foldersLists all folders in an account with full hierarchical paths.
| Parameter | Type | Required | Description |
|---|---|---|---|
account | string | No | Account to list folders from (defaults to iCloud) |
Example:
{}
Returns: List of folder paths. Nested folders are shown as full paths (e.g., Work/Clients/Omnia). Duplicate folder names are disambiguated by their full path. Literal slashes in folder names are escaped as \/ (e.g., Spain\/Portugal 2023).
create-folderCreates a new folder.
| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Name for the new folder |
account | string | No | Account to create folder in (defaults to iCloud) |
Example:
{
"name": "Work Projects"
}
Returns: Confirmation message, or error if folder already exists.
delete-folderDeletes a folder.
| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Name or path of the folder to delete (supports nested paths like "Work/Old") |
account | string | No | Account containing the folder (defaults to iCloud) |
Example:
{
"name": "Old Projects"
}
Returns: Confirmation message, or error if folder not found or not empty.
list-accountsLists all configured Notes accounts.
Parameters: None
Example:
{}
Returns: List of account names (e.g., "iCloud", "Gmail", "Exchange").
batch-delete-notesDeletes multiple notes at once by ID.
| Parameter | Type | Required | Description |
|---|---|---|---|
ids | string[] | Yes | Array of note IDs to delete |
Returns: Summary of successes and failures.
batch-move-notesMoves multiple notes to a folder.
| Parameter | Type | Required | Description |
|---|---|---|---|
ids | string[] | Yes | Array of note IDs to move |
folder | string | Yes | Destination folder name or nested path (e.g., "Work/Clients") |
account | string | No | Account containing the folder |
Returns: Summary of successes and failures.
export-notes-jsonExports all notes as a JSON structure.
Parameters: None
Returns: Complete JSON export with all accounts, folders, and notes including metadata.
get-note-markdownGets a note's content as Markdown instead of HTML. If the note contains checklists and Full Disk Access is granted, checklist items are automatically annotated with [x] (done) or [ ] (undone).
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | No | Note ID (preferred) |
title | string | No | Note title |
account | string | No | Account containing the note |
Returns: Note content converted to Markdown format. Checklist items include [x]/[ ] prefixes when database access is available.
get-checklist-stateReads checklist done/undone state for a note. This bypasses the AppleScript limitation where body of note strips checklist state, by reading directly from the NoteStore SQLite database.
Requires: Full Disk Access for the MCP host process (see Full Disk Access Setup).
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Note ID (use search-notes to find it first) |
Example:
{
"id": "x-coredata://ABC123/ICNote/p456"
}
Returns: Checklist items with done/undone state and progress count:
Checklist for "Shopping List" (2/4 done):
[x] Buy milk
[x] Get bread
[ ] Pick up laundry
[ ] Call dentist
list-attachmentsLists attachments in a note.
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | No | Note ID (preferred) |
title | string | No | Note title |
account | string | No | Account containing the note |
Returns: List of attachments with names and content types.
health-checkVerifies Notes.app connectivity and permissions.
Parameters: None
Returns: Status of all health checks (app installed, permissions, account access).
get-notes-statsGets comprehensive statistics about your notes.
Parameters: None
Returns: Total counts, per-account breakdown, folder statistics, and recently modified counts.
get-sync-statusChecks iCloud sync status.
Parameters: None
Returns: Whether sync is active, pending uploads, and last activity time.
list-shared-notesLists all notes shared with collaborators.
Parameters: None
Returns: List of shared notes with warnings about collaboration.
User: "Create a note called 'Todo' with my tasks for today"
AI: [calls create-note with title="Todo", content="Tasks for today..."]
"I've created a note called 'Todo' with your tasks."
User: "What notes do I have?"
AI: [calls list-notes]
"You have 15 notes: Todo, Shopping List, Meeting Notes..."
User: "Show me the Shopping List"
AI: [calls get-note-content with title="Shopping List"]
"Here's your shopping list: - Milk - Eggs - Bread..."
By default, all operations use iCloud. To work with other accounts:
User: "What accounts do I have?"
AI: [calls list-accounts]
"You have 3 accounts: iCloud, Gmail, Exchange"
User: "List notes in my Gmail account"
AI: [calls list-notes with account="Gmail"]
"Your Gmail account has 5 notes..."
User: "Create a folder called 'Archive'"
AI: [calls create-folder with name="Archive"]
"Created folder 'Archive'"
User: "Move my old meeting notes to Archive"
AI: [calls move-note with title="Old Meeting Notes", folder="Archive"]
"Moved 'Old Meeting Notes' to 'Archive'"
User: "What folders do I have?"
AI: [calls list-folders]
"You have 5 folders: Work, Work/Clients, Work/Clients/Omnia, Archive, Recipes"
User: "Create a note in Work/Clients about Acme Corp"
AI: [calls create-note with title="Acme Corp", content="...", folder="Work/Clients"]
"Created 'Acme Corp' in Work/Clients"
npm install -g github:sweetrb/apple-notes-mcp
git clone https://github.com/sweetrb/apple-notes-mcp.git
cd apple-notes-mcp
npm install
npm run build
If installed from source, use this configuration:
{
"mcpServers": {
"apple-notes": {
"command": "node",
"args": ["/path/to/apple-notes-mcp/build/index.js"]
}
}
}
The get-checklist-state tool and checklist annotations in get-note-markdown read directly from the Apple Notes SQLite database. This requires Full Disk Access for the process running the MCP server.
/Applications/Claude.app/Applications/Utilities/Terminal.app/Applications/Visual Studio Code.app/Applications/iTerm.appAll other tools work normally without Full Disk Access. Only checklist state features are affected:
get-checklist-state will return an error explaining that database access is neededget-note-markdown will return plain list items without [x]/[ ] annotations (graceful fallback)| Limitation | Reason |
|---|---|
| macOS only | Apple Notes and AppleScript are macOS-specific |
| No attachment content | Attachments can be listed but not downloaded via AppleScript |
| No pinned notes | Pin status is not exposed via AppleScript |
| Limited rich formatting | Use format: "html" on create/update for headings, lists, bold, code blocks; some complex formatting may not render |
| Title matching | Most operations require exact title matches |
| Checklist state | Requires Full Disk Access to read done/undone state from the database |
When sending content containing backslashes (\) to this MCP server, you must escape them as \\ in the JSON parameters.
Why: The MCP protocol uses JSON for parameter passing. In JSON, a single backslash is an escape character. To include a literal backslash in content, it must be escaped as \\.
Example - Shell command with escaped path:
{
"title": "Install Script",
"content": "cp ~/Library/Mobile\\\\ Documents/file.txt ~/.config/"
}
The \\\\ in JSON becomes \\ in the actual string, which represents a single \ in the note.
Common patterns requiring escaping:
Mobile\ Documents → Mobile\\\\ Documents in JSONC:\Users\ → C:\\\\Users\\\\ in JSON\d+ → \\\\d+ in JSONIf you see errors when creating/updating notes with backslashes, double-check that backslashes are properly escaped in the JSON payload.
list-notes to see available notes\ characters requires JSON escaping\\ to represent each literal backslashnpm install # Install dependencies
npm run build # Compile TypeScript
npm test # Run test suite (313 tests)
npm run lint # Check code style
npm run format # Format code
Rob Sweet - President, Superior Technologies Research
A software consulting, contracting, and development company.
MIT License - see LICENSE for details.
Contributions are welcome! Please see CONTRIBUTING.md for guidelines.
FAQs
MCP server for Apple Notes - create, search, update, and manage notes via Claude
We found that apple-notes-mcp demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
OpenAI rotated macOS signing certificates after a malicious Axios package reached its CI pipeline in a broader software supply chain attack.

Security News
Open source is under attack because of how much value it creates. It has been the foundation of every major software innovation for the last three decades. This is not the time to walk away from it.

Security News
Socket CEO Feross Aboukhadijeh breaks down how North Korea hijacked Axios and what it means for the future of software supply chain security.