bearnotes-mcp
# bearnotes-mcp
A tiny local [MCP](https://modelcontextprotocol.io) server that lets any local
MCP client on macOS — [Claude Code](https://claude.com/claude-code), Claude
Desktop, Cursor, VS Code — read and edit your [Bear](https://bear.app) notes:
search, read, create, append, and overwrite (e.g. tick a checkbox).
**No Bear API token is needed.** Reads use Bear's local database (opened
read-only); writes use Bear's `bear://x-callback-url` scheme. Neither requires a
token, and nothing here ever touches the network.
## Requirements
- **macOS** with **Bear installed and opened at least once** (the database only
exists after Bear has run).
- **[uv](https://docs.astral.sh/uv/)** — install with `curl -LsSf https://astral.sh/uv/install.sh | sh` (or `brew install uv`).
No Python setup, no token.
## Install — Claude Code
**1. Warm the cache** (first run downloads ~30 packages — may take a minute; ends with `selfcheck ok`):
```sh
uvx bearnotes-mcp --selfcheck
```
**2. Register** — one command, at user scope so it's available in every project:
```sh
claude mcp add bear -s user -- uvx bearnotes-mcp
```
**3. Verify:**
```sh
claude mcp list # → bear: ✔ Connected
```
> If the very first connect times out, just **retry** (the cache is warm after
> one attempt), or start Claude once with `MCP_TIMEOUT=60000 claude`.
## Install — Claude Desktop, Cursor, VS Code
Add an `mcpServers` entry. **Use the full path to `uvx`** — GUI apps don't see
your shell `PATH` (`which uvx`, e.g. `/opt/homebrew/bin/uvx`):
```json
{
"mcpServers": {
"bear": {
"command": "/opt/homebrew/bin/uvx",
"args": ["bearnotes-mcp"]
}
}
}
```
- **Claude Desktop** — Settings → Developer → Edit Config (creates
`~/Library/Application Support/Claude/claude_desktop_config.json`); paste, then
**fully quit and restart**. Logs: `~/Library/Logs/Claude/mcp-server-bear.log`.
- **Cursor** — same block in `~/.cursor/mcp.json`.
- **VS Code (Copilot)** — `.vscode/mcp.json`, but the top-level key is `servers` (not `mcpServers`).
- **Windsurf / Cline / Zed / LM Studio** — same stdio pattern; check their docs for the exact file.
**Cannot work:** claude.ai in the browser, mobile apps, remote/hosted connectors,
and non-Mac machines — they can't spawn a local process, and Bear lives only on
your Mac.
<details>
<summary>Alternatives: bleeding edge, or run from a clone</summary>
Latest `main` without waiting for a release (builds from GitHub each install):
```sh
claude mcp add bear -s user -- uvx --from git+https://github.com/samcrudge/bearnotes-mcp bearnotes-mcp
```
Clone it to read/hack the code first:
```sh
git clone https://github.com/samcrudge/bearnotes-mcp
claude mcp add bear -s user -- uv --directory /absolute/path/to/bearnotes-mcp run bearnotes-mcp
```
To point at a non-default Bear database, add `-e BEAR_DB=/path/to/database.sqlite`
to the `claude mcp add` command.
</details>
## How it works
- **Reads** — Bear's local SQLite DB, opened **read-only** (`mode=ro`).
- **Writes** — Bear's [`x-callback-url`](https://bear.app/faq/x-callback-url-scheme-documentation/)
scheme (`create`, `add-text` in `append` / `replace_all` mode).
The DB is never written directly (that corrupts Bear's sync). Before any
full-body overwrite, the note's current text is snapshotted to
`~/.bear-mcp-backups/` as a timestamped `.md` file.
## Tools
| Tool | What it does |
|------|--------------|
| `search_notes(query="", tag="", limit=20)` | Search non-trashed notes, optional tag filter (incl. subtags); returns id, title, tags, pinned, modified |
| `read_note(id)` | Full note + tags, pinned, and open/done checkbox counts |
| `list_tags()` | Every tag with its live-note count |
| `get_backlinks(id)` | Notes linking to this one, and notes it links to (Bear `[[wiki-link]]` graph) |
| `create_note(title, text="", tags=[])` | Create a new note |
| `append_note(id, text)` | Append to a note |
| `prepend_note(id, text)` | Prepend to a note (after the title line) |
| `replace_note(id, text)` | Overwrite a note's entire text; backs up first |
| `toggle_task(id, match, done=None)` | Check/uncheck one checkbox line by substring (`done` None=flip); errors if ambiguous |
| `open_note(id)` | Open and focus a note in the Bear app |
**Resources** (read-only, `@`-mentionable): `bear://notes` (index of recent notes) and `bear://note/{id}` (a note's full text).
## What this can access
Once connected, the client can **read every non-trashed note** (encrypted notes
are refused) and **create, append to, or overwrite** notes. Everything runs
**locally with no network calls**; the database is opened **strictly read-only**;
and before any full-body overwrite the current text is backed up to
`~/.bear-mcp-backups/`. Tools carry MCP annotations (reads marked read-only,
`replace_note` marked destructive) so clients can surface the right warnings.
## Troubleshooting
- **First connect times out** — retry (cache is warm now), or `MCP_TIMEOUT=60000 claude`.
- **Desktop fails instantly** — `"command"` must be the *full path* to `uvx` (`which uvx`).
- **No notes found** — open Bear at least once so its database exists.
## License
Apache-2.0. See [LICENSE](LICENSE).
TDQS
Scored across 10 tools
Each tool targets a distinct operation: reading, searching, listing tags, backlinks, creating, appending, prepending, replacing, toggling tasks, and opening. No two tools have overlapping purposes.
All tool names follow a consistent verb_noun snake_case pattern (e.g., read_note, search_notes, create_note), making them predictable and easy for an agent to infer.
With 10 tools covering core note operations, tagging, backlinks, and task management, the count is well-scoped for a Bear notes server—neither sparse nor overwhelming.
Covers essential CRUD-like operations (read, create, update via replace, append, prepend), search, tags, backlinks, and task toggling. Minor missing features like explicit delete/trash or tag management are gaps but workable.