basic-memory
Basic Memory is an MCP server for a local-first Markdown knowledge base that both humans and AI can read, write, search, and navigate.
Create, read, edit, move, overwrite-guarded write, and delete notes or directories.
Search notes with full-text, title, permalink, semantic/vector, and hybrid search, including metadata/tag/date filters.
Browse filesystem-like views with
ls,find,grep,cat,tail, and directory listing.Follow the knowledge graph with
bm_contextto gather a note, its observations, and related notes up to several hops.Manage projects and cloud workspaces: list, create, set defaults, route cloud/local, inspect recent activity.
Validate, infer, and diff Picoschema note schemas.
Use POSIX-style/manual helpers and diagnostics for troubleshooting.
Provide OpenAI/ChatGPT connector adapters (
search,fetch) and cloud-aware project routing.
Uses Markdown as the primary file format for storing knowledge, with specific patterns for semantic structure.
Works seamlessly with Obsidian for knowledge management, visualization, and editing of the Basic Memory knowledge base files.
Provides import capability for ChatGPT conversation history into the Basic Memory knowledge base.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@basic-memorycreate a note about coffee brewing methods I've been exploring"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Skip the install — try Basic Memory in the cloud
Claude, Codex, or Cursor connected in 30 seconds. No Python, no JSON, no
terminal. $15.00/mo locked in for life (12.50/mo yearly pricing). 7-day free
trial — cancel any time before day 7 if it's not for you. Beta pricing —
sign up now and your rate never goes up. OSS users: code BMFOSS takes
another 20% off for 3 months.
Basic Memory Teams is now available!
Give your team a single, shared cloud workspace. Knowledge isn't confined to one person — anything a teammate writes is immediately available to everyone else and to their AI assistants. Edit a note together in real time, hand work off between humans and agents, and build one connected knowledge base instead of scattered copies. Same pricing - start with one user and add more as needed.
Basic Memory
Your AI never forgets again.
Pick up right where you left off — in Claude, Codex, Cursor, ChatGPT, or anything that speaks MCP. Your knowledge lives as Markdown files that both you and your AI can read, write, and search.
Local-first. Plain text on your disk. Forever.
Two-way. AI and humans write to the same files; sync keeps them in step.
A real knowledge graph. Observations and wikilinks compound into context.
Semantic search. Find notes by meaning, not just keywords, with optional cross-encoder reranking for higher-quality vector and hybrid results.
MCP-native. Works with every major AI client and IDE.
Progressive tool discovery. Every tool is tagged with behavior hints (read-only, destructive, idempotent) so agents pick the right tool on demand — no wasted context trying things to see what they do.
Cloud, optional. Sync across devices when you want — never required.
Related MCP server: memora
Get started
Pick the path that fits you. Both run the same product on the same Markdown.
30 seconds. Sign up, connect your AI client, done.
Works in any browser
Mobile, web, desktop
Cross-device sync built in
We handle hosting, backups, snapshots
$15.00/mo locked for life · 7-day free trial · cancel any time
2 minutes. Install, configure your AI client, run.
Free forever (AGPL-3.0)
All data on your disk
Air-gapped friendly
Requires Python via
uv
uv tool install basic-memory --prerelease=allow--prerelease=allow is required: Basic Memory 0.23 depends on a FastMCP 4
pre-release, and uv only accepts pre-releases of transitive dependencies when
told to — without the flag it silently installs an older release. The same flag
goes on every uvx / uv tool upgrade command below.
For Postgres deployments that store semantic vectors in Milvus, install the first-party optional extra instead:
uv tool install "basic-memory[milvus]" --prerelease=allowWhat people are saying
Basic Memory changed my whole relationship with LLMs. I switched from GPT and Gemini to exclusively Claude and Claude Code because of this integration and am completely revamping all our company's processes around a Basic Memory workflow.
— Alex, TrainerDay
Basic Memory is the missing 'wow' factor in AI chatbots. Now I can't imagine Claude or Claude Code without it.
— Caleb, Caleb Picker Consulting
I don't code without Basic Memory anymore. It's such a time saver to be able to refer to projects I don't currently have active and keep a running log of all my learnings and ProTips.
— @groksrc, Developer
More on basicmemory.com.
Basic Memory Cloud
The hosted version of Basic Memory. Same product, same Markdown files, same MCP tools — we just host the database, run the sync, and put it on your phone.
What you get
Every device, same brain. Your knowledge graph on web, mobile, and desktop. No copy-paste between machines.
Connect any MCP client. Claude Desktop, Claude Code, Codex, Cursor, ChatGPT (Custom GPTs), VS Code — one-click connect from the web app.
Bidirectional sync to local. Edit on your phone, see it in Obsidian on your laptop. rclone-powered with conflict resolution.
Snapshots and backups. Point-in-time restore. Browse history. Never lose a note.
No lock-in. Your notes are plain Markdown. Export to local Markdown any time — same files, same format, same wikilinks. Cancel anytime, your data stays yours.
Built on WorkOS AuthKit, Neon Postgres, and Tigris S3.
Pricing
$15.00/mo, locked in for the life of your subscription (regular price $19). Sign up during beta and the rate never goes up — as long as you stay subscribed, you keep the price. One plan, no tiers, no surprise upgrades. Unlimited notes, unlimited projects, every feature.
7-day free trial. Cancel any time before day 7 if it's not for you.
Cancel anytime after that too — export your notes whenever you want.
OSS users: code
BMFOSSfor another 20% off for 3 months (~$11.40/mo).
Cloud vs. local
Cloud | Local | |
Setup time | 30 seconds | 2 minutes (requires Python) |
Cost | $15.00/mo, locked for life (7-day trial) | Free |
Storage | We host (Tigris S3) | Your disk |
Cross-device sync | Built in | Manual (Git, Syncthing, etc.) |
Mobile access | Yes (web + app) | No |
Air-gapped | No | Yes |
Your data stays yours | Yes — export anytime | Yes — already there |
Source code | AGPL-3.0 | AGPL-3.0 |
Snapshots & backups | Built in | Roll your own |
Both paths use the same OSS engine and the same Markdown files. There's no lock-in either way — flip between them when your needs change.
Works with the tools you already use
Client | Transport | Notes |
Cloud web app | https | Sign in at basicmemory.com — no install |
stdio/https | macOS / Windows / Linux | |
stdio/https |
| |
stdio/https | OpenAI's coding agent | |
stdio/https |
| |
stdio/https | Native MCP support | |
https | Custom GPT actions ( | |
— | Reads/writes the same Markdown directly | |
Anything MCP | stdio/https | If it speaks MCP, it works |
Official agent packages
This repository is also the canonical home for Basic Memory's host-native agent packages. The core Python package, Claude Code plugin, shared skills, Hermes plugin, and OpenClaw plugin all ship from the same source tree.
Maintainers can verify the whole consolidated surface from the repo root:
just package-checkPackage-local justfiles are also available when working inside one host:
just package-check-claude-code
just package-check-skills
just package-check-hermes
just package-check-openclawClaude Code plugin
The Claude Code plugin is the bridge between Claude's working memory and Basic
Memory — session-start briefings, pre-compaction checkpoints, an opt-in capture
output style, and /basic-memory:bm-setup · :remember · :share · :status.
Connect the Basic Memory MCP server first — see Connect your AI client. The plugin's hooks and skills call it, so it's a hard prerequisite. Then install the plugin:
bm install claude-codeThat registers the marketplace and installs the plugin through Claude Code. Add
--scope project to declare both in the repository's settings for a team, or
--dry-run to see the underlying claude plugin commands without running them.
Source: plugins/claude-code.
Shared skills
Framework-agnostic SKILL.md files live in skills/. If your
Skills CLI supports repository subdirectory sources:
npx skills add basicmachines-co/basic-memory/skills -gFor Claude and ChatGPT, upload basic-memory.zip or basic-memory-chatgpt.zip
from the skills-latest
release; see skills/README.md.
If your installed Skills CLI cannot load that source, update the CLI or copy
the memory-* directories from skills/ into your agent's skills directory.
Hermes
Hermes keeps its native plugin shape under integrations/hermes:
hermes plugins install basicmachines-co/basic-memory/integrations/hermesHermes does not install a plugin's Python dependencies, so also add the mcp
package to the Hermes venv — see the plugin README
for that step and the supported Hermes releases.
OpenClaw
OpenClaw stays package-native and publishes from
integrations/openclaw:
openclaw plugins install @basicmemory/openclaw-basic-memoryPick up where you left off
https://github.com/user-attachments/assets/a55d8238-8dd0-454a-be4c-8860dbbd0ddc
Connect your AI client
If you went the Cloud route, the web app walks you through client connect. The snippets below are for local installs.
Claude Desktop
Edit ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"basic-memory": {
"command": "uvx",
"args": ["--prerelease=allow", "basic-memory", "mcp"]
}
}
}Restart Claude Desktop. Notes live in ~/basic-memory by default.
Claude Code
claude mcp add basic-memory -- uvx --prerelease=allow basic-memory mcpFor the full memory bridge — session briefings, pre-compaction checkpoints, and
the /basic-memory:* commands — also install the Claude Code
plugin on top of this.
Codex CLI
Add to ~/.codex/config.toml:
[mcp_servers.basic-memory]
command = "uvx"
args = ["--prerelease=allow", "basic-memory", "mcp"]Codex can keep its default MCP approval behavior, or you can pre-approve eligible Basic Memory tools by adding this server-scoped setting to the same table:
[mcp_servers.basic-memory]
command = "uvx"
args = ["--prerelease=allow", "basic-memory", "mcp"]
default_tools_approval_mode = "approve"This does not disable Codex approvals globally or expand which Basic Memory projects the server can access. Codex still requires approval for tools that advertise a destructive annotation, including Basic Memory's writes, edits, and deletes. If you installed the Basic Memory Codex plugin, use its plugin-scoped configuration instead.
Cursor
Add to .cursor/mcp.json (project) or ~/.cursor/mcp.json (global):
{
"mcpServers": {
"basic-memory": {
"command": "uvx",
"args": ["--prerelease=allow", "basic-memory", "mcp"]
}
}
}VS Code
Add to your User Settings (JSON):
{
"mcp": {
"servers": {
"basic-memory": {
"command": "uvx",
"args": ["--prerelease=allow", "basic-memory", "mcp"]
}
}
}
}ChatGPT
Basic Memory exposes OpenAI-compatible search and fetch tools for Custom
GPT actions. See the ChatGPT integration
guide.
Obsidian
No setup. Point Obsidian at ~/basic-memory (or your project folder) and the
same wikilinks, frontmatter, and Markdown your AI writes appear in your graph
view. Edit either side — sync handles the rest.
Try a prompt:
"Create a note about our project architecture decisions."
"Find information about JWT auth in my notes."
"What have I been working on this week?"What's New
Automatic updates. Basic Memory keeps itself up to date for
uv tooland Homebrew installs;bm updatetriggers a manual check.Semantic vector search. Find notes by meaning, not just keywords. Hybrid full-text + vector ranking with FastEmbed embeddings, on SQLite or Postgres.
Optional search reranking. Rescore the strongest vector and hybrid candidates with a local FastEmbed cross-encoder or a LiteLLM-backed provider.
Schema system. Infer, validate, and diff the structure of your knowledge base with
bm_schema(command="infer"),bm_schema(command="validate"), andbm_schema(command="diff").Per-project cloud routing. Route individual projects through the cloud while others stay local, via API key (
bm project set-cloud).Explicit note changes.
bm_editupdates existing notes;bm_writecreates notes and guards against accidental overwrites.Richer search results. Matched chunk text is included so the LLM gets context, not just hits.
FastMCP 3.0 + tool annotations. Every tool ships with MCP behavior hints (
readOnlyHint,destructiveHint,idempotentHint,openWorldHint) so agents can discover capabilities progressively at runtime instead of guessing or burning tokens.CLI overhaul.
--jsonoutput for scripting, workspace-aware commands, and an htop-inspired project dashboard.
Full CHANGELOG for v0.18 → v0.20.
Optional cross-encoder reranking
Reranking adds a second relevance pass after vector or hybrid retrieval. It is disabled by default because it adds inference latency and, for the local provider, a first-run model download. Text, title, and permalink searches keep their existing ranking.
Enable the default local FastEmbed reranker:
export BASIC_MEMORY_RERANKER_ENABLED=trueThe default model is jinaai/jina-reranker-v1-tiny-en. To use a hosted
reranker through LiteLLM instead, first install the optional LiteLLM
SDK, then configure it:
export BASIC_MEMORY_RERANKER_ENABLED=true
export BASIC_MEMORY_RERANKER_PROVIDER=litellm
export BASIC_MEMORY_RERANKER_MODEL=cohere/rerank-v3.5
export COHERE_API_KEY=...The feature fails fast on invalid configuration and does not silently fall back to retrieval order when an enabled provider fails. See the semantic search guide for provider setup, all settings, tuning, pagination, and failure behavior.
Why Basic Memory
Most LLM conversations are ephemeral. You ask a question, get an answer, then everything is forgotten. Workarounds have limits:
Chat history captures conversations but isn't structured knowledge.
RAG lets the LLM query your documents but not write back to them.
Vector DBs need complex infra and usually live in someone else's cloud.
Knowledge graphs need specialized tooling to maintain.
Basic Memory takes a simpler path: structured Markdown files that humans and LLMs both read and write.
All knowledge stays in plain files you control.
Both sides read and write to the same files.
Familiar Markdown with semantic patterns — no new format to learn.
A traversable graph the LLM can follow link by link.
Works with the editors you already use (Obsidian, VS Code, anything).
Just files plus a local SQLite index. No servers required.
How it works
You're chatting normally about coffee:
I've been experimenting with brewing methods. Pour over gives more clarity than French press, water at 205°F seems best, and freshly ground beans make a huge difference.
Ask the LLM to capture it:
"Make a note on coffee brewing methods."
A Markdown file appears in your project directory in real time:
---
title: Coffee Brewing Methods
permalink: coffee-brewing-methods
tags: [coffee, brewing]
---
# Coffee Brewing Methods
## Observations
- [method] Pour over highlights subtle flavors over body
- [technique] Water at 205°F (96°C) extracts optimal compounds
- [principle] Freshly ground beans preserve aromatics
## Relations
- relates_to [[Coffee Bean Origins]]
- requires [[Proper Grinding Technique]]
- affects [[Flavor Extraction]]Next session, the LLM picks up the thread. It follows the relations to surface what you already know about Ethiopian beans and burr grinders, and builds on it instead of starting over. You see the same files in Obsidian or your editor. Edit them by hand — the AI sees your changes too.
Real two-way flow: humans edit Markdown, LLMs read/write through MCP, sync keeps everything consistent, and the source of truth is always your files.
The Markdown format
Each file is an Entity. Entities have Observations (facts about them) and
Relations (links to other entities). That's the whole grammar.
Frontmatter
---
title: <Entity title>
type: note
permalink: <uri-slug>
tags: [optional, list]
---Observations
Facts about the entity. Categories in [brackets], tags with #, optional
context in parens.
- [method] Pour over highlights subtle flavors
- [tip] Grind medium-fine for V60 #brewing
- [fact] Lighter roasts contain more caffeine than dark
- [resource] James Hoffmann's V60 technique on YouTube
- [question] How does temperature affect compound extraction?Relations
Wiki-style links that form the graph. Single-token relation types, or quote multi-word ones.
- pairs_well_with [[Chocolate Desserts]]
- grown_in [[Ethiopia]]
- requires [[Burr Grinder]]
- "pairs well with" [[Dark Chocolate]]Bare - [[Target]] and prose - Worth checking out [[Target]] index as
links_to. Full reference in the
docs.
MCP tools
Basic Memory exposes these tools to any MCP client. Every tool is annotated with MCP behavior hints (read-only, destructive, idempotent, open-world) so agents can pick the right one without trial-and-error:
Content:
bm_write,bm_read,bm_edit,bm_move,bm_deleteSearch & discovery:
bm_search,bm_list,bm_findKnowledge graph:
bm_contextProjects:
bm_project(command="list" | "create" | "recent");bm_project_deleteis separate and requires server opt-in.Schema:
bm_schema(command="validate" | "infer" | "diff")Manual:
bm_manCloud connector adapters:
searchandfetchare registered by Cloud only. Local diagnostics usebm doctor.
Most tools default to text; bm_context defaults to JSON. Pass
output_format="json" for structured responses. Project-scoped tools accept a
name, workspace/project, or external UUID through project.
Use bm_man(page="bm-search(3)") for the installed contract, or see the
tool guide. CLI commands retain their shell names.
CLI essentials
# Projects
basic-memory project list
basic-memory project add research ~/research
basic-memory project set-cloud research # route through cloud
basic-memory project set-local research # revert
# Config
basic-memory config list # all settings, effective values, env overrides
basic-memory config set cli_output_style plain # validated through the config model
basic-memory config unset cli_output_style # revert to default
# Health & maintenance
basic-memory status
basic-memory doctor # report project problems and the commands that fix them
basic-memory tool edit ... # CLI access to MCP tools
basic-memory update # check for and install updates
# Imports
basic-memory import claude conversations
basic-memory import chatgpt
basic-memory import memory-jsonRouting flags (--local / --cloud) force a target when you're in mixed
mode. Full CLI reference in the
docs.
Auto-updates
CLI installs check for updates every 24 hours by default and apply them silently (so the MCP server keeps responding).
Supported install sources:
uv tool, HomebrewSkipped for
uvx(ephemeral runtime managed by uv)Manual:
bm update(check + apply) orbm update --check(check only)
Disable in ~/.basic-memory/config.json:
{ "auto_update": false }Telemetry
Minimal, anonymous events to understand the CLI-to-cloud conversion funnel.
What we collect: cloud promo impressions, cloud login attempts and outcomes, promo opt-out events.
What we don't: file contents, note titles, knowledge base data, PII, IP addresses, per-command or per-tool tracking.
Events go to our Umami Cloud instance (open-source, privacy-focused) on a background thread — never blocks the CLI.
Opt out:
export BASIC_MEMORY_NO_PROMOS=1This disables promos and all telemetry.
Logging
Basic Memory uses Loguru. Defaults vary by entry point:
Entry point | Default | Why |
CLI commands | File only | Doesn't interfere with command output |
MCP server | File only | Stdout would corrupt JSON-RPC |
API server | File (local) or stdout (cloud) | Docker/cloud uses stdout |
Log file: ~/.basic-memory/basic-memory.log (10MB rotation, 10 days
retention).
Environment variables
Variable | Default | Description |
|
| DEBUG / INFO / WARNING / ERROR |
|
| API logs to stdout with structured context |
|
| Force local API routing |
|
| Force cloud API routing |
|
| Mark route selection as explicit |
|
| Set to |
|
| Disable cloud promos and telemetry |
|
| Max uploaded import size |
BASIC_MEMORY_LOG_LEVEL=DEBUG basic-memory reindex
tail -f ~/.basic-memory/basic-memory.logDevelopment
Basic Memory supports SQLite (default, fast, no Docker) and Postgres (via testcontainers — Docker required).
just install # Install with dev dependencies
just test-sqlite # All tests, SQLite
just test-postgres # All tests, Postgres (testcontainers)
just test # Both backends
just fast-check # fix/format/typecheck + impacted tests
just doctor # File <-> DB consistency check (temp config)
just package-check # Claude Code, skills, Hermes, OpenClaw package checks
just lint
just typecheck # Pyright (primary)
just typecheck-ty # ty (supplemental)
just format
just check # All quality checks
just migration "msg" # New Alembic migrationTests use pytest markers: windows, benchmark, smoke. See
justfile for the full list.
Contributions welcome — see CONTRIBUTING.md.
License
Built with ♥️ by Basic Machines
Available Tools
12 toolsbm_contextBuild contextARead-onlyIdempotent
Follow the Basic Memory knowledge graph from a note: the note, its observations, and the notes its relations reach, up to depth hops (1-5). identifier is a path, permalink, memory:// URL, or a pattern such as 'specs/*'. since limits related results to recent changes. compact returns the graph without note bodies; read chosen notes with bm_read.
| Name | Required | Description | Default |
|---|---|---|---|
| page | No | Page number. | |
| depth | No | Relation hops to follow (1-5). | |
| since | No | How far back to look: '7d', '24h', '2 days ago', 'last week', or a date. Windows shorter than one day are widened to one day. | 7d |
| compact | No | Omit note bodies and observations; keep the graph shape. | |
| project | Yes | Required project name, 'workspace/project', or project external id. Discover projects with bm_project(command='list'). Paths are relative to this project; a qualified path must agree with it. | |
| page_size | No | Primary results per page (1-50). | |
| identifier | Yes | Where to start: a note path, permalink, memory:// URL, or a pattern such as 'specs/*'. | |
| max_related | No | Most related results to return (0-100). | |
| output_format | No | json |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly, idempotent, non-destructive and closed-world, so the safety bar is met structurally. The description adds real behavioral context beyond them: hop limits of 1-5, that `since` scopes only related results, and that `compact` strips bodies while keeping graph shape.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three dense sentences, front-loaded with the core traversal behavior and ending with the handoff to bm_read. No filler and no restatement of the title.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, return values need no explanation, and the description covers the traversal model and the key tuning knobs. It omits mention of the required `project` scoping and pagination (`page`/`page_size`/`max_related`), though the schema carries those adequately.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 89%, so the schema already documents nearly every parameter, and the description largely restates it (`identifier` forms, `depth` 1-5, `compact` omitting bodies). The one genuine addition is clarifying that `since` limits related results specifically rather than the root note, which is why this sits at baseline rather than below it.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: follow the knowledge graph from a note, returning the note, its observations, and relation-reached notes up to `depth` hops. It also names the boundary against the sibling bm_read, so an agent can distinguish traversal from direct reading without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The closing clause routes the agent clearly: use `compact` for graph shape, then bm_read for chosen note bodies. That is a genuine when-to-use/alternative statement. It does not, however, say when to prefer this over bm_search or bm_find for discovery.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
bm_deleteDelete noteADestructiveIdempotent
Delete a Basic Memory note (identifier) or a directory (path). A directory delete removes every file under it and needs recursive=true. Pass expected_checksum (from bm_read) to delete a note only if it is still the revision you read. A note that does not exist is an error. This cannot be undone.
| Name | Required | Description | Default |
|---|---|---|---|
| path | No | The directory to delete, with everything in it. | |
| project | Yes | Required project name, 'workspace/project', or project external id. Discover projects with bm_project(command='list'). Paths are relative to this project; a qualified path must agree with it. | |
| recursive | No | Required true to delete a directory and everything under it. | |
| identifier | No | The note to delete: a path, permalink, memory:// URL or exact title. | |
| output_format | No | text | |
| expected_checksum | No | Delete the note only while it is still this revision (from bm_read). |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Adds meaningful behavior beyond the annotations: irreversibility is stated plainly, directory deletion is gated on `recursive=true`, and a missing note raises an error rather than silently succeeding. The checksum-gated delete is real context an agent cannot get from destructiveHint alone; only cross-parameter conflict behavior is missing.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four short sentences, front-loaded with the two deletion modes, followed by preconditions and the irreversibility warning as a closing emphasizer. Nothing is repeated from the schema verbatim and no sentence is filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Output schema exists, so return values need not be explained, and the annotations already declare destructive/idempotent semantics. For a destructive mutation the description covers modes, gating flags, existence errors, and irreversibility; only permission/auth expectations and the identifier-vs-path precedence are unstated.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is high (83%) and each parameter already carries its own description, so the schema carries the load. The description reinforces the `recursive` requirement and the provenance of `expected_checksum` (from bm_read) but adds little new syntax or format guidance beyond the schema, making 3 the correct baseline.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (Delete) against two clearly named resource modes — a note via `identifier` or a directory via `path` — which is the main ambiguity an agent would face. It does not contrast itself with sibling mutators like bm_edit or bm_move, so it stops short of full sibling differentiation.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit conditional usage: use `recursive=true` to delete a directory, pass `expected_checksum` from bm_read for revision-guarded deletes. It does not say when to prefer a different tool (e.g., moving or editing instead of deleting) or explicitly state what happens if both `identifier` and `path` are supplied.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
bm_editEdit noteADestructive
Change part of an existing Basic Memory note. command: append or prepend content; find_replace find_text with content (exact text, which must occur expected_replacements times, default 1); replace_section, insert_before_section or insert_after_section for a section heading ('Decisions', 'Auth/Decisions', 'Decisions[1]', as bm_read takes it); set_metadata to merge metadata into the frontmatter without touching the body. metadata also merges with any other command. Pass expected_checksum (from bm_read) to edit only the revision you read. A missing note is an error; create notes with bm_write.
| Name | Required | Description | Default |
|---|---|---|---|
| command | Yes | The edit. | |
| content | No | The text to add or the replacement. Not used by set_metadata. | |
| project | Yes | Required project name, 'workspace/project', or project external id. Discover projects with bm_project(command='list'). Paths are relative to this project; a qualified path must agree with it. | |
| section | No | The heading for section commands: "Decisions", "Auth/Decisions" for one under "Auth", or "Decisions[1]" for the second of two. | |
| metadata | No | Frontmatter fields to set; other fields are kept. | |
| find_text | No | For find_replace: the exact, case-sensitive text to replace. | |
| identifier | Yes | The note or file: a file path ('notes/plan.md'), permalink, memory:// URL, exact title, external id, or '<project>/path'. | |
| output_format | No | text | |
| expected_checksum | No | Edit only while the note is still this revision (from bm_read). | |
| replace_subsections | No | For replace_section: true replaces the section's subsections too; false stops at the first subsection heading. | |
| expected_replacements | No | For find_replace: how many times find_text must occur. |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes beyond the destructiveHint=true / idempotentHint=false annotations by disclosing that set_metadata and metadata merge rather than overwrite ('without touching the body'), that find_replace fails unless find_text occurs expected_replacements times, and that expected_checksum enables revision-guarded edits. It does not spell out irreversibility or that replaced section content is destroyed, which is the remaining gap given the destructive flag.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the core action, then groups per-command semantics and the safety/error clauses in a single dense paragraph. Nearly every clause carries distinct information; there is no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For an 11-parameter mutation tool with an output schema (so return values need no explanation) and annotations covering the safety profile, the description covers command selection, concurrency, and the missing-note error. Minor omissions remain, such as content being unused by set_metadata as an explicit precondition or what a section command does when the heading is absent.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 91%, so the baseline is 3; the description still adds value by tying each parameter to its command and by stating a rule the schema does not — that 'metadata also merges with any other command.' The section-heading syntax and expected_replacements default largely restate the schema text.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb+resource+scope: 'Change part of an existing Basic Memory note.' It explicitly carves out the sibling boundary by stating 'A missing note is an error; create notes with bm_write,' so an agent can separate edit from create without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Enumerates every command with the condition that selects it (append/prepend content, find_replace with expected_replacements, section commands for a heading, set_metadata for frontmatter only) plus the alternative tool for the create case. It also states the failure mode when the note does not exist, which is the main when-not.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
bm_findFind filesARead-onlyIdempotent
Find files in a Basic Memory project, recursively. With name, match file names against a glob ('meeting'). With filters, match notes by frontmatter, e.g. {"status": "active"} or {"priority": {"$in": ["high"]}}, and with fields return just those frontmatter values per note. path limits the search to a folder. For ranked text or meaning search, use bm_search.
| Name | Required | Description | Default |
|---|---|---|---|
| name | No | File-name glob, e.g. '*.md'. Not with `filters`. | |
| page | No | Page number. | |
| path | No | A directory in the project, e.g. 'specs' or 'specs/active'. '/' is the project root; '<project>/path' addresses another project. | / |
| depth | No | Folder levels to search (1-10). | |
| fields | No | Frontmatter fields to return per note (dot paths allowed), e.g. ["title", "priority"]. Needs `filters`. | |
| filters | No | Frontmatter filters as {field: condition}. Nested fields use dot notation ("schema.confidence"). A condition is a value for equality ({"status": "draft"}), null for absent-or-null ({"owner": null}), a list for contains-all ({"tags": ["a", "b"]}), or an operator object with $gt, $gte, $lt, $lte, $in, $between, $contains or $exists, e.g. {"priority": {"$in": ["high"]}}. Several operators on one field AND together. | |
| project | Yes | Required project name, 'workspace/project', or project external id. Discover projects with bm_project(command='list'). Paths are relative to this project; a qualified path must agree with it. | |
| page_size | No | Results per page (1-100). | |
| output_format | No | text |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare this as read-only, idempotent, non-destructive, and not open-world. The description adds meaningful behavior beyond annotations: recursive traversal, frontmatter-based filtering, and projecting only requested frontmatter fields per note. It does not discuss permissions, but for a read-only search tool the added behavioral detail is solid.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is four sentences, front-loaded with the core purpose, then organized by query mode, and ends with the key alternative. There is no filler and every sentence contributes to selecting or invoking the tool correctly.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 9-parameter tool with a detailed schema, high schema coverage, annotations, and an output schema, the description covers the main behavior and the key alternative. Minor gaps around pagination, depth, and `output_format` are handled by the schema, so the definition is complete enough for correct selection and invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 89% and the schema itself contains detailed parameter documentation and examples. The description reinforces `name`, `filters`, `fields`, and `path` with examples, but adds little beyond the structured schema and does not explain pagination, depth, project resolution, or `output_format`.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: 'Find files in a Basic Memory project, recursively.' It clearly enumerates the main query modes (`name`, `filters`, `fields`, `path`) and explicitly distinguishes this tool from `bm_search` for ranked text or meaning search.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Useful usage context is given for `name`, `filters`, `fields`, and `path`, and the description explicitly routes ranked text/meaning search to `bm_search`. However, it does not mention that `name` cannot be combined with `filters` (that constraint is only in the schema) and does not distinguish usage from siblings such as `bm_list`.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
bm_listList folderARead-onlyIdempotent
List one folder of a Basic Memory project: its subfolders, then its files with title, date and id. project is required; '/' lists its root. Discover projects with bm_project(command='list'). Filter files with glob and order them with sort. For a recursive search by name or frontmatter, use bm_find.
| Name | Required | Description | Default |
|---|---|---|---|
| glob | No | File-name glob, e.g. '*.md' or '*meeting*'. | |
| page | No | Page number. | |
| path | No | A directory in the project, e.g. 'specs' or 'specs/active'. '/' is the project root; '<project>/path' addresses another project. | / |
| sort | No | File order. Folders always come first. | |
| project | Yes | Required project name, 'workspace/project', or project external id. Discover projects with bm_project(command='list'). Paths are relative to this project; a qualified path must agree with it. | |
| page_size | No | Results per page (1-100). | |
| output_format | No | text |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly, idempotent, closed-world and non-destructive, so safety is covered. The description adds genuine context beyond them: what the listing contains, that folders always precede files, and that sorting applies only to files. It does not mention paging or that large folders are truncated at page_size, which is the one behavioral trait an agent could trip over.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four short sentences, front-loaded with the core action and output shape, then constraints, then the sibling alternative. Every clause carries information; there is no restatement of the tool name or filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, return values need not be explained in depth, and the description still previews them. Project discovery, root addressing, filtering, ordering and the sibling alternative are all covered, which is everything needed to invoke a read-only folder lister correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 86%, so the schema already carries parameter meaning; the description reinforces that 'glob' filters files (not folders) and that 'sort' orders files only. It adds modest clarification but no format, syntax, or interaction detail (e.g. how glob and path interact) beyond the schema — baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('List one folder of a Basic Memory project') and even describes the output shape — subfolders first, then files with title, date and id. It explicitly separates itself from bm_find's recursive search, so an agent can pick between them without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives the prerequisite ('project' is required), the root convention ('/' lists its root), a bootstrapping step (bm_project(command='list')), and an explicit alternative for a different use case ('For a recursive search by name or frontmatter, use bm_find'). Nothing about when to choose this tool is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
bm_manManualARead-onlyIdempotent
Read the Basic Memory manual. With no arguments, the index of every page. page reads one page: 'bm-search(3)' for an MCP tool, 'grep(1)' for a shell command; a tool name such as 'bm_search' works too. query lists the pages that mention every word given, like man -k.
| Name | Required | Description | Default |
|---|---|---|---|
| page | No | The page to read, e.g. 'bm-search(3)', 'grep(1)' or 'bm_search'. | |
| query | No | Words to find in the manual; lists the pages that mention them all. | |
| output_format | No | text |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The annotations already declare readOnlyHint=true, destructiveHint=false, idempotentHint=true, and openWorldHint=false. The description adds useful behavioral detail beyond that: what the no-argument form returns, what `page` accepts, and that `query` lists pages mentioning every supplied word, much like `man -k`.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with the core purpose and then efficiently explains each mode in one sentence. There is no redundancy or filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With read-only annotations and an output schema present, the description does not need to explain return values or safety. It covers the main calling modes well, though it could briefly mention `output_format` behavior to be fully complete for all three parameters.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The description adds real meaning for `page` by giving accepted forms like 'bm-search(3)', 'grep(1)', and bare tool names, and for `query` by clarifying the all-words matching behavior. It does not describe `output_format`, and schema description coverage is 67%, but the main parameters are well explained.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: 'Read the Basic Memory manual.' It then clearly distinguishes the three modes (index, page, query), so an agent can immediately tell what the tool does without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explains how to use each mode: no arguments for the index, `page` for one page, and `query` for keyword listing. It does not explicitly compare this tool to sibling tools like bm_search or bm_find, but the manual-reading context is clear and there are no misleading exclusions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
bm_moveMove noteA
Move or rename a Basic Memory note (identifier) or a directory (path) within its project. destination is the new project-relative path; ending it with '/' moves into that folder under the current name ('archive/'). A note keeps its file extension ('.markdown' may become '.md'). Pass expected_checksum (from bm_read) to move a note only if it is still the revision you read. Moving into another project is refused: bm_read, bm_write there, then bm_delete.
| Name | Required | Description | Default |
|---|---|---|---|
| path | No | The directory to move, with everything in it, e.g. 'drafts/2025'. | |
| project | Yes | Required project name, 'workspace/project', or project external id. Discover projects with bm_project(command='list'). Paths are relative to this project; a qualified path must agree with it. | |
| identifier | No | The note to move: a path, permalink, memory:// URL or exact title. | |
| destination | Yes | New path, e.g. 'archive/plan.md'. A trailing '/' ('archive/') moves the note or directory into that folder under its current name. | |
| output_format | No | text | |
| expected_checksum | No | Move the note only while it is still this revision (from bm_read). |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations (which only mark it as non-read-only, non-idempotent, non-destructive): it discloses the cross-project refusal, extension normalization ('.markdown' may become '.md'), preservation of the current name when destination ends in '/', and optimistic-concurrency behavior via expected_checksum. It does not say what happens if the destination path already exists, which is the one meaningful behavioral gap for a move operation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four dense sentences with the core action and destination semantics front-loaded; the cross-project refusal and checksum note follow logically. Slightly packed with parenthetical detail, but no sentence is filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists so return values need no explanation, and annotations cover the safety profile; the description fills in the refusal rule and checksum semantics. The missing piece is overwrite/collision behavior when the destination already exists, which matters for a move tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is already 83%, so the baseline is 3; the description still adds meaning by framing `destination` as a project-relative path, explaining the trailing-'/' convention in operational terms, and tying `expected_checksum` to a prior bm_read. The extension-change note for notes is additional context not in the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource pair ('Move or rename a Basic Memory note or directory') and immediately disambiguates the two modes via the `identifier` vs `path` parameters. The within-project scope constraint further narrows what the tool does, letting an agent separate it from bm_edit (content change) and bm_delete.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit when-not with the replacement workflow: cross-project moves are refused, so use bm_read, bm_write there, then bm_delete. It also specifies the conditional-move case via `expected_checksum` and the trailing-slash convention for moving into a folder without renaming.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
bm_projectProjectsB
Basic Memory projects. command: list (projects, grouped by workspace); create (name, path, optional set_default, workspace); recent (what changed lately in the required project: since, items, paging).
| Name | Required | Description | Default |
|---|---|---|---|
| name | No | For create: the new project's name. | |
| page | No | Page number. | |
| path | No | For create: the folder that holds the project's notes. | |
| items | No | What to return: notes, observations, relations, or a mix. Default: notes. | |
| since | No | How far back to look: '7d', '24h', '2 days ago', 'last week', or a date. Windows shorter than one day are widened to one day. | 7d |
| command | Yes | What to do. | |
| project | No | Project name, 'workspace/project', or external id. Required for one-project operations; search may instead use `projects` or `all_projects=true`. Project discovery needs no scope. | |
| page_size | No | Results per page (1-100). | |
| workspace | No | In Cloud: the workspace slug, name or id that holds the project. | |
| set_default | No | For create: make the new project the default. | |
| output_format | No | text |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare non-readOnly, non-destructive, non-idempotent, closed-world, so the safety profile is set. The description adds that `list` groups by workspace and that `recent` requires a project scope, but says nothing about what `create` actually does on disk (folder creation, failure modes, whether it overwrites), which is the one mutating path and the main behavioral risk.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single dense sentence that front-loads the resource and then walks the commands in order with their parameters. No filler, though the heavy parenthetical nesting makes it slightly harder to scan than a short bulleted form would be.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With 11 parameters, an output schema, and annotations present, the description covers the command-to-parameter mapping adequately. It leaves gaps on what `create` produces, how errors surface, and why an agent would choose this over bm_list/bm_search for project awareness, which matter given three divergent modes behind one tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 91%, so individual parameters are already well documented, and the description largely restates the schema's per-command mapping (name/path/set_default/workspace for create, since/items/paging for recent). It does clarify which parameters group together per command, a mild add over the schema. Baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names the resource (Basic Memory projects) and enumerates the three distinct operations (list, create, recent) with the parameters each consumes, so an agent can map intent to command. It does not explicitly contrast with siblings such as bm_list or bm_search, which handle notes rather than project administration, so it falls short of 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
"recent (what changed lately in the required `project`)" implies when to pick that command, and the create/list breakdown hints at contexts, but there is no explicit statement of when to use this tool instead of bm_list, bm_read, or bm_search, nor any exclusions. Usage must be inferred from the command names.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
bm_readRead noteARead-onlyIdempotent
Read a Basic Memory note or file by path, permalink, memory:// URL or exact title. Slice a long note with section (a heading), start_line/end_line or max_tokens; line numbers count the whole file, frontmatter included. A text file such as .txt takes start_line/end_line too. include_content=false returns only the metadata and the checksum that bm_write and bm_edit take as expected_checksum. Images come back as images and other binary files as documents. A missing note is an error: find notes with bm_search.
| Name | Required | Description | Default |
|---|---|---|---|
| project | Yes | Required project name, 'workspace/project', or project external id. Discover projects with bm_project(command='list'). Paths are relative to this project; a qualified path must agree with it. | |
| section | No | A heading to read: "Decisions", "Auth/Decisions" for a heading under "Auth", or "Decisions[1]" for the second "Decisions" heading. | |
| end_line | No | ||
| identifier | Yes | The note or file: a file path ('notes/plan.md'), permalink, memory:// URL, exact title, external id, or '<project>/path'. | |
| max_tokens | No | Approximate token budget. Longer content is cut at a section or paragraph boundary, and the result says which line to continue from. | |
| start_line | No | ||
| output_format | No | text | |
| include_content | No | False returns only title, paths, checksum and updated_at. | |
| include_frontmatter | No | Include the YAML frontmatter in a whole-note read. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnly/idempotent annotations, it discloses non-obvious behavior: missing notes raise an error rather than returning empty, images come back as images and other binaries as documents, truncation via max_tokens reports a continuation line, and the checksum is the expected_checksum value consumed by bm_write/bm_edit. That cross-tool linkage is exactly the kind of context annotations cannot carry.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core action, then slicing options, then the metadata/checksum mode, then edge cases — a sensible order with no filler. It is dense and long for a read tool, but every clause carries distinct information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With 9 parameters and no output schema, the description carries the return-value burden well: it says what comes back for notes, text files, images and binaries, what the truncated response includes, and what metadata-only mode yields. Nothing essential for a correct call is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
At 67% schema coverage it adds real meaning: line numbers count the whole file including frontmatter, section accepts a heading path or an indexed repeat ('Decisions[1]'), max_tokens cuts at section/paragraph boundaries, and include_content=false returns title, paths, checksum and updated_at. It leaves output_format, start_line and end_line's own semantics (e.g., default end) unstated.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Read a Basic Memory note or file') and enumerates the accepted identifier forms (path, permalink, memory:// URL, exact title), which lets an agent map its input to this tool immediately. It also distinguishes itself from the discovery sibling by naming bm_search.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives clear routing: 'A missing note is an error: find notes with bm_search,' and explains the metadata-only mode via include_content=false for checksum lookups. It stops short of naming other plausible alternatives (bm_find, bm_list, bm_context) or stating when not to read a whole file.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
bm_schemaNote schemasARead-onlyIdempotent
Basic Memory note schemas (Picoschema). command: validate notes against their schema (one note_type, one note by identifier, or every type that has a schema); infer a schema from the notes of a note_type; diff a note_type's notes against its schema to find drift. A schema is a note with type: schema whose entity field names the note type it describes.
| Name | Required | Description | Default |
|---|---|---|---|
| command | Yes | What to do. | |
| project | Yes | Required project name, 'workspace/project', or project external id. Discover projects with bm_project(command='list'). Paths are relative to this project; a qualified path must agree with it. | |
| note_type | No | The frontmatter `type:` to check. Required for infer and diff. | |
| threshold | No | For infer: the share of notes a field must appear in to be suggested. | |
| identifier | No | For validate: one note, instead of a whole note type. | |
| output_format | No | text |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, non-destructive and closed-world, so the safety profile is covered. The description adds genuine domain context beyond that: the definition of a schema note and the entity field linkage. It doesn't describe failure output or how partial validation results are reported, but an output schema exists to carry that.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The core capability and the three commands are front-loaded in the first sentence, with the schema definition last. It is dense but every clause carries information; the telegraphic 'infer a schema from the notes of a note_type' phrasing costs a little readability.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a three-mode tool with a full output schema and rich annotations, the description covers what the commands do and the conceptual model needed to use them. Remaining gaps (threshold behavior, output_format choice) are handled by the schema, so nothing essential is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 83%, so the baseline is 3, and the description earns a bump by clarifying the mutually exclusive targeting modes (one note_type, one note via identifier, or every type with a schema) that the schema only hints at with per-field 'For validate' notes. The threshold and output_format parameters are not mentioned in the description, but both are documented in the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names the resource (Basic Memory note schemas / Picoschema) and gives a specific verb for each of the three commands: validate, infer, and diff. It also defines what a schema is (a note with type: schema whose entity field names the described type). It does not explicitly distinguish itself from siblings such as bm_man or bm_read, relying on the uniqueness of schema operations instead.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Each command is given a situation: validate for one note_type, one note by identifier, or all types with schemas; infer to derive a schema from existing notes; diff to find drift. That is clear per-command guidance. There are no explicit exclusions or pointers to alternative tools for overlapping needs.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
bm_searchSearch notesARead-onlyIdempotent
Search a Basic Memory project, ranked by relevance. query supports quoted phrases, AND/OR/NOT and tag:name. mode picks hybrid (the default when semantic search is available), text, semantic, title or permalink (globs with *). Narrow with filters (frontmatter), note_types, items (notes, observations, relations) and since. lines returns the matching lines of each hit with that many lines of context, like grep. path limits the search to a folder; identifier searches one note. Scope every search with project (one project), projects (a list), or all_projects=true. Read full notes with bm_read.
| Name | Required | Description | Default |
|---|---|---|---|
| mode | No | Search mode. | |
| page | No | Page number. | |
| path | No | Search only this folder and its subfolders. | |
| items | No | What to return: notes, observations, relations, or a mix. Default: notes. | |
| lines | No | Return each hit's matching lines with this many lines of context (0-10), instead of a match excerpt. | |
| query | No | What to search for. Omit to search by filters alone. | |
| since | No | How far back to look: '7d', '24h', '2 days ago', 'last week', or a date. Windows shorter than one day are widened to one day. | |
| compact | No | Omit note bodies and excerpts; keep identifiers and scores. | |
| filters | No | Frontmatter filters as {field: condition}. Nested fields use dot notation ("schema.confidence"). A condition is a value for equality ({"status": "draft"}), null for absent-or-null ({"owner": null}), a list for contains-all ({"tags": ["a", "b"]}), or an operator object with $gt, $gte, $lt, $lte, $in, $between, $contains or $exists, e.g. {"priority": {"$in": ["high"]}}. Several operators on one field AND together. | |
| project | No | Project name, 'workspace/project', or external id. Required for one-project operations; search may instead use `projects` or `all_projects=true`. Project discovery needs no scope. | |
| projects | No | Search these projects together. | |
| valid_at | No | Specialist: only facts whose authored valid time contains this date. | |
| page_size | No | Results per page (1-100). | |
| time_kind | No | Specialist: effective, valid, occurred, due or mentioned. | |
| categories | No | Observation categories to match exactly, e.g. ['decision']. | |
| identifier | No | Search only this note; returns its matching lines. | |
| note_types | No | Frontmatter `type` values, e.g. ['person', 'meeting']. | |
| max_matches | No | Matching lines shown per note with `lines`. | |
| all_projects | No | Search every project you can access. | |
| output_format | No | text | |
| min_similarity | No | Override the semantic similarity floor (0-1). | |
| valid_overlaps | No | Specialist: only facts whose valid range overlaps '[start,end)'. |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The annotations already establish that this is a read-only, idempotent, non-destructive operation. The description adds useful behavioral detail beyond that: relevance ranking, hybrid mode as the default when semantic search is available, grep-like line output, and the requirement to scope every search.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is dense and front-loaded, leading with what the tool does and then covering query syntax, mode, narrowing, line output, scoping, and the bm_read follow-up. Every sentence carries useful information for a complex search tool.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the rich input schema, output schema, and safety annotations, the description provides enough context to select and invoke the tool correctly. It emphasizes the critical scoping requirement and the main search behaviors without redundantly restating structured fields.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 95%, so the baseline is 3, but the description adds real meaning for key parameters: query syntax with quoted phrases and AND/OR/NOT/tag:name, hybrid mode default behavior, filters on frontmatter, grep-like lines, and project scoping. It does not cover every one of the 22 parameters, but it covers the parameters most likely to affect correct invocation.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: search a Basic Memory project, ranked by relevance. It also names bm_read as the follow-up tool for full notes, making the boundary between searching and reading explicit.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives clear usage context: use query syntax, choose a mode, narrow with filters/note_types/items/since, scope with project/projects/all_projects, and use bm_read for full notes. It does not explicitly distinguish bm_search from the sibling bm_find or bm_list, so the closest alternative remains unaddressed.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
bm_writeWrite noteADestructive
Create or replace a Basic Memory note. Give a file path as identifier ('notes/plan.md'), or title plus directory. With a path the file lands exactly there and the title comes from the content's frontmatter, then title, then the file name. An existing note is an error unless overwrite=true; pass expected_checksum (from bm_read) to replace only the revision you read. To change part of a note use bm_edit. Content may hold frontmatter, observations ('- [category] fact #tag') and relations ('- relation_type [[Other Note]]').
| Name | Required | Description | Default |
|---|---|---|---|
| tags | No | Tags, as a list or 'a,b,c'. | |
| title | No | Note title. With `directory`, it also names the file. With `identifier`, it is used when the content has no frontmatter title. | |
| content | Yes | The note's Markdown. Saved as given; it may start with frontmatter. | |
| project | Yes | Required project name, 'workspace/project', or project external id. Discover projects with bm_project(command='list'). Paths are relative to this project; a qualified path must agree with it. | |
| metadata | No | Extra frontmatter fields, merged into the note's frontmatter. | |
| directory | No | Folder for a note addressed by title, e.g. 'meetings'; '/' is the root. | |
| note_type | No | Frontmatter `type:`. A `type:` in the content wins. | note |
| overwrite | No | Replace a note that already exists. Default: the write_note_overwrite_default setting (false unless changed). | |
| identifier | No | File path for the note, e.g. 'notes/plan.md'; '.md' is added when missing. '<project>/path' writes into another project. Use instead of title + directory. | |
| output_format | No | text | |
| expected_checksum | No | Replace the note only while it is still this revision (the checksum from bm_read). Implies overwrite=true. |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true and idempotentHint=false, but the description adds the crucial nuance that writes are non-destructive by default and only overwrite when asked, plus optimistic-concurrency semantics via `expected_checksum`. It also discloses title-resolution precedence (frontmatter, then `title`, then file name). Missing only auth/permission context and whether the project must pre-exist, which keeps it off a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four dense sentences ordered from what the tool does, to how to address the note, to conflict handling, to content shape. Zero filler, though the content-syntax sentence packs three concepts (frontmatter, observations, relations) into one trailing clause.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be described, and the remaining parameters (tags, metadata, note_type, output_format) are documented in the schema at 91% coverage. What an agent needs for correct invocation — addressing, overwrite, checksum, content format — is all present; only cross-project path qualification is hinted at rather than explained.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 91%, so the baseline is 3, but the description adds real precedence rules the schema does not: the title is taken from frontmatter first, then `title`, then the file name, and that a path pins the file exactly. That resolves the ambiguity between the `identifier` and `title`/`directory` parameters.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Create or replace a Basic Memory note') and immediately names the sibling it is not ('To change part of a note use bm_edit'). An agent can separate bm_write from bm_edit and bm_delete without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit addressing alternatives (file path as `identifier` vs `title` + `directory`), states that an existing note errors unless `overwrite=true`, and points to bm_read as the source of `expected_checksum` for revision-safe replacement. The redirect to bm_edit is an explicit when-not rule.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
38 tool updates
- Removed
basic_memory_diagnostics - Changed
bm_context7 fields changed- removed
Input schema / properties / project / anyOfRemoved value: -[ - { - "type": "string" - }, - { - "type": "null" - } -] - removed
Input schema / properties / project / defaultRemoved value: -null - changed
Input schema / properties / project / descriptionPrevious value: -"Project name, 'workspace/project', or project external id. Omit to use the default project."New value: +"Required project name, 'workspace/project', or project external id. Discover projects with bm_project(command='list'). Paths are relative to this project; a qualified path must agree with it." - added
Input schema / properties / project / minLengthAdded value: +1 - added
Input schema / properties / project / typeAdded value: +"string" - changed
Input schema / requiredPrevious value: -[ - "identifier" -]New value: +[ + "identifier", + "project" +] - changed
Output schema / properties / result / anyOfPrevious value: -[ - { - "additionalProperties": true, - "type": "object" - }, - { - "type": "string" - } -]New value: +[ + { + "type": "string" + }, + { + "additionalProperties": true, + "type": "object" + } +]
- Changed
bm_delete7 fields changed- removed
Input schema / properties / project / anyOfRemoved value: -[ - { - "type": "string" - }, - { - "type": "null" - } -] - removed
Input schema / properties / project / defaultRemoved value: -null - changed
Input schema / properties / project / descriptionPrevious value: -"Project name, 'workspace/project', or project external id. Omit to use the default project."New value: +"Required project name, 'workspace/project', or project external id. Discover projects with bm_project(command='list'). Paths are relative to this project; a qualified path must agree with it." - added
Input schema / properties / project / minLengthAdded value: +1 - added
Input schema / properties / project / typeAdded value: +"string" - added
Input schema / requiredAdded value: +[ + "project" +] - changed
Output schema / properties / result / anyOfPrevious value: -[ - { - "additionalProperties": true, - "type": "object" - }, - { - "type": "string" - } -]New value: +[ + { + "type": "string" + }, + { + "additionalProperties": true, + "type": "object" + } +]
- Changed
bm_edit7 fields changed- removed
Input schema / properties / project / anyOfRemoved value: -[ - { - "type": "string" - }, - { - "type": "null" - } -] - removed
Input schema / properties / project / defaultRemoved value: -null - changed
Input schema / properties / project / descriptionPrevious value: -"Project name, 'workspace/project', or project external id. Omit to use the default project."New value: +"Required project name, 'workspace/project', or project external id. Discover projects with bm_project(command='list'). Paths are relative to this project; a qualified path must agree with it." - added
Input schema / properties / project / minLengthAdded value: +1 - added
Input schema / properties / project / typeAdded value: +"string" - changed
Input schema / requiredPrevious value: -[ - "identifier", - "command" -]New value: +[ + "identifier", + "command", + "project" +] - changed
Output schema / properties / result / anyOfPrevious value: -[ - { - "additionalProperties": true, - "type": "object" - }, - { - "type": "string" - } -]New value: +[ + { + "type": "string" + }, + { + "additionalProperties": true, + "type": "object" + } +]
- Changed
bm_find7 fields changed- removed
Input schema / properties / project / anyOfRemoved value: -[ - { - "type": "string" - }, - { - "type": "null" - } -] - removed
Input schema / properties / project / defaultRemoved value: -null - changed
Input schema / properties / project / descriptionPrevious value: -"Project name, 'workspace/project', or project external id. Omit to use the default project."New value: +"Required project name, 'workspace/project', or project external id. Discover projects with bm_project(command='list'). Paths are relative to this project; a qualified path must agree with it." - added
Input schema / properties / project / minLengthAdded value: +1 - added
Input schema / properties / project / typeAdded value: +"string" - added
Input schema / requiredAdded value: +[ + "project" +] - changed
Output schema / properties / result / anyOfPrevious value: -[ - { - "additionalProperties": true, - "type": "object" - }, - { - "type": "string" - } -]New value: +[ + { + "type": "string" + }, + { + "additionalProperties": true, + "type": "object" + } +]
- Changed
bm_list7 fields changed- removed
Input schema / properties / project / anyOfRemoved value: -[ - { - "type": "string" - }, - { - "type": "null" - } -] - removed
Input schema / properties / project / defaultRemoved value: -null - changed
Input schema / properties / project / descriptionPrevious value: -"Project name, 'workspace/project', or project external id. Omit to use the default project."New value: +"Required project name, 'workspace/project', or project external id. Discover projects with bm_project(command='list'). Paths are relative to this project; a qualified path must agree with it." - added
Input schema / properties / project / minLengthAdded value: +1 - added
Input schema / properties / project / typeAdded value: +"string" - added
Input schema / requiredAdded value: +[ + "project" +] - changed
Output schema / properties / result / anyOfPrevious value: -[ - { - "additionalProperties": true, - "type": "object" - }, - { - "type": "string" - } -]New value: +[ + { + "type": "string" + }, + { + "additionalProperties": true, + "type": "object" + } +]
- Changed
bm_man1 field changed- changed
Output schema / properties / result / anyOfPrevious value: -[ - { - "additionalProperties": true, - "type": "object" - }, - { - "type": "string" - } -]New value: +[ + { + "type": "string" + }, + { + "additionalProperties": true, + "type": "object" + } +]
- Changed
bm_move7 fields changed- removed
Input schema / properties / project / anyOfRemoved value: -[ - { - "type": "string" - }, - { - "type": "null" - } -] - removed
Input schema / properties / project / defaultRemoved value: -null - changed
Input schema / properties / project / descriptionPrevious value: -"Project name, 'workspace/project', or project external id. Omit to use the default project."New value: +"Required project name, 'workspace/project', or project external id. Discover projects with bm_project(command='list'). Paths are relative to this project; a qualified path must agree with it." - added
Input schema / properties / project / minLengthAdded value: +1 - added
Input schema / properties / project / typeAdded value: +"string" - changed
Input schema / requiredPrevious value: -[ - "destination" -]New value: +[ + "destination", + "project" +] - changed
Output schema / properties / result / anyOfPrevious value: -[ - { - "additionalProperties": true, - "type": "object" - }, - { - "type": "string" - } -]New value: +[ + { + "type": "string" + }, + { + "additionalProperties": true, + "type": "object" + } +]
- Changed
bm_project2 fields changed- changed
Input schema / properties / project / anyOfPrevious value: -[ - { - "type": "string" - }, - { - "type": "null" - } -]New value: +[ + { + "minLength": 1, + "type": "string" + }, + { + "type": "null" + } +] - changed
Input schema / properties / project / descriptionPrevious value: -"Project name, 'workspace/project', or project external id. Omit to use the default project."New value: +"Project name, 'workspace/project', or external id. Required for one-project operations; search may instead use `projects` or `all_projects=true`. Project discovery needs no scope."
- Changed
bm_read6 fields changed- removed
Input schema / properties / project / anyOfRemoved value: -[ - { - "type": "string" - }, - { - "type": "null" - } -] - removed
Input schema / properties / project / defaultRemoved value: -null - changed
Input schema / properties / project / descriptionPrevious value: -"Project name, 'workspace/project', or project external id. Omit to use the default project."New value: +"Required project name, 'workspace/project', or project external id. Discover projects with bm_project(command='list'). Paths are relative to this project; a qualified path must agree with it." - added
Input schema / properties / project / minLengthAdded value: +1 - added
Input schema / properties / project / typeAdded value: +"string" - changed
Input schema / requiredPrevious value: -[ - "identifier" -]New value: +[ + "identifier", + "project" +]
- Changed
bm_schema6 fields changed- removed
Input schema / properties / project / anyOfRemoved value: -[ - { - "type": "string" - }, - { - "type": "null" - } -] - removed
Input schema / properties / project / defaultRemoved value: -null - changed
Input schema / properties / project / descriptionPrevious value: -"Project name, 'workspace/project', or project external id. Omit to use the default project."New value: +"Required project name, 'workspace/project', or project external id. Discover projects with bm_project(command='list'). Paths are relative to this project; a qualified path must agree with it." - added
Input schema / properties / project / minLengthAdded value: +1 - added
Input schema / properties / project / typeAdded value: +"string" - changed
Input schema / requiredPrevious value: -[ - "command" -]New value: +[ + "command", + "project" +]
- Changed
bm_search3 fields changed- changed
Input schema / properties / project / anyOfPrevious value: -[ - { - "type": "string" - }, - { - "type": "null" - } -]New value: +[ + { + "minLength": 1, + "type": "string" + }, + { + "type": "null" + } +] - changed
Input schema / properties / project / descriptionPrevious value: -"Project name, 'workspace/project', or project external id. Omit to use the default project."New value: +"Project name, 'workspace/project', or external id. Required for one-project operations; search may instead use `projects` or `all_projects=true`. Project discovery needs no scope." - changed
Output schema / properties / result / anyOfPrevious value: -[ - { - "additionalProperties": true, - "type": "object" - }, - { - "type": "string" - } -]New value: +[ + { + "type": "string" + }, + { + "additionalProperties": true, + "type": "object" + } +]
- Changed
bm_write7 fields changed- removed
Input schema / properties / project / anyOfRemoved value: -[ - { - "type": "string" - }, - { - "type": "null" - } -] - removed
Input schema / properties / project / defaultRemoved value: -null - changed
Input schema / properties / project / descriptionPrevious value: -"Project name, 'workspace/project', or project external id. Omit to use the default project."New value: +"Required project name, 'workspace/project', or project external id. Discover projects with bm_project(command='list'). Paths are relative to this project; a qualified path must agree with it." - added
Input schema / properties / project / minLengthAdded value: +1 - added
Input schema / properties / project / typeAdded value: +"string" - changed
Input schema / requiredPrevious value: -[ - "content" -]New value: +[ + "content", + "project" +] - changed
Output schema / properties / result / anyOfPrevious value: -[ - { - "additionalProperties": true, - "type": "object" - }, - { - "type": "string" - } -]New value: +[ + { + "type": "string" + }, + { + "additionalProperties": true, + "type": "object" + } +]
- Removed
build_context - Removed
cat - Removed
create_memory_project - Removed
delete_note - Removed
edit_note - Removed
fetch - Removed
find - Removed
grep - Removed
list_directory - Removed
list_memory_projects - Removed
list_workspaces - Removed
ls - Removed
man - Removed
move_note - Removed
read_content - Removed
read_note - Removed
recent_activity - Removed
schema_diff - Removed
schema_infer - Removed
schema_validate - Removed
search - Removed
search_notes - Removed
tail - Removed
view_note - Removed
write_note
40 tool updates
v0.24.1- Added
basic_memory_diagnostics - Added
bm_context - Added
bm_delete - Added
bm_edit - Added
bm_find - Added
bm_list - Added
bm_man - Added
bm_move - Added
bm_project - Added
bm_read - Added
bm_schema - Added
bm_search - Added
bm_write - Changed
build_context28 fields changed- added
Input schema / additionalPropertiesAdded value: +false - added
Input schema / properties / compactAdded value: +{ + "default": false, + "description": "Omit note bodies and entity observation lists for graph discovery; the server skips loading observations. Preserve identifiers, relation targets and pagination; use read_note for selected content. Not a guaranteed token budget.", + "type": "boolean" +} - added
Input schema / properties / depth / descriptionAdded value: +"How many relation hops to traverse (1-3 recommended, maximum: 5)" - removed
Input schema / properties / depth / titleRemoved value: -"Depth" - added
Input schema / properties / max_related / descriptionAdded value: +"Maximum total related results to return (default: 10, maximum: 100)" - removed
Input schema / properties / max_related / titleRemoved value: -"Max Related" - added
Input schema / properties / output_formatAdded value: +{ + "default": "json", + "description": "Response format - \"json\" for structured JSON dict,\n\"text\" for compact markdown text", + "enum": [ + "json", + "text" + ], + "type": "string" +} - added
Input schema / properties / page / descriptionAdded value: +"Page number of results to return (default: 1)" - removed
Input schema / properties / page / titleRemoved value: -"Page" - added
Input schema / properties / page_size / descriptionAdded value: +"Number of primary results to return per page (default: 10, maximum: 50)" - removed
Input schema / properties / page_size / titleRemoved value: -"Page Size" - added
Input schema / properties / project / descriptionAdded value: +"Project name to build context from. Optional - server will resolve using hierarchy.\n If unknown, use list_memory_projects() to discover available projects." - removed
Input schema / properties / project / titleRemoved value: -"Project" - added
Input schema / properties / project_idAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Project external_id (UUID). Prefer this over `project` when known —\n it routes to the exact project regardless of name collisions across cloud\n workspaces. Takes precedence over `project`. Get from list_memory_projects()." +} - added
Input schema / properties / timeframe / descriptionAdded value: +"How far back to look. Supports natural language like \"2 days ago\", \"last week\"" - removed
Input schema / properties / timeframe / titleRemoved value: -"Timeframe" - added
Input schema / properties / url / descriptionAdded value: +"memory:// URI pointing to discussion content (e.g. memory://specs/search),\nor a bare permalink path." - removed
Input schema / properties / url / titleRemoved value: -"Url" - removed
Output schema / $defsRemoved value: -{ - "ContextResult": { - "description": "Context result containing a primary item with its observations and related items.", - "properties": { - "observations": { - "description": "Observations belonging to this entity", - "items": { - "$ref": "#/$defs/ObservationSummary" - }, - "title": "Observations", - "type": "array" - }, - "primary_result": { - "description": "Primary item", - "discriminator": { - "mapping": { - "entity": "#/$defs/EntitySummary", - "observation": "#/$defs/ObservationSummary", - "relation": "#/$defs/RelationSummary" - }, - "propertyName": "type" - }, - "oneOf": [ - { - "$ref": "#/$defs/EntitySummary" - }, - { - "$ref": "#/$defs/RelationSummary" - }, - { - "$ref": "#/$defs/ObservationSummary" - } - ], - "title": "Primary Result" - }, - "related_results": { - "description": "Related items", - "items": { - "discriminator": { - "mapping": { - "entity": "#/$defs/EntitySummary", - "observation": "#/$defs/ObservationSummary", - "relation": "#/$defs/RelationSummary" - }, - "propertyName": "type" - }, - "oneOf": [ - { - "$ref": "#/$defs/EntitySummary" - }, - { - "$ref": "#/$defs/RelationSummary" - }, - { - "$ref": "#/$defs/ObservationSummary" - } - ] - }, - "title": "Related Results", - "type": "array" - } - }, - "required": [ - "primary_result" - ], - "title": "ContextResult", - "type": "object" - }, - "EntitySummary": { - "description": "Simplified entity representation.", - "properties": { - "content": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Content" - }, - "created_at": { - "format": "date-time", - "title": "Created At", - "type": "string" - }, - "entity_id": { - "title": "Entity Id", - "type": "integer" - }, - "file_path": { - "title": "File Path", - "type": "string" - }, - "permalink": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Permalink" - }, - "title": { - "title": "Title", - "type": "string" - }, - "type": { - "const": "entity", - "default": "entity", - "title": "Type", - "type": "string" - } - }, - "required": [ - "entity_id", - "permalink", - "title", - "file_path", - "created_at" - ], - "title": "EntitySummary", - "type": "object" - }, - "MemoryMetadata": { - "description": "Simplified response metadata.", - "properties": { - "depth": { - "title": "Depth", - "type": "integer" - }, - "generated_at": { - "format": "date-time", - "title": "Generated At", - "type": "string" - }, - "primary_count": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Primary Count" - }, - "related_count": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Related Count" - }, - "timeframe": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Timeframe" - }, - "total_observations": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Total Observations" - }, - "total_relations": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Total Relations" - }, - "total_results": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Total Results" - }, - "types": { - "anyOf": [ - { - "items": { - "$ref": "#/$defs/SearchItemType" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Types" - }, - "uri": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Uri" - } - }, - "required": [ - "depth", - "generated_at" - ], - "title": "MemoryMetadata", - "type": "object" - }, - "ObservationSummary": { - "description": "Simplified observation representation.", - "properties": { - "category": { - "title": "Category", - "type": "string" - }, - "content": { - "title": "Content", - "type": "string" - }, - "created_at": { - "format": "date-time", - "title": "Created At", - "type": "string" - }, - "entity_id": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Entity Id" - }, - "file_path": { - "title": "File Path", - "type": "string" - }, - "observation_id": { - "title": "Observation Id", - "type": "integer" - }, - "permalink": { - "title": "Permalink", - "type": "string" - }, - "title": { - "title": "Title", - "type": "string" - }, - "type": { - "const": "observation", - "default": "observation", - "title": "Type", - "type": "string" - } - }, - "required": [ - "observation_id", - "title", - "file_path", - "permalink", - "category", - "content", - "created_at" - ], - "title": "ObservationSummary", - "type": "object" - }, - "RelationSummary": { - "description": "Simplified relation representation.", - "properties": { - "created_at": { - "format": "date-time", - "title": "Created At", - "type": "string" - }, - "entity_id": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Entity Id" - }, - "file_path": { - "title": "File Path", - "type": "string" - }, - "from_entity": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "title": "From Entity" - }, - "from_entity_id": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "default": null, - "title": "From Entity Id" - }, - "permalink": { - "title": "Permalink", - "type": "string" - }, - "relation_id": { - "title": "Relation Id", - "type": "integer" - }, - "relation_type": { - "title": "Relation Type", - "type": "string" - }, - "title": { - "title": "Title", - "type": "string" - }, - "to_entity": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "title": "To Entity" - }, - "to_entity_id": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "default": null, - "title": "To Entity Id" - }, - "type": { - "const": "relation", - "default": "relation", - "title": "Type", - "type": "string" - } - }, - "required": [ - "relation_id", - "title", - "file_path", - "permalink", - "relation_type", - "created_at" - ], - "title": "RelationSummary", - "type": "object" - }, - "SearchItemType": { - "description": "Types of searchable items.", - "enum": [ - "entity", - "observation", - "relation" - ], - "title": "SearchItemType", - "type": "string" - } -} - removed
Output schema / descriptionRemoved value: -"Complete context response." - removed
Output schema / properties / metadataRemoved value: -{ - "$ref": "#/$defs/MemoryMetadata" -} - removed
Output schema / properties / pageRemoved value: -{ - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Page" -} - removed
Output schema / properties / page_sizeRemoved value: -{ - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Page Size" -} - added
Output schema / properties / resultAdded value: +{ + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "string" + } + ] +} - removed
Output schema / properties / resultsRemoved value: -{ - "description": "Hierarchical results with related items nested", - "items": { - "$ref": "#/$defs/ContextResult" - }, - "title": "Results", - "type": "array" -} - changed
Output schema / requiredPrevious value: -[ - "metadata" -]New value: +[ + "result" +] - removed
Output schema / titleRemoved value: -"GraphContext" - added
Output schema / x-fastmcp-wrap-resultAdded value: +true
- Removed
canvas - Added
cat - Changed
create_memory_project13 fields changed- added
Input schema / additionalPropertiesAdded value: +false - added
Input schema / properties / output_formatAdded value: +{ + "default": "text", + "description": "\"text\" returns human-readable result text.\n\"json\" returns structured project creation metadata.", + "enum": [ + "text", + "json" + ], + "type": "string" +} - added
Input schema / properties / project_name / descriptionAdded value: +"Name for the new project (must be unique)" - removed
Input schema / properties / project_name / titleRemoved value: -"Project Name" - added
Input schema / properties / project_path / descriptionAdded value: +"File system path where the project will be stored" - removed
Input schema / properties / project_path / titleRemoved value: -"Project Path" - added
Input schema / properties / set_default / descriptionAdded value: +"Whether to set this project as the default (optional, defaults to False)" - removed
Input schema / properties / set_default / titleRemoved value: -"Set Default" - added
Input schema / properties / workspaceAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional cloud workspace selector to create the project in. Slug is\npreferred for AI callers, but tenant_id and unique name are also accepted.\nWhen omitted, the connection's default workspace is used. Discover values\nvia `list_workspaces`. A workspace selector implies cloud routing:\nwithout cloud credentials the call fails fast instead of silently\ncreating a local project." +} - added
Output schema / properties / result / anyOfAdded value: +[ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "string" + } +] - removed
Output schema / properties / result / titleRemoved value: -"Result" - removed
Output schema / properties / result / typeRemoved value: -"string" - removed
Output schema / titleRemoved value: -"_WrappedResult"
- Changed
delete_note11 fields changed- added
Input schema / additionalPropertiesAdded value: +false - added
Input schema / properties / identifier / descriptionAdded value: +"For files: note title or permalink to delete.\n For directories: the directory path (e.g., \"docs\", \"projects/2025\").\n Can be a title like \"Meeting Notes\" or permalink like \"notes/meeting-notes\"" - removed
Input schema / properties / identifier / titleRemoved value: -"Identifier" - added
Input schema / properties / is_directoryAdded value: +{ + "default": false, + "description": "If True, deletes an entire directory and all its contents.\n When True, identifier should be a directory path\n (without file extensions). Defaults to False.", + "type": "boolean" +} - added
Input schema / properties / output_formatAdded value: +{ + "default": "text", + "description": "\"text\" returns true/false for a single note (false if not found),\na markdown summary for directories, or markdown guidance on error. \"json\"\nreturns machine-readable deletion metadata.", + "enum": [ + "text", + "json" + ], + "type": "string" +} - added
Input schema / properties / project / descriptionAdded value: +"Project name to delete from. Optional - server will resolve using hierarchy.\n If unknown, use list_memory_projects() to discover available projects." - removed
Input schema / properties / project / titleRemoved value: -"Project" - added
Input schema / properties / project_idAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Project external_id (UUID). Prefer this over `project` when known —\n it routes to the exact project regardless of name collisions across cloud\n workspaces. Takes precedence over `project`. Get from list_memory_projects()." +} - changed
Output schema / properties / result / anyOfPrevious value: -[ - { - "type": "boolean" - }, - { - "type": "string" - } -]New value: +[ + { + "type": "boolean" + }, + { + "type": "string" + }, + { + "additionalProperties": true, + "type": "object" + } +] - removed
Output schema / properties / result / titleRemoved value: -"Result" - removed
Output schema / titleRemoved value: -"_WrappedResult"
- Removed
delete_project - Changed
edit_note29 fields changed- added
Input schema / additionalPropertiesAdded value: +false - added
Input schema / properties / content / descriptionAdded value: +"The content to add or use for replacement" - removed
Input schema / properties / content / titleRemoved value: -"Content" - added
Input schema / properties / expected_checksumAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional revision precondition: the full `checksum` that\nread_note, write_note, or edit_note returned in JSON mode (the accepted\nrevision's checksum; text output shows only its first 8 characters). When the\nnote has changed since, the edit is refused with a revision conflict that\nnames the current checksum, and nothing is written. A refused precondition\nnever auto-creates the note. To refresh a stale checksum without reading the\nwhole note, call read_note(identifier=..., include_content=False)." +} - added
Input schema / properties / expected_replacements / anyOfAdded value: +[ + { + "type": "integer" + }, + { + "type": "null" + } +] - changed
Input schema / properties / expected_replacements / defaultPrevious value: -1New value: +null - added
Input schema / properties / expected_replacements / descriptionAdded value: +"For find_replace: required occurrence count of find_text\n(default 1). A mismatch fails without writing." - removed
Input schema / properties / expected_replacements / titleRemoved value: -"Expected Replacements" - removed
Input schema / properties / expected_replacements / typeRemoved value: -"integer" - added
Input schema / properties / find_text / descriptionAdded value: +"For find_replace operation - the exact, case-sensitive text to replace" - removed
Input schema / properties / find_text / titleRemoved value: -"Find Text" - added
Input schema / properties / identifier / descriptionAdded value: +"The exact title, permalink, or memory:// URL of the note to edit.\n Must be an exact match - fuzzy matching is not supported for edit operations.\n Use search_notes() or read_note() first to find the correct identifier if uncertain.\n From the CLI this is a positional argument, not a flag." - removed
Input schema / properties / identifier / titleRemoved value: -"Identifier" - added
Input schema / properties / metadataAdded value: +{ + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional dict of frontmatter fields to merge, independent of `operation`.\nProvided keys overwrite existing frontmatter values (or are added if new);\nunrelated frontmatter keys and the note body are left untouched. Can be\ncombined with any operation in the same call. `title` and `permalink` are\nignored since those have their own dedicated handling; `type` is applied like\nany other frontmatter field. Key deletion is not supported." +} - added
Input schema / properties / operation / descriptionAdded value: +"The editing operation to perform:\n - \"append\": Add content to the end of the note (creates the note if it doesn't exist)\n - \"prepend\": Add content to the beginning of the note (creates the note if it doesn't exist)\n - \"find_replace\": Replace occurrences of find_text with content (note must exist)\n - \"replace_section\": Replace a markdown section identified by its header (note and section must exist).\n The heading must match exactly, including trailing tags or text; a miss fails without writing.\n By default the section spans through the next heading of the same or higher\n level, so its subsections are replaced too; see replace_subsections.\n - \"insert_before_section\": Insert content before a section heading without consuming it (note must exist)\n - \"insert_after_section\": Insert content after a section heading without consuming it (note must exist)" - added
Input schema / properties / operation / enumAdded value: +[ + "append", + "prepend", + "find_replace", + "replace_section", + "insert_before_section", + "insert_after_section" +] - removed
Input schema / properties / operation / titleRemoved value: -"Operation" - added
Input schema / properties / output_formatAdded value: +{ + "default": "text", + "description": "\"text\" returns a markdown summary of the edit and the note's\nresulting observations and relations. \"json\" returns machine-readable edit\nmetadata.", + "enum": [ + "text", + "json" + ], + "type": "string" +} - added
Input schema / properties / project / descriptionAdded value: +"Project name to edit in. Optional - server will resolve using hierarchy.\n Use \"workspace/project\" to route to a project in a specific cloud workspace.\n If unknown, use list_memory_projects() to discover available projects." - removed
Input schema / properties / project / titleRemoved value: -"Project" - added
Input schema / properties / project_idAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Project external_id (UUID). Prefer this over `project` when known —\n it routes to the exact project regardless of name collisions across cloud\n workspaces. Takes precedence over `project`. Get from list_memory_projects()." +} - added
Input schema / properties / replace_subsectionsAdded value: +{ + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "description": "For replace_section operation. Default (true): the section\nspans everything through the next heading of the same or higher level in the\noriginal note, so replacing \"## Section\" also replaces its \"###\" subsections —\nthe replacement content may freely introduce new headings. Set to false to\nreplace only the immediate content under the header, stopping at the next\nheading of any level and preserving subsections." +} - added
Input schema / properties / section / descriptionAdded value: +"Heading for replace_section, insert_before_section, and\ninsert_after_section (e.g. \"## Notes\", \"### Implementation\"). Must match exactly." - removed
Input schema / properties / section / titleRemoved value: -"Section" - added
Input schema / properties / workspaceAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Workspace slug, name, or tenant_id. When provided with `project`,\n routes as `workspace/project`. Cannot be combined with `project_id`." +} - added
Output schema / properties / result / anyOfAdded value: +[ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "string" + } +] - removed
Output schema / properties / result / titleRemoved value: -"Result" - removed
Output schema / properties / result / typeRemoved value: -"string" - removed
Output schema / titleRemoved value: -"_WrappedResult"
- Changed
fetch5 fields changed- added
Input schema / additionalPropertiesAdded value: +false - added
Input schema / properties / id / descriptionAdded value: +"Document identifier (permalink, title, or memory URL)" - removed
Input schema / properties / id / titleRemoved value: -"Id" - removed
Output schema / properties / result / titleRemoved value: -"Result" - removed
Output schema / titleRemoved value: -"_WrappedResult"
- Added
find - Added
grep - Changed
list_directory18 fields changed- added
Input schema / additionalPropertiesAdded value: +false - added
Input schema / properties / depth / descriptionAdded value: +"Recursion depth (1-10, default: 1 for immediate children only)\n Higher values show subdirectory contents recursively" - removed
Input schema / properties / depth / titleRemoved value: -"Depth" - added
Input schema / properties / dir_name / descriptionAdded value: +"Directory path to list (default: root \"/\")\n Examples: \"/\", \"/projects\", \"/research/ml\"" - removed
Input schema / properties / dir_name / titleRemoved value: -"Dir Name" - added
Input schema / properties / file_name_glob / descriptionAdded value: +"Optional glob pattern for filtering file names\n Examples: \"*.md\", \"*meeting*\", \"project_*\"" - removed
Input schema / properties / file_name_glob / titleRemoved value: -"File Name Glob" - added
Input schema / properties / output_formatAdded value: +{ + "default": "text", + "description": "\"text\" for a readable listing or \"json\" for structured pagination data", + "enum": [ + "text", + "json" + ], + "type": "string" +} - added
Input schema / properties / pageAdded value: +{ + "default": 1, + "description": "One-indexed result page (default: 1)", + "type": "integer" +} - added
Input schema / properties / page_sizeAdded value: +{ + "default": 10, + "description": "Number of nodes per page (default: 10, maximum: 200)", + "type": "integer" +} - added
Input schema / properties / project / descriptionAdded value: +"Project name to list directory from. Optional - server will resolve using hierarchy.\n If unknown, use list_memory_projects() to discover available projects." - removed
Input schema / properties / project / titleRemoved value: -"Project" - added
Input schema / properties / project_idAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Project external_id (UUID). Prefer this over `project` when known —\n it routes to the exact project regardless of name collisions across cloud\n workspaces. Takes precedence over `project`. Get from list_memory_projects()." +} - added
Input schema / properties / sortAdded value: +{ + "anyOf": [ + { + "enum": [ + "title_asc", + "title_desc", + "updated_asc", + "updated_desc" + ], + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional file ordering: \"title_asc\", \"title_desc\", \"updated_asc\",\n or \"updated_desc\". Directories remain first." +} - added
Output schema / properties / result / anyOfAdded value: +[ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "string" + } +] - removed
Output schema / properties / result / titleRemoved value: -"Result" - removed
Output schema / properties / result / typeRemoved value: -"string" - removed
Output schema / titleRemoved value: -"_WrappedResult"
- Changed
list_memory_projects6 fields changed- added
Input schema / additionalPropertiesAdded value: +false - added
Input schema / properties / output_formatAdded value: +{ + "default": "text", + "description": "\"text\" returns a human-readable project list.\n\"json\" returns structured project metadata.", + "enum": [ + "text", + "json" + ], + "type": "string" +} - added
Output schema / properties / result / anyOfAdded value: +[ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "string" + } +] - removed
Output schema / properties / result / titleRemoved value: -"Result" - removed
Output schema / properties / result / typeRemoved value: -"string" - removed
Output schema / titleRemoved value: -"_WrappedResult"
- Added
list_workspaces - Added
ls - Added
man - Changed
move_note17 fields changed- added
Input schema / additionalPropertiesAdded value: +false - added
Input schema / properties / destination_folderAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Move the note into this folder, preserving the original filename.\n Mutually exclusive with destination_path. Only for single-file moves." +} - added
Input schema / properties / destination_path / defaultAdded value: +"" - added
Input schema / properties / destination_path / descriptionAdded value: +"For files: new path relative to project root (e.g., \"work/meetings/note.md\")\n For directories: new directory path (e.g., \"archive/docs\")\n Mutually exclusive with destination_folder." - removed
Input schema / properties / destination_path / titleRemoved value: -"Destination Path" - added
Input schema / properties / identifier / descriptionAdded value: +"For files: exact entity identifier (title, permalink, or memory:// URL).\n For directories: the directory path (e.g., \"docs\", \"projects/2025\").\n Must be an exact match - fuzzy matching is not supported for move operations.\n Use search_notes() or list_directory() first to find the correct path if uncertain." - removed
Input schema / properties / identifier / titleRemoved value: -"Identifier" - added
Input schema / properties / is_directoryAdded value: +{ + "default": false, + "description": "If True, moves an entire directory and all its contents.\n When True, identifier and destination_path should be directory paths\n (without file extensions). Defaults to False.", + "type": "boolean" +} - added
Input schema / properties / output_formatAdded value: +{ + "default": "text", + "description": "\"text\" returns a markdown success or failure message. \"json\"\nreturns machine-readable move metadata, with an error code on failure.", + "enum": [ + "text", + "json" + ], + "type": "string" +} - added
Input schema / properties / project / descriptionAdded value: +"Project name to move within. Optional - server will resolve using hierarchy.\n If unknown, use list_memory_projects() to discover available projects." - removed
Input schema / properties / project / titleRemoved value: -"Project" - added
Input schema / properties / project_idAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Project external_id (UUID). Prefer this over `project` when known —\n it routes to the exact project regardless of name collisions across cloud\n workspaces. Takes precedence over `project`. Get from list_memory_projects()." +} - changed
Input schema / requiredPrevious value: -[ - "identifier", - "destination_path" -]New value: +[ + "identifier" +] - added
Output schema / properties / result / anyOfAdded value: +[ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "string" + } +] - removed
Output schema / properties / result / titleRemoved value: -"Result" - removed
Output schema / properties / result / typeRemoved value: -"string" - removed
Output schema / titleRemoved value: -"_WrappedResult"
- Changed
read_content6 fields changed- added
Input schema / additionalPropertiesAdded value: +false - added
Input schema / properties / path / descriptionAdded value: +"The path or permalink to the file. Can be:\n- A regular file path (docs/example.md)\n- A memory URL (memory://docs/example)\n- A permalink (docs/example)" - removed
Input schema / properties / path / titleRemoved value: -"Path" - added
Input schema / properties / project / descriptionAdded value: +"Project name to read from. Optional - server will resolve using hierarchy.\n If unknown, use list_memory_projects() to discover available projects." - removed
Input schema / properties / project / titleRemoved value: -"Project" - added
Input schema / properties / project_idAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Project external_id (UUID). Prefer this over `project` when known —\n it routes to the exact project regardless of name collisions across cloud\n workspaces. Takes precedence over `project`. Get from list_memory_projects()." +}
- Changed
read_note19 fields changed- added
Input schema / additionalPropertiesAdded value: +false - added
Input schema / properties / end_lineAdded value: +{ + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Last document line to read (inclusive); omitted means EOF.\nOut-of-file ranges return empty content; invalid/reversed ranges fail.\nWith either bound, text output is numbered and JSON carries coordinates,\nhas_more, and next_start_line/next_end_line. include_frontmatter does\nnot strip an explicitly addressed range. Edits between calls may shift lines." +} - added
Input schema / properties / identifier / descriptionAdded value: +"The title or permalink of the note to read.\n Can be a full memory:// URL, a permalink, a title, or search text.\n From the CLI this is a positional argument, not a flag." - removed
Input schema / properties / identifier / titleRemoved value: -"Identifier" - added
Input schema / properties / include_contentAdded value: +{ + "default": true, + "description": "Default true. Set to false to return only the note's metadata —\ntitle, permalink, file_path, the full accepted-revision checksum, and\nupdated_at — without the body. Use it to refresh the checksum that\nedit_note/write_note take as expected_checksum without reading the whole\nnote. Cannot be combined with start_line/end_line.", + "type": "boolean" +} - added
Input schema / properties / include_frontmatterAdded value: +{ + "default": false, + "description": "For unsliced JSON reads, include opening YAML in content;\nparsed frontmatter is returned either way. Explicit line ranges are never\nstripped. CLI: --frontmatter (--include-frontmatter is a deprecated alias).", + "type": "boolean" +} - added
Input schema / properties / output_formatAdded value: +{ + "default": "text", + "description": "\"text\" returns markdown content or guidance text.\n\"json\" returns a structured object with title/permalink/file_path/content/frontmatter.\nUnresolved notes carry error=\"NOTE_NOT_FOUND\" and a message, with\nrelated_results when suggestions are available.", + "enum": [ + "text", + "json" + ], + "type": "string" +} - added
Input schema / properties / page / descriptionAdded value: +"Page of fallback-search results to use when the identifier does not\nresolve to a note directly (default: 1). A direct or exact-title match\nreturns the note content — page/page_size never chunk the\nnote itself, and the title-match lookup pages through fixed-size pages\nof title results until an exact match is found or results are\nexhausted, regardless of page or page_size. Aliases: page_number." - removed
Input schema / properties / page / titleRemoved value: -"Page" - added
Input schema / properties / page_size / descriptionAdded value: +"Number of fallback-search results per page (default: 10). When no\nmatch is found, this caps how many related-note suggestions are listed.\nAliases: limit, per_page." - removed
Input schema / properties / page_size / titleRemoved value: -"Page Size" - added
Input schema / properties / project / descriptionAdded value: +"Project name to read from. Optional - when omitted, a project prefix\n on a memory:// URL or permalink identifier routes the read; otherwise the\n server uses the configured default project. If unknown, use\n list_memory_projects() to discover available projects." - removed
Input schema / properties / project / titleRemoved value: -"Project" - added
Input schema / properties / project_idAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Project external_id (UUID). Prefer this over `project` when known —\n it routes to the exact project regardless of name collisions across cloud\n workspaces. Takes precedence over `project`. Get from list_memory_projects()." +} - added
Input schema / properties / start_lineAdded value: +{ + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "description": "First document line to read (1-based, inclusive). Defaults to 1\nwhen only end_line is given. Line scans count the full Markdown,\nincluding frontmatter, matching cat's default line coordinates." +} - added
Output schema / properties / result / anyOfAdded value: +[ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "string" + } +] - removed
Output schema / properties / result / titleRemoved value: -"Result" - removed
Output schema / properties / result / typeRemoved value: -"string" - removed
Output schema / titleRemoved value: -"_WrappedResult"
- Changed
recent_activity17 fields changed- added
Input schema / additionalPropertiesAdded value: +false - added
Input schema / properties / depth / descriptionAdded value: +"How many relation hops to traverse (1-3 recommended, maximum: 5)" - removed
Input schema / properties / depth / titleRemoved value: -"Depth" - added
Input schema / properties / output_formatAdded value: +{ + "default": "text", + "description": "\"text\" returns human-readable summary text. \"json\" returns\na flat list of recent items.", + "enum": [ + "text", + "json" + ], + "type": "string" +} - added
Input schema / properties / pageAdded value: +{ + "default": 1, + "description": "Page number for pagination (default 1)", + "type": "integer" +} - added
Input schema / properties / page_sizeAdded value: +{ + "default": 10, + "description": "Number of items per page (default 10, maximum: 100)", + "type": "integer" +} - added
Input schema / properties / project / descriptionAdded value: +"Project name to query. Optional - when omitted, the server uses the\n configured default project, and discovery mode across all projects\n applies only when there is no default.\n If unknown, use list_memory_projects() to discover available projects." - removed
Input schema / properties / project / titleRemoved value: -"Project" - added
Input schema / properties / project_idAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Project external_id (UUID). Prefer this over `project` when known —\n it routes to the exact project regardless of name collisions across cloud\n workspaces. Takes precedence over `project`. Get from list_memory_projects()." +} - added
Input schema / properties / timeframe / descriptionAdded value: +"Time window to search. Supports natural language:\n- Relative: \"2 days ago\", \"last week\", \"yesterday\"\n- Points in time: \"2024-01-01\", \"January 1st\"\n- Standard format: \"7d\", \"24h\"\nAliases: since, time_range, lookback." - removed
Input schema / properties / timeframe / titleRemoved value: -"Timeframe" - added
Input schema / properties / type / descriptionAdded value: +"Filter by content type(s). Can be a string or list of strings.\nValid options:\n- \"entity\" or [\"entity\"] for knowledge entities\n- \"relation\" or [\"relation\"] for connections between entities\n- \"observation\" or [\"observation\"] for notes and observations\nMultiple types can be combined: [\"entity\", \"relation\"]\nCase-insensitive: \"ENTITY\" and \"entity\" are treated the same.\nDefault is entity-only. Specify other types explicitly to include\nobservations and relations." - removed
Input schema / properties / type / titleRemoved value: -"Type" - added
Output schema / properties / result / anyOfAdded value: +[ + { + "type": "string" + }, + { + "items": { + "additionalProperties": true, + "type": "object" + }, + "type": "array" + } +] - removed
Output schema / properties / result / titleRemoved value: -"Result" - removed
Output schema / properties / result / typeRemoved value: -"string" - removed
Output schema / titleRemoved value: -"_WrappedResult"
- Added
schema_diff - Added
schema_infer - Added
schema_validate - Changed
search5 fields changed- added
Input schema / additionalPropertiesAdded value: +false - added
Input schema / properties / query / descriptionAdded value: +"Search query (full-text syntax supported by `search_notes`)" - removed
Input schema / properties / query / titleRemoved value: -"Query" - removed
Output schema / properties / result / titleRemoved value: -"Result" - removed
Output schema / titleRemoved value: -"_WrappedResult"
- Changed
search_notes41 fields changed- added
Input schema / additionalPropertiesAdded value: +false - added
Input schema / properties / after_date / descriptionAdded value: +"Optional date filter for recent content (e.g., \"1 week\", \"2d\", \"2024-01-01\")" - removed
Input schema / properties / after_date / titleRemoved value: -"After Date" - added
Input schema / properties / categoriesAdded value: +{ + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Observation categories to match exactly (e.g. [\"requirement\"]). Implies\nobservation results unless entity_types is set. Accepts a list, a\ncomma-separated string, or a JSON-array string." +} - added
Input schema / properties / compactAdded value: +{ + "default": false, + "description": "Omit note bodies and matched excerpts from results. Keep identifiers, metadata, relation targets, scores and pagination for discovery, then read selected notes.", + "type": "boolean" +} - added
Input schema / properties / entity_types / descriptionAdded value: +"Knowledge-graph item types to return: \"entity\" (whole notes),\n\"observation\", \"relation\". Defaults to entity, or to observation when categories\nor a valid-time filter is given. Not the frontmatter `type` (use note_types for\nthat). Accepts a list, a comma-separated string, or a JSON-array string." - removed
Input schema / properties / entity_types / titleRemoved value: -"Entity Types" - added
Input schema / properties / metadata_filtersAdded value: +{ + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Structured frontmatter filters, {field: condition}. Nested fields use dot notation (\"schema.confidence\"). Conditions: a value for equality ({\"status\": \"draft\"}); null for absent-or-null ({\"owner\": null}); a list for array-contains-all ({\"tags\": [\"a\", \"b\"]}); or an operator object using $gt, $gte, $lt, $lte, $in (list), $between ([min, max]), $contains (value or list), $exists (true/false), e.g. {\"priority\": {\"$in\": [\"high\"]}}. Several operators on one field AND together: {\"started\": {\"$gte\": \"2026-01-01\", \"$lt\": \"2026-02-01\"}}. The leading $ is optional." +} - added
Input schema / properties / min_similarityAdded value: +{ + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional float to override the global semantic_min_similarity threshold\n for this query. E.g., 0.0 to see all vector results, or 0.8 for high precision.\n Only applies to vector and hybrid search types." +} - added
Input schema / properties / note_typesAdded value: +{ + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Filter by the frontmatter `type` field (e.g. \"note\", \"person\").\nCase-insensitive. Accepts a list, a comma-separated string, or a JSON-array string." +} - added
Input schema / properties / output_formatAdded value: +{ + "default": "text", + "description": "\"text\" returns a formatted markdown result list. \"json\" returns a\nmachine-readable dictionary payload.", + "enum": [ + "text", + "json" + ], + "type": "string" +} - added
Input schema / properties / page / descriptionAdded value: +"The page number of results to return (default 1).\nAliases: page_number." - removed
Input schema / properties / page / titleRemoved value: -"Page" - added
Input schema / properties / page_size / descriptionAdded value: +"The number of results to return per page (default 10).\nAliases: limit, per_page." - removed
Input schema / properties / page_size / titleRemoved value: -"Page Size" - added
Input schema / properties / project / descriptionAdded value: +"Project name to search in. Optional - server will resolve using hierarchy.\n If unknown, use list_memory_projects() to discover available projects." - removed
Input schema / properties / project / titleRemoved value: -"Project" - added
Input schema / properties / project_idAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Project external_id (UUID). Prefer this over `project` when known —\n it routes to the exact project regardless of name collisions across cloud\n workspaces. Takes precedence over `project`. Get from list_memory_projects()." +} - added
Input schema / properties / projectsAdded value: +{ + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional list of project names or external ids to search together. Names\n are matched exactly as list_memory_projects() reports them (cloud projects\n by their workspace-qualified name). Ignored when `project` or `project_id`\n is supplied; an unknown name is an error rather than a silent skip." +} - added
Input schema / properties / query / anyOfAdded value: +[ + { + "type": "string" + }, + { + "type": "null" + } +] - added
Input schema / properties / query / defaultAdded value: +null - added
Input schema / properties / query / descriptionAdded value: +"Optional search query string (supports boolean operators, phrases, patterns).\n Omit or pass None for filter-only searches using metadata_filters, tags, or status." - removed
Input schema / properties / query / titleRemoved value: -"Query" - removed
Input schema / properties / query / typeRemoved value: -"string" - added
Input schema / properties / search_all_projectsAdded value: +{ + "default": false, + "description": "Optional opt-in to search every accessible project. Ignored when\n `project` or `project_id` is supplied.", + "type": "boolean" +} - added
Input schema / properties / search_type / anyOfAdded value: +[ + { + "type": "string" + }, + { + "type": "null" + } +] - changed
Input schema / properties / search_type / defaultPrevious value: -"text"New value: +null - added
Input schema / properties / search_type / descriptionAdded value: +"Type of search to perform, one of:\n \"text\", \"title\", \"permalink\", \"vector\", \"semantic\", \"hybrid\".\n Default is dynamic: \"hybrid\" when semantic search is enabled, otherwise \"text\"." - removed
Input schema / properties / search_type / titleRemoved value: -"Search Type" - removed
Input schema / properties / search_type / typeRemoved value: -"string" - added
Input schema / properties / statusAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional status filter (frontmatter status); shorthand for metadata_filters[\"status\"]" +} - added
Input schema / properties / tagsAdded value: +{ + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional tag filter (frontmatter tags); shorthand for metadata_filters[\"tags\"].\n Accepts a list ([\"a\", \"b\"]) or a comma-separated string (\"a,b\"), matching the\n write_note tags convention and the tag: query shorthand." +} - added
Input schema / properties / time_kindAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional kind of valid time to narrow to: \"effective\", \"valid\",\n \"occurred\", \"due\", or \"mentioned\". Valid on its own. Alias: kind." +} - removed
Input schema / properties / typesRemoved value: -{ - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Types" -} - added
Input schema / properties / valid_atAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional date (\"2026-07-28\") or RFC 3339 instant (\"2026-07-28T09:00:00Z\";\n a timestamp with no offset is read as UTC). Returns sources whose authored\n valid range contains it. Sources with no temporal qualifier are excluded.\n Aliases: as_of, valid_on." +} - added
Input schema / properties / valid_overlapsAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional PostgreSQL-style range literal (\"[2026-06-10,2026-07-27)\",\n \"(,2026-07-27]\", \"[2026-06-10,)\"). Returns sources whose authored valid range\n overlaps it. Mutually exclusive with valid_at; also excludes undated sources.\n Aliases: overlaps, valid_during." +} - removed
Input schema / requiredRemoved value: -[ - "query" -] - removed
Output schema / $defsRemoved value: -{ - "SearchItemType": { - "description": "Types of searchable items.", - "enum": [ - "entity", - "observation", - "relation" - ], - "title": "SearchItemType", - "type": "string" - }, - "SearchResponse": { - "description": "Wrapper for search results.", - "properties": { - "current_page": { - "title": "Current Page", - "type": "integer" - }, - "page_size": { - "title": "Page Size", - "type": "integer" - }, - "results": { - "items": { - "$ref": "#/$defs/SearchResult" - }, - "title": "Results", - "type": "array" - } - }, - "required": [ - "results", - "current_page", - "page_size" - ], - "title": "SearchResponse", - "type": "object" - }, - "SearchResult": { - "description": "Search result with score and metadata.", - "properties": { - "category": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Category" - }, - "content": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Content" - }, - "entity": { - "anyOf": [ - { - "minLength": 1, - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Entity" - }, - "entity_id": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Entity Id" - }, - "file_path": { - "title": "File Path", - "type": "string" - }, - "from_entity": { - "anyOf": [ - { - "minLength": 1, - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "title": "From Entity" - }, - "metadata": { - "anyOf": [ - { - "additionalProperties": true, - "type": "object" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Metadata" - }, - "observation_id": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Observation Id" - }, - "permalink": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Permalink" - }, - "relation_id": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Relation Id" - }, - "relation_type": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Relation Type" - }, - "score": { - "title": "Score", - "type": "number" - }, - "title": { - "title": "Title", - "type": "string" - }, - "to_entity": { - "anyOf": [ - { - "minLength": 1, - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "title": "To Entity" - }, - "type": { - "$ref": "#/$defs/SearchItemType" - } - }, - "required": [ - "title", - "type", - "score", - "permalink", - "file_path" - ], - "title": "SearchResult", - "type": "object" - } -} - changed
Output schema / properties / result / anyOfPrevious value: -[ - { - "$ref": "#/$defs/SearchResponse" - }, - { - "type": "string" - } -]New value: +[ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "string" + } +] - removed
Output schema / properties / result / titleRemoved value: -"Result" - removed
Output schema / titleRemoved value: -"_WrappedResult"
- Added
tail - Changed
view_note10 fields changed- added
Input schema / additionalPropertiesAdded value: +false - added
Input schema / properties / identifier / descriptionAdded value: +"The title or permalink of the note to view" - removed
Input schema / properties / identifier / titleRemoved value: -"Identifier" - removed
Input schema / properties / pageRemoved value: -{ - "default": 1, - "title": "Page", - "type": "integer" -} - removed
Input schema / properties / page_sizeRemoved value: -{ - "default": 10, - "title": "Page Size", - "type": "integer" -} - added
Input schema / properties / project / descriptionAdded value: +"Project name to read from. Optional - server will resolve using hierarchy.\n If unknown, use list_memory_projects() to discover available projects." - removed
Input schema / properties / project / titleRemoved value: -"Project" - added
Input schema / properties / project_idAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Project external_id (UUID). Prefer this over `project` when known —\n it routes to the exact project regardless of name collisions across cloud\n workspaces. Takes precedence over `project`. Get from list_memory_projects()." +} - removed
Output schema / properties / result / titleRemoved value: -"Result" - removed
Output schema / titleRemoved value: -"_WrappedResult"
- Changed
write_note24 fields changed- added
Input schema / additionalPropertiesAdded value: +false - added
Input schema / properties / content / descriptionAdded value: +"Markdown content for the note, can include observations and relations.\nMay carry its own frontmatter; a `type:` in content frontmatter takes\nprecedence over the note_type parameter." - removed
Input schema / properties / content / titleRemoved value: -"Content" - added
Input schema / properties / directoryAdded value: +{ + "description": "Directory path relative to project root where the file should be saved.\n Use forward slashes (/) as separators. Use \"/\" or \"\" to write to project root.\n Examples: \"notes\", \"projects/2025\", \"research/ml\", \"/\" (root).\n MCP accepts the aliases folder, dir, and path; the CLI flag is --folder.", + "type": "string" +} - added
Input schema / properties / expected_checksumAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional revision precondition for overwrite=True: the checksum\n of the note you read (from a JSON read_note, write_note or edit_note\n result). The\n note is replaced only while it is still that revision; otherwise the\n tool reports a revision conflict with the current checksum and changes\n nothing. Omit it to replace the note unconditionally." +} - removed
Input schema / properties / folderRemoved value: -{ - "title": "Folder", - "type": "string" -} - added
Input schema / properties / metadataAdded value: +{ + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional dict of extra frontmatter fields merged into entity_metadata.\n Useful for schema notes or any note that needs custom YAML frontmatter\n beyond title/type/tags. Nested dicts are supported. Not available from the CLI." +} - added
Input schema / properties / note_type / descriptionAdded value: +"Type of note to create (stored in frontmatter `type:`). Defaults to \"note\".\n Can be \"guide\", \"report\", \"config\", \"person\", etc. The CLI flag is --type.\n A `type:` in content frontmatter takes precedence over this parameter, and\n this is what schema validation keys on." - removed
Input schema / properties / note_type / titleRemoved value: -"Note Type" - added
Input schema / properties / output_formatAdded value: +{ + "default": "text", + "description": "\"text\" returns a markdown summary. \"json\" returns\n machine-readable metadata. A refused write (note exists, revision\n conflict, moved target, disallowed directory) is a tool error; in\n JSON mode its message is the payload with action: \"conflict\" and an\n error code.", + "enum": [ + "text", + "json" + ], + "type": "string" +} - added
Input schema / properties / overwriteAdded value: +{ + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "description": "If True, replace existing note on conflict. If False, error on conflict.\n If None (default), consult write_note_overwrite_default config setting.\n Overwrite replaces the body but merges frontmatter: keys the existing\n note has and this write does not set (custom fields) are kept, while\n keys this write sets (title, type, tags, metadata, or frontmatter in\n content) replace the old values. Existing frontmatter that cannot be\n parsed is discarded rather than merged. To remove a key, rewrite it\n with edit_note or edit the file." +} - added
Input schema / properties / project / descriptionAdded value: +"Project name to write to. Optional. Omitting both project and project_id\n writes to the configured default project. Calls do not remember a\n project between them, so after working in another project, pass project\n explicitly. Use\n \"workspace/project\" to route to a project in a specific cloud workspace.\n A bare name that exists in multiple workspaces resolves to the default\n workspace, so use the qualified form (or project_id) to disambiguate. If\n unknown, use list_memory_projects() to discover available projects and\n their qualified names." - removed
Input schema / properties / project / titleRemoved value: -"Project" - added
Input schema / properties / project_idAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Project external_id (UUID). Prefer this over `project` when known —\n it routes to the exact project regardless of name collisions across cloud\n workspaces. Takes precedence over `project`. Get from list_memory_projects()." +} - added
Input schema / properties / tags / descriptionAdded value: +"Tags to categorize the note. Can be a list of strings, a comma-separated string, or None.\n Note: If passing from external MCP clients, use a string format (e.g. \"tag1,tag2,tag3\")" - removed
Input schema / properties / tags / titleRemoved value: -"Tags" - added
Input schema / properties / title / descriptionAdded value: +"The title of the note; written to frontmatter and drives the permalink.\nNo H1 is added for you: content is saved as given, so include a\n\"# Title\" heading yourself if the note should open with one." - removed
Input schema / properties / title / titleRemoved value: -"Title" - added
Input schema / properties / workspaceAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Workspace slug, name, or tenant_id. When provided with `project`,\n routes as `workspace/project`. Cannot be combined with `project_id`." +} - changed
Input schema / requiredPrevious value: -[ - "title", - "content", - "folder" -]New value: +[ + "title", + "content", + "directory" +] - added
Output schema / properties / result / anyOfAdded value: +[ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "string" + } +] - removed
Output schema / properties / result / titleRemoved value: -"Result" - removed
Output schema / properties / result / typeRemoved value: -"string" - removed
Output schema / titleRemoved value: -"_WrappedResult"
11 tool updates
v1.0.0- Changed
build_context12 fields changed- removed
Input schema / $defsRemoved value: -{ - "StringOrInt": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "integer" - } - ] - } -} - changed
Input schema / properties / depth / anyOfPrevious value: -[ - { - "$ref": "#/$defs/StringOrInt" - }, - { - "type": "null" - } -]New value: +[ + { + "type": "string" + }, + { + "type": "integer" + }, + { + "type": "null" + } +] - added
Output schema / $defs / EntitySummary / properties / entity_idAdded value: +{ + "title": "Entity Id", + "type": "integer" +} - changed
Output schema / $defs / EntitySummary / requiredPrevious value: -[ - "permalink", - "title", - "file_path", - "created_at" -]New value: +[ + "entity_id", + "permalink", + "title", + "file_path", + "created_at" +] - added
Output schema / $defs / ObservationSummary / properties / entity_idAdded value: +{ + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Entity Id" +} - added
Output schema / $defs / ObservationSummary / properties / observation_idAdded value: +{ + "title": "Observation Id", + "type": "integer" +} - changed
Output schema / $defs / ObservationSummary / requiredPrevious value: -[ - "title", - "file_path", - "permalink", - "category", - "content", - "created_at" -]New value: +[ + "observation_id", + "title", + "file_path", + "permalink", + "category", + "content", + "created_at" +] - added
Output schema / $defs / RelationSummary / properties / entity_idAdded value: +{ + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Entity Id" +} - added
Output schema / $defs / RelationSummary / properties / from_entity_idAdded value: +{ + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "From Entity Id" +} - added
Output schema / $defs / RelationSummary / properties / relation_idAdded value: +{ + "title": "Relation Id", + "type": "integer" +} - added
Output schema / $defs / RelationSummary / properties / to_entity_idAdded value: +{ + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "To Entity Id" +} - changed
Output schema / $defs / RelationSummary / requiredPrevious value: -[ - "title", - "file_path", - "permalink", - "relation_type", - "created_at" -]New value: +[ + "relation_id", + "title", + "file_path", + "permalink", + "relation_type", + "created_at" +]
- Added
fetch - Removed
get_current_project - Changed
list_memory_projects1 field changed- removed
Input schema / properties / _compatibilityRemoved value: -{ - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Compatibility" -}
- Changed
recent_activity13 fields changed- removed
Input schema / properties / max_relatedRemoved value: -{ - "default": 10, - "title": "Max Related", - "type": "integer" -} - removed
Input schema / properties / pageRemoved value: -{ - "default": 1, - "title": "Page", - "type": "integer" -} - removed
Input schema / properties / page_sizeRemoved value: -{ - "default": 10, - "title": "Page Size", - "type": "integer" -} - removed
Output schema / $defsRemoved value: -{ - "ContextResult": { - "description": "Context result containing a primary item with its observations and related items.", - "properties": { - "observations": { - "description": "Observations belonging to this entity", - "items": { - "$ref": "#/$defs/ObservationSummary" - }, - "title": "Observations", - "type": "array" - }, - "primary_result": { - "description": "Primary item", - "discriminator": { - "mapping": { - "entity": "#/$defs/EntitySummary", - "observation": "#/$defs/ObservationSummary", - "relation": "#/$defs/RelationSummary" - }, - "propertyName": "type" - }, - "oneOf": [ - { - "$ref": "#/$defs/EntitySummary" - }, - { - "$ref": "#/$defs/RelationSummary" - }, - { - "$ref": "#/$defs/ObservationSummary" - } - ], - "title": "Primary Result" - }, - "related_results": { - "description": "Related items", - "items": { - "discriminator": { - "mapping": { - "entity": "#/$defs/EntitySummary", - "observation": "#/$defs/ObservationSummary", - "relation": "#/$defs/RelationSummary" - }, - "propertyName": "type" - }, - "oneOf": [ - { - "$ref": "#/$defs/EntitySummary" - }, - { - "$ref": "#/$defs/RelationSummary" - }, - { - "$ref": "#/$defs/ObservationSummary" - } - ] - }, - "title": "Related Results", - "type": "array" - } - }, - "required": [ - "primary_result" - ], - "title": "ContextResult", - "type": "object" - }, - "EntitySummary": { - "description": "Simplified entity representation.", - "properties": { - "content": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Content" - }, - "created_at": { - "format": "date-time", - "title": "Created At", - "type": "string" - }, - "file_path": { - "title": "File Path", - "type": "string" - }, - "permalink": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Permalink" - }, - "title": { - "title": "Title", - "type": "string" - }, - "type": { - "const": "entity", - "default": "entity", - "title": "Type", - "type": "string" - } - }, - "required": [ - "permalink", - "title", - "file_path", - "created_at" - ], - "title": "EntitySummary", - "type": "object" - }, - "MemoryMetadata": { - "description": "Simplified response metadata.", - "properties": { - "depth": { - "title": "Depth", - "type": "integer" - }, - "generated_at": { - "format": "date-time", - "title": "Generated At", - "type": "string" - }, - "primary_count": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Primary Count" - }, - "related_count": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Related Count" - }, - "timeframe": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Timeframe" - }, - "total_observations": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Total Observations" - }, - "total_relations": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Total Relations" - }, - "total_results": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Total Results" - }, - "types": { - "anyOf": [ - { - "items": { - "$ref": "#/$defs/SearchItemType" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Types" - }, - "uri": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Uri" - } - }, - "required": [ - "depth", - "generated_at" - ], - "title": "MemoryMetadata", - "type": "object" - }, - "ObservationSummary": { - "description": "Simplified observation representation.", - "properties": { - "category": { - "title": "Category", - "type": "string" - }, - "content": { - "title": "Content", - "type": "string" - }, - "created_at": { - "format": "date-time", - "title": "Created At", - "type": "string" - }, - "file_path": { - "title": "File Path", - "type": "string" - }, - "permalink": { - "title": "Permalink", - "type": "string" - }, - "title": { - "title": "Title", - "type": "string" - }, - "type": { - "const": "observation", - "default": "observation", - "title": "Type", - "type": "string" - } - }, - "required": [ - "title", - "file_path", - "permalink", - "category", - "content", - "created_at" - ], - "title": "ObservationSummary", - "type": "object" - }, - "RelationSummary": { - "description": "Simplified relation representation.", - "properties": { - "created_at": { - "format": "date-time", - "title": "Created At", - "type": "string" - }, - "file_path": { - "title": "File Path", - "type": "string" - }, - "from_entity": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "title": "From Entity" - }, - "permalink": { - "title": "Permalink", - "type": "string" - }, - "relation_type": { - "title": "Relation Type", - "type": "string" - }, - "title": { - "title": "Title", - "type": "string" - }, - "to_entity": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "title": "To Entity" - }, - "type": { - "const": "relation", - "default": "relation", - "title": "Type", - "type": "string" - } - }, - "required": [ - "title", - "file_path", - "permalink", - "relation_type", - "created_at" - ], - "title": "RelationSummary", - "type": "object" - }, - "SearchItemType": { - "description": "Types of searchable items.", - "enum": [ - "entity", - "observation", - "relation" - ], - "title": "SearchItemType", - "type": "string" - } -} - removed
Output schema / descriptionRemoved value: -"Complete context response." - removed
Output schema / properties / metadataRemoved value: -{ - "$ref": "#/$defs/MemoryMetadata" -} - removed
Output schema / properties / pageRemoved value: -{ - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Page" -} - removed
Output schema / properties / page_sizeRemoved value: -{ - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Page Size" -} - added
Output schema / properties / resultAdded value: +{ + "title": "Result", + "type": "string" +} - removed
Output schema / properties / resultsRemoved value: -{ - "description": "Hierarchical results with related items nested", - "items": { - "$ref": "#/$defs/ContextResult" - }, - "title": "Results", - "type": "array" -} - changed
Output schema / requiredPrevious value: -[ - "metadata" -]New value: +[ + "result" +] - changed
Output schema / titlePrevious value: -"GraphContext"New value: +"_WrappedResult" - added
Output schema / x-fastmcp-wrap-resultAdded value: +true
- Added
search - Changed
search_notes3 fields changed- added
Output schema / $defs / SearchResult / properties / entity_idAdded value: +{ + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Entity Id" +} - added
Output schema / $defs / SearchResult / properties / observation_idAdded value: +{ + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Observation Id" +} - added
Output schema / $defs / SearchResult / properties / relation_idAdded value: +{ + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Relation Id" +}
- Removed
set_default_project - Removed
switch_project - Removed
sync_status - Changed
write_note3 fields changed- removed
Input schema / properties / entity_typeRemoved value: -{ - "default": "note", - "title": "Entity Type", - "type": "string" -} - added
Input schema / properties / note_typeAdded value: +{ + "default": "note", + "title": "Note Type", + "type": "string" +} - added
Input schema / properties / tags / anyOfAdded value: +[ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "string" + }, + { + "type": "null" + } +]
2 tool updates
- Changed
build_context11 fields changed- added
Input schema / $defsAdded value: +{ + "StringOrInt": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "integer" + } + ] + } +} - changed
Input schema / properties / depth / anyOfPrevious value: -[ - { - "type": "integer" - }, - { - "type": "null" - } -]New value: +[ + { + "$ref": "#/$defs/StringOrInt" + }, + { + "type": "null" + } +] - removed
Output schema / $defs / ContextResult / properties / primary_result / anyOfRemoved value: -[ - { - "$ref": "#/$defs/EntitySummary" - }, - { - "$ref": "#/$defs/RelationSummary" - }, - { - "$ref": "#/$defs/ObservationSummary" - } -] - added
Output schema / $defs / ContextResult / properties / primary_result / discriminatorAdded value: +{ + "mapping": { + "entity": "#/$defs/EntitySummary", + "observation": "#/$defs/ObservationSummary", + "relation": "#/$defs/RelationSummary" + }, + "propertyName": "type" +} - added
Output schema / $defs / ContextResult / properties / primary_result / oneOfAdded value: +[ + { + "$ref": "#/$defs/EntitySummary" + }, + { + "$ref": "#/$defs/RelationSummary" + }, + { + "$ref": "#/$defs/ObservationSummary" + } +] - removed
Output schema / $defs / ContextResult / properties / related_results / items / anyOfRemoved value: -[ - { - "$ref": "#/$defs/EntitySummary" - }, - { - "$ref": "#/$defs/RelationSummary" - }, - { - "$ref": "#/$defs/ObservationSummary" - } -] - added
Output schema / $defs / ContextResult / properties / related_results / items / discriminatorAdded value: +{ + "mapping": { + "entity": "#/$defs/EntitySummary", + "observation": "#/$defs/ObservationSummary", + "relation": "#/$defs/RelationSummary" + }, + "propertyName": "type" +} - added
Output schema / $defs / ContextResult / properties / related_results / items / oneOfAdded value: +[ + { + "$ref": "#/$defs/EntitySummary" + }, + { + "$ref": "#/$defs/RelationSummary" + }, + { + "$ref": "#/$defs/ObservationSummary" + } +] - added
Output schema / $defs / EntitySummary / properties / type / constAdded value: +"entity" - added
Output schema / $defs / ObservationSummary / properties / type / constAdded value: +"observation" - added
Output schema / $defs / RelationSummary / properties / type / constAdded value: +"relation"
- Changed
recent_activity9 fields changed- removed
Output schema / $defs / ContextResult / properties / primary_result / anyOfRemoved value: -[ - { - "$ref": "#/$defs/EntitySummary" - }, - { - "$ref": "#/$defs/RelationSummary" - }, - { - "$ref": "#/$defs/ObservationSummary" - } -] - added
Output schema / $defs / ContextResult / properties / primary_result / discriminatorAdded value: +{ + "mapping": { + "entity": "#/$defs/EntitySummary", + "observation": "#/$defs/ObservationSummary", + "relation": "#/$defs/RelationSummary" + }, + "propertyName": "type" +} - added
Output schema / $defs / ContextResult / properties / primary_result / oneOfAdded value: +[ + { + "$ref": "#/$defs/EntitySummary" + }, + { + "$ref": "#/$defs/RelationSummary" + }, + { + "$ref": "#/$defs/ObservationSummary" + } +] - removed
Output schema / $defs / ContextResult / properties / related_results / items / anyOfRemoved value: -[ - { - "$ref": "#/$defs/EntitySummary" - }, - { - "$ref": "#/$defs/RelationSummary" - }, - { - "$ref": "#/$defs/ObservationSummary" - } -] - added
Output schema / $defs / ContextResult / properties / related_results / items / discriminatorAdded value: +{ + "mapping": { + "entity": "#/$defs/EntitySummary", + "observation": "#/$defs/ObservationSummary", + "relation": "#/$defs/RelationSummary" + }, + "propertyName": "type" +} - added
Output schema / $defs / ContextResult / properties / related_results / items / oneOfAdded value: +[ + { + "$ref": "#/$defs/EntitySummary" + }, + { + "$ref": "#/$defs/RelationSummary" + }, + { + "$ref": "#/$defs/ObservationSummary" + } +] - added
Output schema / $defs / EntitySummary / properties / type / constAdded value: +"entity" - added
Output schema / $defs / ObservationSummary / properties / type / constAdded value: +"observation" - added
Output schema / $defs / RelationSummary / properties / type / constAdded value: +"relation"
19 tool updates
- First observed
build_context - First observed
canvas - First observed
create_memory_project - First observed
delete_note - First observed
delete_project - First observed
edit_note - First observed
get_current_project - First observed
list_directory - First observed
list_memory_projects - First observed
move_note - First observed
read_content - First observed
read_note - First observed
recent_activity - First observed
search_notes - First observed
set_default_project - First observed
switch_project - First observed
sync_status - First observed
view_note - First observed
write_note
TDQS
Scored across 12 tools
There is real overlap among three retrieval tools (bm_find, bm_list, bm_search), but the descriptions explicitly route the agent: bm_list for one folder, bm_find for recursive name/frontmatter matching, bm_search for ranked text/semantic search. Similarly bm_read (one note body) is distinguished from bm_context (graph traversal) and bm_write (full replace) from bm_edit (partial change). Only a small chance of misselection remains for an agent skimming names.
All 12 tools follow a single predictable bm_<word> snake_case pattern with no style mixing. Most suffixes are verbs (find, list, read, write, edit, move, delete, search), but a few are nouns/commands (bm_context, bm_schema, bm_project, bm_man), which is a minor deviation rather than an inconsistency.
Twelve tools sit comfortably in the well-scoped range and each maps to a distinct capability: directory listing, find, search, read, write, edit, move, delete, graph context, schema ops, project ops, and docs. None look like padding, and the surface is not so thin that agents would have to chain workarounds.
Note lifecycle is fully covered (create/replace, read, partial edit, move, delete, plus graph context and search), and bm_schema and bm_project cover schema and project management. Minor gaps: bm_project only supports list/create/recent (no rename or delete of projects), and there is no copy/duplicate operation, though the description notes the read+write+delete workaround.
Maintenance
Related MCP Connectors
Personal wiki and memory layer for AI assistants. Persistent, structured memory across sessions.
- ContextaOAuthcc.contexta
Persistent memory and knowledge graph for AI assistants — keyword + vector + graph search.
Persistent, portable memory for AI assistants — your private memory graph, from any MCP client.
Persistent memory for AI agents. Semantic search, memory graph, W3C DID identity.
Related MCP Servers
- AlicenseNot gradedqualityFmaintenanceProvides persistent memory functionality for AI conversations by creating, managing and querying entities and relationships in a knowledge graph. Features SQLite storage, advanced search capabilities, and Windows auto-start integration for long-term AI memory retention.41 npmMIT
- AlicenseAqualityAmaintenancePersistent memory with knowledge graph visualization, semantic/hybrid search, importance scoring, and cloud sync (S3/R2) for cross-session context management.44746MIT
- AlicenseNot gradedqualityCmaintenanceProvides persistent memory for AI tools by building a local knowledge graph from conversations, enabling cross-session recall and context awareness without cloud dependencies.9MIT
- AlicenseNot gradedqualityAmaintenanceEnables AI agents to share persistent, self-improving memory by ingesting, classifying, synthesizing, and retrieving knowledge from Obsidian vaults, code, documents, transcripts, bookmarks, and sessions through MCP and REST interfaces with token-optimized search.14 npmMIT