loading…
Search for a command to run...
loading…
Apple Notes MCP with semantic search, hybrid vector+keyword search, full CRUD operations, and incremental indexing. Uses JXA for native macOS integration.
Apple Notes MCP with semantic search, hybrid vector+keyword search, full CRUD operations, and incremental indexing. Uses JXA for native macOS integration.
npm version npm downloads License: MIT macOS Bun Claude
MCP server for Apple Notes with semantic search and CRUD operations. Claude searches, reads, creates, updates, and manages your Apple Notes through natural language.
list-notes folder filtering - list-notes now queries only the requested folder instead of scanning all notes firstnpm install -g @disco_trooper/apple-notes-mcp
apple-notes-mcp
The setup wizard guides you through:
git clone https://github.com/disco-trooper/apple-notes-mcp.git
cd apple-notes-mcp
bun install
bun run start
Run the command after installation:
apple-notes-mcp
The setup wizard starts automatically on first run. Restart Claude Code after setup to use the MCP tools.
Configuration stored in ~/.apple-notes-mcp/.env:
| Variable | Description | Default |
|---|---|---|
OPENROUTER_API_KEY |
OpenRouter API key (enables cloud embeddings) | - |
EMBEDDING_MODEL |
Model name (local or OpenRouter) | Xenova/multilingual-e5-small |
EMBEDDING_DIMS |
Embedding dimensions | 4096 |
READONLY_MODE |
Block all write operations | false |
INDEX_TTL |
Auto-refresh-on-search interval in seconds (disabled when unset) | - |
SEARCH_REFRESH_TIMEOUT_MS |
Max time search waits for refresh before using stale index | 2000 |
INDEX_JOB_RETENTION_SECONDS |
How long completed/failed index jobs remain queryable | 3600 |
EMBEDDING_BATCH_SIZE |
Batch size for embedding generation | 50 |
DEBUG |
Enable debug logging | false |
search-notes does not force refresh on every request.INDEX_TTL is unset, auto-refresh is disabled and search uses the current index.INDEX_TTL is set, refresh runs only after TTL expiration.SEARCH_REFRESH_TIMEOUT_MS, search falls back to stale index results instead of timing out.To reconfigure:
apple-notes-mcp setup
# or from source:
bun run setup
Local (default): Uses HuggingFace Transformers with Xenova/multilingual-e5-small. Free, runs locally, ~200MB download.
OpenRouter: Uses cloud API. Fast, requires no local resources, needs API key from openrouter.ai.
See docs/models.md for model comparison.
search-notesHybrid vector + fulltext search.
query: "meeting notes from last week"
folder: "Work" # optional, filter by folder
limit: 10 # default: 20
mode: "hybrid" # hybrid, keyword, or semantic
include_content: false # include full content vs preview
list-notesList notes with sorting and filtering. Without parameters, shows index statistics.
sort_by: "modified" # created, modified, or title (default: modified)
order: "desc" # asc or desc (default: desc)
limit: 10 # max notes to return (1-100)
folder: "Work" # filter by folder (case-insensitive)
When folder is provided, the server fetches only matching folders from Apple Notes. This keeps folder-scoped requests fast even when your vault has hundreds of notes.
Examples:
{ sort_by: "created", order: "desc", limit: 5 }{ sort_by: "modified", limit: 10 }{ sort_by: "title", order: "asc", folder: "Projects" }list-foldersList all Apple Notes folders.
get-noteGet note content by title.
title: "My Note" # or "Work/My Note" for disambiguation
include_html: false # include raw HTML (default: false)
get-tablesExtract structured table data from a note.
title: "My Note"
Returns:
{
"tableCount": 2,
"tables": [{
"index": 0,
"rows": [["Header1", "Header2"], ["Val1", "Val2"]],
"formatting": [[{"bold": true}, {"bold": true}], ...]
}]
}
index-notesIndex notes for semantic search.
mode: "incremental" # incremental (default) or full
force: false # force reindex even if TTL hasn't expired
background: false # optional; defaults to false (synchronous mode)
Use mode: "full" to create the chunk index for better long-note search. First full index takes longer as it generates chunks, but subsequent searches run fast.
For large vaults, prefer background indexing:
start-index-jobmode: "full" # full or incremental
Returns a job snapshot with id, status, and progress.
Progress updates in smaller steps across fetch, embed, and persist phases.
get-index-jobjob_id: "<job-id>"
Poll until status is completed, failed, or cancelled.
You may see cancelling as a transitional status.
list-index-jobslimit: 10 # optional, 1-50
cancel-index-jobjob_id: "<job-id>"
Requests best-effort cancellation for a running job. Cancellation is cooperative:
cancelled.reindex-noteRe-index a single note after manual edits.
title: "My Note"
create-noteCreate a note in Apple Notes.
title: "New Note"
content: "# Heading\n\nMarkdown content..."
folder: "Work" # optional, defaults to Notes
After create, update, delete, or move, the server auto-syncs vector and chunk indexes in best-effort mode.
If sync partly fails, the tool response includes an index sync warning. Run reindex-note or index-notes.
update-noteUpdate an existing note.
title: "My Note"
content: "Updated markdown content..."
reindex: true # re-embed after update (default: true)
delete-noteDelete a note (requires confirmation).
title: "My Note"
confirm: true # must be true to delete
move-noteMove a note to another folder.
title: "My Note"
folder: "Archive"
batch-deleteDelete multiple notes at once.
titles: ["Note 1", "Note 2"] # OR folder: "Old Project"
confirm: true # required for safety
batch-moveMove multiple notes to a target folder.
titles: ["Note 1", "Note 2"] # OR sourceFolder: "Old"
targetFolder: "Archive" # required
purge-indexClear all indexed data. Use when switching embedding models or to fix corrupted index.
confirm: true # required for safety
After purging, run index-notes to rebuild.
list-tagsList all tags with occurrence counts.
search-by-tagFind notes with a specific tag.
tag: "project"
folder: "Work" # optional
limit: 20 # default: 20
related-notesFind notes related to a source note.
title: "My Note"
types: ["tag", "link", "similar"] # default: all
limit: 10 # default: 10
export-graphExport knowledge graph for visualization.
format: "json" # json or graphml
folder: "Work" # optional filter
Supported Formats:
json - For custom visualization (D3.js, web apps)graphml - For professional tools (Gephi, yEd, Cytoscape)The setup wizard automatically adds apple-notes-mcp to Claude Code. Run apple-notes-mcp after installation.
Add to ~/.claude.json:
For npm installation:
{
"mcpServers": {
"apple-notes": {
"command": "apple-notes-mcp",
"args": [],
"env": {}
}
}
}
For source installation:
{
"mcpServers": {
"apple-notes": {
"command": "bun",
"args": ["run", "/path/to/apple-notes-mcp/src/index.ts"],
"env": {}
}
}
}
After setup, use natural language with Claude:
Use full path format Folder/Note Title when multiple notes share the same name.
Local embeddings download the model on first use (~200MB). Subsequent searches run fast.
Set READONLY_MODE=false in .env to enable write operations.
Run index-notes to update the search index. Use mode: full if incremental misses changes.
Can't get account "iCloud"This error comes from a different Apple Notes MCP implementation that uses tool search_notes and argument Keywords.
This project uses:
search-notesqueryIf your client calls search_notes with Keywords, point your MCP config to apple-notes-mcp and restart the client.
Ensure Apple Notes runs and contains notes. Grant automation permissions when prompted.
This usually means the indexing process ran out of memory. Try:
EMBEDDING_BATCH_SIZE=25 in .env to reduce memory usageindex-notes againSome notes may be skipped if they are:
The indexer will report which notes were skipped and continue with the rest.
# Type check
bun run check
# Run tests
bun run test
# Run with coverage
bun run test:coverage
# Run with debug logging
DEBUG=true bun run start
# Watch mode
bun run dev
PRs welcome! Please:
bun run check before submittingMIT
Добавь это в claude_desktop_config.json и перезапусти Claude Desktop.
{
"mcpServers": {
"disco-trooper-apple-notes-mcp": {
"command": "npx",
"args": []
}
}
}