trackmcp
Back to directory
disco-trooper

apple-notes-mcp

View on GitHub

MCP server for Apple Notes. Semantic search, full CRUD, works with MCP clients.

7 stars TypeScriptOthers Updated Jul 12, 2026
apple-notesmacosmcpragsemantic-search

Documentation

apple-notes-mcp

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.

Features

  • Chunk-Based Search - Long notes split into chunks for accurate matching
  • Query Caching - 60x faster repeated searches
  • Knowledge Graph - Tags, links, and related notes discovery
  • Hybrid Search - Vector + keyword search with Reciprocal Rank Fusion
  • Semantic Search - Find notes by meaning, not keywords
  • Full CRUD - Create, read, update, delete, and move notes
  • Incremental Indexing - Re-embed only changed notes
  • Background Index Jobs - Async full/incremental indexing with progress polling
  • Dual Embedding - Local HuggingFace or OpenRouter API

What's New in 1.8.1

  • Faster `list-notes` folder filtering - `list-notes` now queries only the requested folder instead of scanning all notes first
  • Duplicate folder name correctness - Folder filtering now aggregates matching folders across accounts
  • Large vault performance - Folder-scoped listing is significantly faster on larger note libraries

Installation

bash
npm install -g @disco_trooper/apple-notes-mcp
apple-notes-mcp

The setup wizard guides you through:

1. Choosing your embedding provider (local or OpenRouter)

2. Configuring API keys if needed

3. Setting up Claude Code integration

4. Indexing your notes

From source

bash
git clone https://github.com/disco-trooper/apple-notes-mcp.git
cd apple-notes-mcp
bun install
bun run start

Requirements

  • macOS (uses Apple Notes via JXA)
  • Bun runtime
  • Apple Notes app with notes

Quick Start

Run the command after installation:

bash
apple-notes-mcp

The setup wizard starts automatically on first run. Restart Claude Code after setup to use the MCP tools.

Configuration

Configuration stored in `~/.apple-notes-mcp/.env`:

VariableDescriptionDefault
`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 Auto-Refresh Policy

  • `search-notes` does not force refresh on every request.
  • If `INDEX_TTL` is unset, auto-refresh is disabled and search uses the current index.
  • If `INDEX_TTL` is set, refresh runs only after TTL expiration.
  • If refresh fails or takes longer than `SEARCH_REFRESH_TIMEOUT_MS`, search falls back to stale index results instead of timing out.

To reconfigure:

bash
apple-notes-mcp setup
# or from source:
bun run setup

Embedding Providers

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.

Tools

Search & Discovery

`search-notes`

Hybrid vector + fulltext search.

code
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-notes`

List notes with sorting and filtering. Without parameters, shows index statistics.

code
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:

  • Get 5 newest notes: `{ sort_by: "created", order: "desc", limit: 5 }`
  • Recently modified: `{ sort_by: "modified", limit: 10 }`
  • Alphabetical in folder: `{ sort_by: "title", order: "asc", folder: "Projects" }`

`list-folders`

List all Apple Notes folders.

`get-note`

Get note content by title.

code
title: "My Note"          # or "Work/My Note" for disambiguation
include_html: false       # include raw HTML (default: false)

`get-tables`

Extract structured table data from a note.

code
title: "My Note"

Returns:

json
{
  "tableCount": 2,
  "tables": [{
    "index": 0,
    "rows": [["Header1", "Header2"], ["Val1", "Val2"]],
    "formatting": [[{"bold": true}, {"bold": true}], ...]
  }]
}

Indexing

`index-notes`

Index notes for semantic search.

code
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-job`

code
mode: "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-job`

code
job_id: ""

Poll until status is `completed`, `failed`, or `cancelled`.

You may see `cancelling` as a transitional status.

`list-index-jobs`

code
limit: 10                  # optional, 1-50

`cancel-index-job`

code
job_id: ""

Requests best-effort cancellation for a running job. Cancellation is cooperative:

  • A long-running step must reach a cancellation checkpoint.
  • Partial work may remain.
  • Start a new job after the current one reaches `cancelled`.

