Bear笔记MCP服务器

一个MCP服务器,让Claude Code能够通过SQLite和URL方案在macOS上读取、搜索并管理Bear笔记。

  • by danielv14
  • TypeScript
  • 本地部署
  • 更新于
在 GitHub 查看 danielv14/bear-notes-mcp-server

使用说明

Bear MCP Server

An MCP server that gives Claude Code access to Bear notes on macOS.

Architecture

Reads go straight to Bear's SQLite store, writes go through Bear's URL scheme:

Operation Method Why
Read (search, get, list) SQLite A search is one query, with no round-trip through Bear's UI
Write (create, append, prepend, trash, archive, rename-tag, delete-tag) URL scheme Bear owns the database, so writes go through its own API

Reads and writes have different guarantees, and it is worth knowing which is which before trusting a tool response. See Behaviour notes.

Requirements

  • macOS (Bear is macOS/iOS only)
  • Bear installed
  • Bun runtime

Installation

cd bear-notes-mpc-server
bun install

Claude Code configuration

Add the MCP server using the Claude Code CLI:

claude mcp add --transport stdio --scope user bear -- bun run /absolute/path/to/bear-mcp-server/src/server.ts

Note: Replace the path with the actual absolute path to your bear-mcp-server directory.

Scope options:

  • --scope user - Available in all Claude Code sessions (recommended)
  • --scope local - Only available in the current project directory
  • --scope project - Creates .mcp.json for team sharing via git

Check configured servers:

claude mcp list

View server details:

claude mcp get bear

Starting Claude with Bear

Once the MCP server is configured, start a new Claude session:

claude

Claude starts the Bear MCP server itself, and the Bear tools show up in the session.

Removing the MCP server

The MCP server runs as a subprocess of Claude Code and stops when you exit Claude.

To permanently remove the server:

claude mcp remove bear

Available tools

Tool Description
bear_create_note Create a new note with optional tags
bear_search Search notes by text or tag (paged)
bear_get_note Get full content of a note by ID, including its trashed/archived status
bear_append Append text to an existing note
bear_prepend Prepend text to the beginning of an existing note
bear_replace_content Replace the entire content of an existing note
bear_list_tags List all tags with note counts
bear_list_by_tag List notes with a specific tag (paged)
bear_rename_tag Rename an existing tag
bear_delete_tag Delete an existing tag from all notes
bear_trash_note Move a note to trash
bear_archive_note Archive a note
bear_list_archived List archived notes (paged)

There is no un-archive tool. Bear's x-callback-url API has no unarchive action, so this server cannot do it. Un-archive in Bear's own UI.

Example usage in Claude

Once the server is running, you can ask Claude things like:

  • "Search my Bear notes for 'project ideas'"
  • "List all my tags in Bear"
  • "Create a new note titled 'Meeting Notes' with today's date"
  • "Show me all notes tagged with 'work'"
  • "Append this summary to my 'Daily Log' note"
  • "Rename my 'old-project' tag to 'archived-project'"
  • "Delete the 'temp' tag from all notes"

Database location

The server tries these two locations in order and uses the first that exists:

  • iCloud sync: ~/Library/Group Containers/9K33E3U3T4.net.shinyfrog.bear/Application Data/database.sqlite
  • Local storage: ~/Library/Containers/net.shinyfrog.bear/Data/Documents/Application Data/database.sqlite

Behaviour notes

Writes are sent, not confirmed. Every write goes out as a bear:// URL opened with open -g, which exits as soon as macOS finds a handler for the scheme. Bear reports nothing back, so the server cannot tell an applied change from one Bear ignored (an unknown note id, for instance). Write tools therefore say what was sent, never that it was applied. Two failures the server does see come back as error results: Bear not installed, and a payload too large to send. If a write matters, verify it in Bear, or read the note back with bear_get_note.

The server refuses runaway payloads rather than truncating them. It will not send a bear:// URL longer than 500000 characters (measured after percent-encoding, which inflates non-ASCII text up to 3x), and the tool returns an error naming the size. The number comes from the only ceiling that can be measured: the argv limit open inherits, ARG_MAX = 1048576. It sits roughly 10x above the largest note observed in a real Bear library. Bear's own limit, if it has one, is undocumented. Without the guard an oversized write would be silently truncated, which under bear_replace_content means overwriting a note with a partial copy. Split very large content across several bear_append calls.

Timestamps are ISO-8601 UTC. createdAt and modifiedAt come back as 2026-07-27T06:09:00Z. The trailing Z is deliberate: an unmarked 2026-07-27 06:09:00 reads as local time and is off by the UTC offset, which shifts the date for notes written in the first hours of the day.

Search is case-insensitive for all characters, and literal. MÖTE finds möte, and 50% finds the literal text 50% rather than acting as a wildcard. Case folding happens in JS because Bun's SQLite only folds ASCII. The same applies to tag names, so bear_list_tags groups Work and work into one entry rather than reporting two with split counts.

Tags may be written with or without #. work, #work and Bear's own multiword form #my tag# all name the same tag, on both the read and the write path.

List results are paged. bear_search, bear_list_by_tag and bear_list_archived return { notes, count, limit, offset, hasMore }. count is the size of that page, never a total; hasMore says whether further notes matched. Pass limit and offset to page through the rest.

Testing

bun run typecheck
bun test   # in-memory SQLite fixture, no Bear needed

Both run in CI on every push to master and every pull request, along with bun run build. CI runs on Linux, which is fine because nothing in the unit suite needs macOS or Bear, and a green run says nothing about whether Bear accepts what this server sends it.

bun test proves the code agrees with its fixture, not with Bear. For changes to the read queries, the write path, the tool surface or the note rendering, also walk docs/TEST-PROTOCOL.md, or run it as the repo-local skill /bear-protocol in Claude Code: it creates, reads, modifies, tags, archives and trashes one real test note through the connected MCP server, and verifies every write with a raw read-only query against Bear's database rather than through this repo's own read path.

Logs

The server writes logs to stderr, and Claude Code captures them. It reads no environment variables and has no log-level setting.

Permissions

On first run, macOS may ask for Automation permissions to allow the server to open Bear URLs.

Troubleshooting

"Bear database not found"

  • Make sure Bear is installed and has been opened at least once

Notes not appearing after create

  • Bear may take a moment to sync. The note is created via URL scheme and may not immediately appear in SQLite queries.

Permission denied on database

  • The database is opened in read-only mode. If you still get errors, check that Bear isn't currently writing to the database.

MCP server not connecting

  • Verify the path in your config is correct
  • Run claude mcp list to check if the server is configured
  • Ensure Bun is installed and available in your PATH

"Unsupported Bear database schema"

  • Bear's note/tag join table is named after Core Data's generated entity ids, and those can change between Bear versions. The server discovers them from Z_PRIMARYKEY and fails with this message when the tables it needs are not where the discovery says they should be. Please open an issue with the Bear version, since it means the schema moved.