`reindex-note`

Re-index a single note after manual edits.

code
title: "My Note"

CRUD Operations

`create-note`

Create a note in Apple Notes.

code
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-note`

Update an existing note.

code
title: "My Note"
content: "Updated markdown content..."
reindex: true             # re-embed after update (default: true)

`delete-note`

Delete a note (requires confirmation).

code
title: "My Note"
confirm: true             # must be true to delete

`move-note`

Move a note to another folder.

code
title: "My Note"
folder: "Archive"

`batch-delete`

Delete multiple notes at once.

code
titles: ["Note 1", "Note 2"]  # OR folder: "Old Project"
confirm: true                 # required for safety

`batch-move`

Move multiple notes to a target folder.

code
titles: ["Note 1", "Note 2"]  # OR sourceFolder: "Old"
targetFolder: "Archive"       # required

Index Management

`purge-index`

Clear all indexed data. Use when switching embedding models or to fix corrupted index.

code
confirm: true   # required for safety

After purging, run `index-notes` to rebuild.

Knowledge Graph

`list-tags`

List all tags with occurrence counts.

`search-by-tag`

Find notes with a specific tag.

code
tag: "project"
folder: "Work"    # optional
limit: 20         # default: 20

Find notes related to a source note.

code
title: "My Note"
types: ["tag", "link", "similar"]  # default: all
limit: 10                          # default: 10

`export-graph`

Export knowledge graph for visualization.

code
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)

Claude Code Setup

The setup wizard automatically adds apple-notes-mcp to Claude Code. Run `apple-notes-mcp` after installation.

Manual

Add to `~/.claude.json`:

For npm installation:

json
{
  "mcpServers": {
    "apple-notes": {
      "command": "apple-notes-mcp",
      "args": [],
      "env": {}
    }
  }
}

For source installation:

json
{
  "mcpServers": {
    "apple-notes": {
      "command": "bun",
      "args": ["run", "/path/to/apple-notes-mcp/src/index.ts"],
      "env": {}
    }
  }
}

Usage Examples

After setup, use natural language with Claude:

  • "Search my notes for project ideas"
  • "Create a note called 'Meeting Notes' in the Work folder"
  • "What's in my note about vacation plans?"
  • "Move the 'Old Project' note to Archive"
  • "Index my notes" (after adding notes in Apple Notes)

Troubleshooting

"Note not found"

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.

"READONLY_MODE is enabled"

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.

"iCloud account not available" / `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:

  • tool: `search-notes`
  • argument: `query`

If your client calls `search_notes` with `Keywords`, point your MCP config to `apple-notes-mcp` and restart the client.

JXA errors

Ensure Apple Notes runs and contains notes. Grant automation permissions when prompted.

"JSON Parse error: Unexpected identifier undefined"

This usually means the indexing process ran out of memory. Try:

1. Close other applications to free memory

2. Set `EMBEDDING_BATCH_SIZE=25` in `.env` to reduce memory usage

3. Restart Apple Notes app

4. Run `index-notes` again

Skipped notes during indexing

Some notes may be skipped if they are:

  • Locked - Unlock them in Apple Notes if you want them indexed
  • Syncing - Wait for iCloud sync to complete, then reindex
  • Corrupted - Try copying content to a new note and deleting the old one

The indexer will report which notes were skipped and continue with the rest.

Development

bash
# 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

Contributing

PRs welcome! Please:

  • Run `bun run check` before submitting
  • Add tests for new functionality
  • Update documentation as needed

License

MIT

Frequently asked questions

What is apple-notes-mcp?

apple-notes-mcp is MCP server for Apple Notes. Semantic search, full CRUD, works with MCP clients.

How do I install apple-notes-mcp?

Open the GitHub repository and follow its README. Most MCP servers are added to your client's MCP config, then called by your agent.

Is apple-notes-mcp open source?

Yes — it is hosted on GitHub at https://github.com/disco-trooper/apple-notes-mcp and has 7 stars.

Related MCP tools

Run your own MCP server? See who uses it and what to fix.

Measure it with TrackMCP