MemDrive
Uses a Google Drive sync folder as the library root, allowing the MCP server to read and write Markdown notes and assets locally while the Google Drive client handles cloud syncing.
Uses an iCloud sync folder as the library root, allowing the MCP server to read and write Markdown notes and assets locally while iCloud handles syncing.
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., "@MemDrivesave a note that my dentist appointment is May 12 at 3pm"
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.
MemDrive
An MCP server that gives LLMs persistent memory on your own storage: a
local folder (Google Drive / OneDrive / iCloud sync folder, or any plain
directory) today. WebDAV (NAS, Nextcloud, Alist/Rclone) is
interface-reserved behind the StorageBackend interface but not
implemented; whether it is implemented later depends on user
feedback, and it will only be considered if the user base is large
with clear demand.
The model reads and writes Markdown + a sibling assets/ image folder
through six small tools. No cloud service, no account, no server to run —
the MCP server runs on your own machine and touches only the folder you
point it at.
Status: MVP 0.6.0. Local filesystem backend only. WebDAV is interface-reserved behind the
StorageBackendinterface but not implemented. Whether it is implemented later depends on user feedback, and it will only be considered if the user base is large with clear demand. 0.1.1 added one total response budget toread_file(see Reading back and Limits) and put the clipboard rule first in thesave_filetool description. 0.1.2 fixes the preview ladder so previews use the budget instead of stopping at the first coarse shrink step (see TEST-REPORT.md §7). 0.1.3 tries higher JPEG quality at full resolution before shrinking, states the three limit layers (host / server / model) in theread_filetool description, and adds CHANGELOG.md (see TEST-REPORT.md §8). 0.2.0 addsopen_image(open an original image in the OS viewer, only when the user explicitly asks) and a setup wizard that finds a sync folder and writes the Claude Desktop config for you (see Setup and TEST-REPORT.md §9). 0.3.0 adds a Cursor adapter to the wizard: the wizard asks which host to configure first and writes Cursor's global config (~/.cursor/mcp.json) as well (see TEST-REPORT.md §12). 0.4.0 adds a VS Code adapter (Copilot Global config,~/.copilot/mcp-config.json) and a per-host response budget written by the wizard into each host's config (see TEST-REPORT.md §13). 0.5.0 raises the Cursor budget to 10,000,000 on the 2026-10-30 verified read and addsopen_containing_folder(open a note's folder in the OS file manager, only when the user explicitly asks, no highlight or selection — see TEST-REPORT.md §14). 0.6.0 adds a Claude Code adapter to the wizard (user scope,~/.claude.jsontop-levelmcpServers, budget 10,000,000) — UNVERIFIED on a real machine, budget estimated by the author's decision, not measured; see Claude Code config and TEST-REPORT.md §17.
Quick start
Requires Node.js 18+.
Easiest — setup wizard (recommended for first install). Download the release zip, extract it, and run the launcher for your system (it installs dependencies, builds, and starts the wizard, which asks which host to configure and which folder to use, and writes the Claude Desktop, Cursor, VS Code, or Claude Code config):
Windows: double-click
setup.batmacOS: double-click
setup.command(or run./setup.shin a terminal)Linux: run
./setup.shin a terminal
The wizard needs Node.js 18+ already installed; if it is missing, the launcher says so and offers to open https://nodejs.org for you. It never installs anything silently and never changes a config file without backing it up first (see Setup).
# Run without installing (after this package is published to npm):
npx -y memdrive-mcp
# Or from a checkout:
npm install
npm run build
node dist/index.jsThe library root defaults to ~/memdrive (created automatically).
Override it with MEMDRIVE_ROOT:
MEMDRIVE_ROOT=~/Documents/memory npx -y memdrive-mcpRelated MCP server: mor
Claude Desktop config
The setup wizard (see Setup) writes this for you. Only edit it by hand if the wizard could not find your config file — it then prints a ready-to-paste snippet instead.
Add this to your Claude Desktop config file (claude_desktop_config.json):
{
"mcpServers": {
"memdrive": {
"command": "npx",
"args": ["-y", "memdrive-mcp"],
"env": {
"MEMDRIVE_ROOT": "/Users/you/Library/CloudStorage/GoogleDrive-you@example.com/My Drive/memory"
}
}
}
}Point MEMDRIVE_ROOT at a folder your sync client already manages and the
official client syncs everything to the cloud in the background — MemDrive
itself does zero network auth and zero uploads.
On Windows use a Windows path (C:\\Users\\you\\OneDrive\\memory); on
macOS/Linux use a POSIX path. Restart Claude Desktop after editing the
config.
Cursor config
The setup wizard (see Setup) writes this
for you, in Cursor's global config file: %USERPROFILE%\.cursor\mcp.json
on Windows, ~/.cursor/mcp.json on macOS/Linux. If that file does not
exist yet but the .cursor directory does, the wizard creates it (no
backup is needed — there is nothing to back up); if the directory does
not exist, the wizard writes nothing and prints a ready-to-paste snippet
instead. Project-level .cursor/mcp.json files are not written: the
global config makes the server available in every project. Only the
Windows path has been verified on a real machine; the macOS/Linux
paths use the same home-based logic and are marked untested.
{
"mcpServers": {
"memdrive": {
"type": "stdio",
"command": "node",
"args": ["/absolute/path/to/memdrive-mcp/dist/index.js"],
"env": {
"MEMDRIVE_ROOT": "/absolute/path/to/your/library",
"MEMDRIVE_RESPONSE_BUDGET_BYTES": "10000000"
}
}
}
}The type: "stdio" field is required by Cursor; Claude Desktop entries
carry no type field. The wizard writes the 10,000,000-byte budget
above into Cursor's entry (see
Limits for the evidence:
verified 2026-10-30, exact ceiling unmeasured). Restart Cursor after
editing the config, and make sure the server is enabled in Cursor's
MCP settings. Cursor's MCP logs (Output panel → "MCP Logs") are the
first place to look when a tool does not appear.
VS Code config
The setup wizard (see Setup) writes this
for you, in VS Code's Copilot Global config file:
%USERPROFILE%\.copilot\mcp-config.json on Windows,
~/.copilot/mcp-config.json on macOS/Linux. If that file does not
exist yet but the .copilot directory does, the wizard creates it (no
backup is needed — there is nothing to back up); if the directory does
not exist, the wizard writes nothing and prints a ready-to-paste snippet
instead. Only the Windows path has been verified on a real machine; the
macOS/Linux paths use the same home-based logic and are marked untested.
The COPILOT_HOME environment variable is not read — only the
home-directory location above is used.
{
"mcpServers": {
"memdrive": {
"type": "stdio",
"command": "node",
"args": ["/absolute/path/to/memdrive-mcp/dist/index.js"],
"env": {
"MEMDRIVE_ROOT": "/absolute/path/to/your/library",
"MEMDRIVE_RESPONSE_BUDGET_BYTES": "10000000"
}
}
}
}The entry shape above was verified on a real Windows machine (manual
MCP: Add Server flow, Copilot Global config): top-level
mcpServers, type: "stdio", command: "node", absolute
dist/index.js args, and VS Code's own "tools": ["*"] field
alongside them. When the wizard merges into an existing entry, that
tools field is preserved, as are every other key and every other
server; a freshly created entry gets no tools field. The wizard
writes the 10,000,000-byte budget above into VS Code's entry (see
Limits for the evidence:
partly verified, exact ceiling unmeasured). Fully quit and restart
VS Code after editing the config, and make sure the server is enabled
in VS Code's MCP settings. VS Code's MCP logs are the first place to
look when a tool does not appear. Only list_directory and a bundled
image read have been verified in VS Code on a real machine so far;
the other tools still need a real-machine check (see
Roadmap).
Claude Code config
UNVERIFIED — read this first. The Claude Code adapter was added from Anthropic's official docs only (checked 2026-10-31) and has never been tested on a real machine, in any host. The 10,000,000-byte budget below is an estimate set by the author's decision (Claude Code is a paid product; a limit as stingy as Claude Desktop's would make no sense for paying users), not a measurement. If a bundled read fails or comes back truncated in Claude Code, please report the exact error — that report is how the default gets corrected.
The setup wizard (see Setup) writes
this for you, in Claude Code's user scope: the top-level
mcpServers key of the one ~/.claude.json file
(%USERPROFILE%\.claude.json on Windows,
~/.claude.json on macOS/Linux). When CLAUDE_CONFIG_DIR is
set, the file lives inside that directory instead. Local scope
(per-project entries inside the same file) and project scope
(.mcp.json in a project root) are not written: the wizard
writes the user-global config only, so the server is available
in every project. If ~/.claude.json does not exist, the wizard
writes nothing and prints a ready-to-paste snippet instead — it
never creates the file, because ~/.claude.json is Claude
Code's own main state file (it also holds project records),
not a dedicated MCP file, and creating a bare copy was never
verified.
{
"mcpServers": {
"memdrive": {
"command": "node",
"args": ["/absolute/path/to/memdrive-mcp/dist/index.js"],
"env": {
"MEMDRIVE_ROOT": "/absolute/path/to/your/library",
"MEMDRIVE_RESPONSE_BUDGET_BYTES": "10000000"
}
}
}
}The entry carries no type field: Claude Code reads an entry
without a type as a stdio server, the same shape as a Claude
Desktop entry. The budget above controls only how much this
server sends. Claude Code applies its own output limits on top
(default 25,000 tokens per tool result; long text results are
spilled to a file for the model to read back), so a large
bundled read may arrive as a file reference rather than inline
content. To raise Claude Code's own limit, set
MAX_MCP_OUTPUT_TOKENS in the shell before starting Claude
Code (for example MAX_MCP_OUTPUT_TOKENS=50000 claude). Check
the connection with claude mcp list or the /mcp panel.
Optional: raise (or lower) the read_file total response budget if your
client allows larger tool results than Claude Desktop's ~1 MB ceiling:
"env": {
"MEMDRIVE_ROOT": "...",
"MEMDRIVE_RESPONSE_BUDGET_BYTES": "5000000"
}The default is 950,000 bytes; values are clamped to 100,000–50,000,000. See Limits before raising it.
Setup wizard & launchers
node dist/index.js setup runs an interactive wizard (no new
dependencies — plain Node readline). After npm publish, the same
wizard runs as npx memdrive-mcp setup; until the package is
published, use the zip + launcher form below.
What the wizard does, in order:
Chooses a host. The wizard asks which host to configure — 1 Claude Desktop, 2 Cursor, 3 VS Code, 4 Claude Code (Enter = 1). You can skip the question with an argument:
node dist/index.js setup cursor(orsetup claude/setup claude-desktop,setup vscode— only that one word, novs-code/codealias,setup claude-code— only that spelling,codeis not an alias). The argument is an optional shortcut for people who already know which host they want; the prompt is the default, foolproof path, including fornpx memdrive-mcp setupand the launchers, which call the wizard with no argument. An unrecognised argument falls back to the prompt instead of guessing a host.Finds a library folder. It probes for existing sync folders — OneDrive, Google Drive, iCloud — plus the
~/memdrivedefault, and shows a numbered menu. Google Drive on Windows is probed in three steps: the DriveFS install folder must exist, then a PowerShell volume-label probe finds the drive letter, then common paths (G:\My Drive,H:\My Drive, …) are checked for existence — no drive letter is ever assumed. You can also type a custom absolute path (~is expanded). The chosen folder is created if it does not exist.Finds the host config by probing the known locations. Claude Desktop: macOS Application Support; Windows
%APPDATA%\Claudeplus the%LOCALAPPDATA%Store/per-user locations. Cursor: the global config file only,%USERPROFILE%\.cursor\mcp.jsonon Windows and~/.cursor/mcp.jsonon macOS/Linux, returned only when the.cursordirectory exists. VS Code: the Copilot Global config file only,%USERPROFILE%\.copilot\mcp-config.jsonon Windows and~/.copilot/mcp-config.jsonon macOS/Linux, returned only when the.copilotdirectory exists. Claude Code: the user scope only, the top-levelmcpServerskey of the one~/.claude.jsonfile (%USERPROFILE%\.claude.jsonon Windows,~/.claude.jsonon macOS/Linux, or insideCLAUDE_CONFIG_DIRwhen that variable is set), returned only when the file already exists. Exactly one file → it is used; several → you pick one; none → nothing is written and the wizard prints a ready-to-paste snippet instead.Writes the config safely. An existing file is backed up first (
<file>.bak, or<file>.bak-<timestamp>when a backup already exists, so an earlier backup is never overwritten). ThemcpServers.memdriveentry (command: node,args: [<absolute path to dist/index.js>],env: {MEMDRIVE_ROOT: <chosen folder>}, plustype: "stdio"for Cursor and VS Code, plus the host's response budget inenvfor Cursor, VS Code, and Claude Code — see Limits; Claude Desktop entries carry no budget env, and Claude Code entries carry notypefield) is merged in; every other key and every other server is preserved, and an existing entry's"tools": ["*"]field (VS Code) is carried over. For Cursor and VS Code, a missing config file is created instead (the host directory already exists), with no backup to take. A missing Claude Desktop or Claude Code file is never created. A corrupt config file aborts the write entirely — nothing is backed up, nothing is changed. Then it tells you to fully quit and restart the host you configured.
The launchers (setup.bat for Windows, setup.sh for macOS/Linux,
setup.command for double-clicking on macOS) are thin shells: they
check for Node.js 18+, run npm install + npm run build (failures
shown plainly, script stops), then run the wizard. All logic stays
in Node; the scripts contain no configuration of their own.
Windows SmartScreen note. If you downloaded the zip from the
internet, Windows may show "Windows protected your PC" when you run
setup.bat. That is SmartScreen reacting to a downloaded file, not
evidence of a problem: setup.bat is plain text — open it in
Notepad and read it before running if you like. To proceed, click
More info, then Run anyway. No code signing is used (a paid
certificate is only worth it once the project earns revenue).
Other hosts. The wizard writes Claude Desktop, Cursor, VS Code, and Claude Code config (global config for Cursor, Copilot Global config for VS Code, user scope for Claude Code). The config-writing code is isolated behind a small per-host adapter so another host can be added later, but only after that host's config surface is verified on a real machine — with one exception: Claude Code was added from Anthropic's official docs only and is unverified (see Claude Code config). Codex/Gemini are CLIs with no desktop config file, Grok has no desktop MCP config surface, and no Muse desktop app exists. New hosts are added only on user feedback after these four.
Tools
Tool | What it does |
| Lists the immediate children of a directory in the library (root by default). |
| Recursive keyword search: file names and, for small text files, contents. |
| Writes text (usually Markdown). Modes: |
| Reads text, or a Markdown file together with its referenced images in one response, within one total response budget. Pass |
| Opens an image file in the OS default image viewer, at full original quality. Only when the user explicitly asks to view the original — never automatically, and never returns image bytes to the model. |
| Opens the folder containing a file (or the folder itself) in the OS file manager, without highlighting or selecting any file. Only when the user explicitly asks to open the folder — never automatically, and never returns folder contents to the model. Omit the path to open the library root. |
Reading back: packed, two-step, and single-image
One total budget governs every read_file response (text bytes +
base64 bytes of all image blocks together, default 950,000). Text is
guaranteed first; images share only what the text leaves. An image
that does not fit is downscaled in memory to fit the remaining budget,
or skipped with a note — the read never fails as a whole because of an
image, and the file on disk is never modified. Three ways to read:
Packed read (default).
read_fileon a Markdown file returns the text together with its referenced images in one response. Best for short notes with one or two small pictures. A large screenshot (for example ~800 KB on disk, ~1.1 MB as base64) is downscaled in memory to fit the budget instead of blowing up the whole response the way it did before 0.1.1.Two-step read (several images, or one large image). First call
read_filewithinclude_images: false: you get the text plus the list of referenced image paths (library-relative, e.g.notes/assets/shot-....png). Then callread_fileonce per image path. Each direct image read gets the whole budget to itself, so each picture keeps the best quality the budget allows — this is the way to get a large screenshot back at full usable quality.Single-image read.
read_fileon an image path directly returns that one image. It is subject to the same total budget: the image is returned untouched when it fits, and downscaled in memory only when the image itself exceeds the budget (or the 3.5 MB per-image ceiling). If an image cannot be fitted within the budget at all (for example a format the built-in decoder cannot shrink), the result is text explaining that, not an error.
Viewing an original image: open_image
read_file returns a preview that fits the response budget — good
enough to read, not always the original pixels. When the user
explicitly asks to view the original ("open this image", "在系统里打开这张图"),
open_image opens the file in the operating system's default image
viewer (Photos on Windows/macOS, the default viewer on Linux) at
full quality. The tool returns only a short text confirmation; no
image bytes go to the model.
The rule is written into the tool description itself: the model must
only call open_image on an explicit user request, never
automatically after a read or a save. Opening a viewer window is a
visible side effect on the user's screen, and unprompted popups are
not acceptable. Only image files inside the library root open;
non-images, directories, missing files, and sandbox escapes are
rejected, and the viewer is launched with an argument array (never
a shell string), so a crafted filename cannot inject a command.
Opening a note's folder: open_containing_folder
When the user explicitly asks to open a note's folder in the system
("open the folder", "在系统里打开这个笔记所在的文件夹"),
open_containing_folder opens that folder in the operating system's
file manager (Explorer on Windows, Finder on macOS, the default file
manager on Linux). A file opens its parent folder; a folder opens
itself; an empty path opens the whole library root. The folder opens
without highlighting or selecting any file — no explorer /select,
no Finder selection, no reveal-with-selection.
The rule is written into the tool description itself, the same way
as open_image: only on an explicit user request, never
automatically after a read or a save. The tool returns only a short
text confirmation naming the folder opened; no folder contents go to
the model (use list_directory to see what is in the folder).
Only paths inside the library root open; missing paths and sandbox
escapes are rejected, nothing is modified, and the folder is
launched with an argument-array launcher (never a shell string),
so a crafted filename cannot inject a command. On Windows the
folder launch goes through the shell (cmd /c start "" explorer.exe /n,<path>, switch and path in one comma-joined argument), so the
folder opens as a new Explorer window every time instead of a hidden
tab in an already-open Explorer window; image files still open
through the normal viewer launch, unchanged.
Saving with images
save_file accepts an images array mixing three source kinds.
Clipboard comes first, because it is the one people get wrong:
The literal string
"clipboard"— first choice for screenshots. Just tell the model "把截图存下来" / "把剪贴板里的图存下来". The server reads the clipboard directly on your own machine. You do not need to paste, upload, or send the image into the chat, and the model must never claim it cannot read the clipboard or that the library is text-only. (This rule is written at the very top of thesave_filetool description, so the model sees it before anything else.)Local file paths — e.g.
~/Pictures/shot.png(quotes stripped,~expanded).http(s) URLs — downloaded directly, zero token cost.
Images land in a sibling assets/ folder, renamed
<document-name>-<timestamp>.<ext>, and for Markdown files a standard
 reference is appended automatically. Originals are
always kept at full quality.
Interaction rule (built into the tool description): before calling
save_file, the model must show you the exact destination path and
filename and get your confirmation in the chat. There is no popup — the
confirmation happens in the conversation.
Clipboard edge cases
Clipboard empty or holding text instead of an image: the text is still saved; the result tells you to re-screenshot.
Headless environments (Docker, servers, NAS): clipboard capture reports itself as unsupported with a suggestion to use a file path or URL. The server never crashes on clipboard/image failures.
Limits (all in src/config.ts, nowhere else — except the response budget, which is also env-overridable)
Constant | Value | Meaning |
| 950,000 | Default total budget for one |
| 1,000,000 | Text returned by |
| 3,500,000 | Per-image preview ceiling (binary bytes). Image previews are downscaled in memory below this and below what the remaining response budget allows, whichever is smaller. The preview ladder tries a full-resolution JPEG re-encode first, trying JPEG qualities 95, 90, then 80 before shrinking, then shrinks in 0.9 steps at quality 80, returning the first attempt that fits — so the preview stays close to the largest size the budget allows instead of stopping at a coarse first shrink, and spends headroom on sharpness when full resolution already fits. The on-disk original is never modified. |
Why a total budget, and why 950,000: Claude Desktop rejects a whole
tool result over 1,048,576 bytes. The old per-part caps (1 MB text,
3.5 MB per image, no combined check) let a bundled read blow past
that wall — in the real 2026-10-28 test, an 813.5 KB screenshot
became ~1.11 MB of base64 and the entire read was rejected. 950,000
leaves ~98 KB of headroom for JSON framing and notes. Raise the
budget only if your client demonstrably accepts larger results; the
server cannot detect a client's limit (MCP initialize carries no
host/limit information, and no clientInfo identification is done),
so the default stays at the lowest known ceiling and is treated as
universal across Claude Desktop plans and unknown hosts. Three
different limits are at work — the host's result cap, this server's
budget and 3.5 MB per-image ceiling, and the model's own
pixel/token scaling — and the read_file tool description states
all three, so the model does not have to guess which one bit.
Per-host response budgets (written by the wizard into each host's
config entry as MEMDRIVE_RESPONSE_BUDGET_BYTES; the server cannot
identify the host, so the env value is the only way to pass the
budget through). Do not read more into the Cursor and VS Code rows
than the evidence states: Cursor is verified and VS Code is partly
verified, and neither exact ceiling was measured.
Host | Budget | Evidence |
Claude Desktop | 950,000 | Verified: 2026-10-28 single-variable experiment — with the budget disabled via the environment variable, the same bundled read failed twice with the exact 1,048,576 error; 950,000 leaves ~98 KB of headroom for JSON framing and notes. |
Cursor | 10,000,000 | Verified: 2026-10-30 single bundled read passed ( |
VS Code | 10,000,000 | Partly verified: 2026-10-29 four-image bundled read passed ( |
Claude Code | 10,000,000 | ESTIMATED, UNVERIFIED. Set by the author's decision 2026-10-31, never tested on a real machine: Claude Code is a paid product, so a limit as stingy as Claude Desktop's would make no sense for paying users; if the estimate is wrong, user reports of oversized-result errors are the feedback path. Claude Code also applies its own output limits on top of this server-side budget (default 25,000 tokens per tool result; long text results spilled to a file), so this value controls only how much the server sends. Raise Claude Code's own limit with |
ChatGPT, Grok, and other hosts are untested for the limit; the 950,000 default is treated as universal for unknown hosts rather than assuming a larger limit any of them has not demonstrated.
Why 3.5 MB: base64 inflates binary by 4/3, so 3.5 MB becomes ~4.67 MB of base64 text, under every vendor image cap checked in the official docs (5 MB Bedrock/Vertex, 7 MB Gemini, 10 MB Claude API, 20 MB OpenAI). Do not raise it without re-checking those docs. It still caps any single preview even when the total budget is raised above it.
Other caps: at most 20 referenced images per read_file response (the
total budget usually binds first);
search_files returns at most 200 hits and only content-searches files
under 256 KB; URL downloads have a 30 s timeout and a 500 MB safety
ceiling (a disk-exhaustion guard, not a product limit).
Security
Root sandbox (hard). Every path is locked to
MEMDRIVE_ROOT.../escapes, absolute paths outside the root, and symlinks inside the root that point outside are all rejected — including symlinks in the parent chain of not-yet-created files. Violations return a clear error.Local image sources are OS paths, not library paths. A
save_fileimage entry like~/Pictures/shot.pngintentionally reads from outside the root; only the destination is sandboxed.No network listeners. stdio transport only; nothing is exposed.
Zero native dependencies. Pure-JS dependency tree (MCP SDK, zod, jimp). No
node-gyp, no C++ builds, no Sharp.Image formats. jimp (the pure-JS decoder) reads PNG/JPEG/GIF/BMP/ TIFF. WebP files pass through untouched when under the preview cap and are reported (not crashed on) when over it; SVG files are returned as text, never as image blocks; GIFs read as their first frame.
Verifying with MCP Inspector (step 1, zero model cost)
npm run build
npx -y @modelcontextprotocol/inspector --cli node dist/index.js --method tools/list
npx -y @modelcontextprotocol/inspector --cli node dist/index.js --method tools/call --tool-name list_directoryNote: the Inspector CLI spawns the server with its own environment, so
MEMDRIVE_ROOT set in your shell may not reach it — it defaults to
~/memdrive. The interactive Inspector UI (npx @modelcontextprotocol/inspector
without --cli) lets you set environment variables explicitly.
Development
npm install
npm run build # tsc, strict
npm run typecheck # tsc --noEmit
npm test # protocol tests: SDK Client over stdio (see TEST-REPORT.md)The SDK version is pinned exactly (@modelcontextprotocol/sdk 1.32.2,
the v1.x maintenance line) and package-lock.json is committed. The SDK
has a v2 line under separate package names; this project deliberately
stays on v1.x until there is a reason to migrate.
Roadmap (not in this MVP)
WebDAV: interface reserved behind the existing
StorageBackendinterface but not implemented. Whether it is implemented later depends on user feedback, and it will only be considered if the user base is large with clear demand.Windows clipboard capture verified on real hardware (2026-10-28, screenshot save via Claude Desktop); the macOS clipboard branch is still implemented from the documented OS pattern only — no macOS machine was available. The 0.1.3 quality ladder passed its real-conversation retest in Claude Desktop (2026-10-28: 359.0 KB preview of the 1.22 MB comment screenshot, original untouched).
Still to verify on a real Windows machine (see TEST-REPORT.md §14): the setup wizard's VS Code path end-to-end (host prompt choice 3 and
setup vscodeargument, Copilot Global config creation/merge with"tools": ["*"]preserved, restart VS Code, all six tools in VS Code — onlylist_directoryand a bundled image read have been verified there so far), the wizard's Cursor path end-to-end (host prompt and argument, global config creation, restart Cursor, tools + read/save/open_image/ open_containing_folder in Cursor),open_containing_folderopening a folder once in each host, and a Claude Desktop regression check (its entry is byte-identical); the macOS wizard branches (setup.command, iCloud/Google Drive candidates,open) and the PowerShell Google Drive probe are untested on real hardware. No further Cursor or VS Code size-limit probing is planned.
License
MIT — see LICENSE.
Support
If MemDrive saves you time, you can support its development. Thank you!
Ko-fi: ko-fi.com/newmannn91
USDT (TRC-20 only): send only TRC-20 USDT to the address below. Do not send other tokens or use another network — they cannot be recovered.
TU9GBiQ1Ji1Fm5YECYThjcchTofj8B6uCDWeChat Pay: scan the code below.
微信用户可扫码赞赏。
Available Tools
6 toolslist_directoryA
List the immediate children (subfolders and files) of a directory inside the MemDrive memory library. Returns one line per entry with type, size, and modification time. Directories sort first. Use this to explore what is already stored before reading or saving. Paths are relative to the library root (MEMDRIVE_ROOT). Omit path or pass "" for the root. Absolute paths are accepted only when they stay inside the root.
| Name | Required | Description | Default |
|---|---|---|---|
| path | No | Directory to list, relative to the library root. Omit or pass "" for the root. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the burden and does well: it discloses return format (one line per entry with type, size, modification time), sort order (directories first), and a real constraint (absolute paths accepted only when inside the root). It doesn't explicitly state read-only-ness, but listing semantics make that clear.
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 behavior, then usage, then path handling. Every sentence earns its place and none is redundant.
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?
Despite no annotations and no output schema, the description explains the return format, sorting, and path constraints, so an agent has everything needed to call it correctly and interpret results.
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 100%, so baseline is 3, but the description adds value beyond the schema by noting absolute paths are accepted only when they stay inside the root — a constraint not present in the schema's path property. This meaningfully enriches the single parameter.
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 (List) and resource (immediate children of a directory) with precise scope ('immediate', not recursive), making it clearly distinct from siblings like search_files and read_file. An agent can tell what this 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?
'Use this to explore what is already stored before reading or saving' gives a clear when-to-use context. It doesn't explicitly name search_files as the alternative for finding a specific file, but the exploration framing adequately distinguishes listing from searching/reading.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
open_containing_folderA
Open the folder containing a file or directory from the MemDrive memory library in the operating system's file manager (Explorer on Windows, Finder on macOS, the default file manager on Linux). A file opens its parent folder; a folder opens itself; an empty path opens the whole library root. The folder is opened without highlighting or selecting any file. USE ONLY WHEN THE USER EXPLICITLY ASKS TO OPEN THE FOLDER — for example "open the folder", "show me this note in the file manager", or "在系统里打开这个笔记所在的文件夹". NEVER call open_containing_folder automatically after a read_file, a save_file, or any other tool call, and never open a folder the user has not asked to open. Opening a file manager window is a visible side effect on the user's screen; the model must not cause it unprompted. The folder contents are never returned to the model: the result is only a short text confirmation naming the folder that was opened (or a note when no file manager is available, for example on a headless machine). To see what is in the folder, use list_directory instead. Only paths inside the library root can be opened. Missing paths and paths escaping the root are rejected with a note. Nothing is modified. Paths are relative to the library root (MEMDRIVE_ROOT). Absolute paths are accepted only when they stay inside the root.
| Name | Required | Description | Default |
|---|---|---|---|
| path | No | File or folder whose containing folder to open, relative to the library root (for example "notes/2026-10-28.md" opens "notes"). Omit or pass "" to open the library root. Only call this when the user explicitly asked to open the folder. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations present, the description carries the full burden and does so: it discloses the visible side effect on the user's screen, that no file is highlighted/selected, that contents are never returned to the model, that the result is only a short text confirmation, and that headless machines yield a note instead. It also states safety boundaries — paths escaping the root are rejected and nothing is modified.
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 action and the three path cases, then usage rules, then behavioral caveats — a sensible ordering with no filler. It is somewhat longer than needed because the usage restriction is repeated in the schema and again in the paragraph, but every sentence still carries real 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?
For a single-optional-parameter side-effecting tool with no annotations and no output schema, the description covers everything an agent needs: invocation conditions, path resolution, failure modes (missing paths, root escape, no file manager), and what the result looks like.
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 100%, so the baseline is 3; the description adds genuine meaning on top by defining the empty-string case, the parent-folder resolution rule, and that absolute paths are accepted only when they remain inside MEMDRIVE_ROOT. It does not add format/syntax detail beyond the schema examples, so it stops short of a 5.
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 and resource ("Open the folder containing a file or directory") and immediately disambiguates the three input cases: a file opens its parent, a folder opens itself, an empty path opens the library root. It is clearly distinguishable from list_directory, which is named as the way to actually see contents.
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?
Explicitly states the when ("USE ONLY WHEN THE USER EXPLICITLY ASKS TO OPEN THE FOLDER"), gives example phrasings including a non-English one, names explicit exclusions (never after read_file/save_file or any other tool call), and routes to the alternative (list_directory) for the different need of inspecting contents.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
open_imageA
Open an image file from the MemDrive memory library in the operating system's default image viewer (Photos on Windows/macOS, the default viewer on Linux), at full original quality. USE ONLY WHEN THE USER EXPLICITLY ASKS TO VIEW THE ORIGINAL IMAGE — for example "open this image", "show me the original", or "在系统里打开这张图". NEVER call open_image automatically after a read_file, a save_file, or any other tool call, and never open an image the user has not asked to view. Opening a viewer window is a visible side effect on the user's screen; the model must not cause it unprompted. The image itself is never returned to the model: the result is only a short text confirmation (or a note when no viewer is available, for example on a headless machine). To see the picture in the conversation, use read_file on the image path instead. Only image files inside the library root can be opened. Non-image files, directories, missing files, and paths escaping the root are rejected with a note. The file on disk is never modified. Paths are relative to the library root (MEMDRIVE_ROOT). Absolute paths are accepted only when they stay inside the root.
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | Image file to open, relative to the library root (for example "notes/assets/shot-20261028-120000-000.png"). Only call this when the user explicitly asked to view the original image. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does: it discloses the visible side effect (a viewer window on the user's screen), that the image is never returned to the model, that the result is only a short text confirmation, that headless machines yield a note rather than an error, and that the file on disk is never modified.
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, and the trigger/gating rule follows immediately. The gating rule is partially duplicated by the path parameter's schema description and a few clauses (Linux viewer specifics, restating the no-modification guarantee) could be trimmed without loss.
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?
Covers everything an agent needs for a one-parameter, no-output-schema tool: what it does, when it is permitted, what it returns and does not return, error behavior for bad paths, and the path resolution model. No meaningful gap remains.
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 100%, so the baseline is 3, but the description adds genuinely new semantics: paths resolve relative to MEMDRIVE_ROOT, absolute paths are only accepted inside the root, and out-of-root or non-image paths are rejected. It stops short of describing other edge cases, but the added value is real.
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 (open an image file from the MemDrive library) and names the exact mechanism (OS default viewer, full original quality). It also distinguishes itself from read_file, which is the sibling an agent would otherwise confuse it with.
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 when-to-use triggers with example phrasings, explicit when-NOT-to-use rules ('NEVER call after read_file, save_file, or any other tool call'), and the alternative to use instead (read_file for in-conversation viewing). Nothing 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.
read_fileA
Read a file from the MemDrive memory library. TOTAL RESPONSE BUDGET — THREE LIMITS ON THREE DIFFERENT LAYERS. (1) HOST: the MCP host (Claude Desktop, the only host verified so far) rejects a whole tool result over about 1 MB ("Tool result is too large. Maximum size is 1MB"). That limit lives in the host, outside this server, and is NOT a model or context-window limit; other hosts (ChatGPT, Grok) are untested, so this server assumes the same ~1 MB ceiling for all of them. (2) SERVER: text bytes plus the base64 bytes of every image block in one response must together fit inside a single total budget — default 950,000 bytes, overridable with MEMDRIVE_RESPONSE_BUDGET_BYTES (clamped to 100,000–50,000,000) — a safety margin under the host limit. Text comes first and is guaranteed; images share only the budget the text leaves. An image that does not fit is downscaled in memory to fit it, or skipped with a note — a read never fails as a whole because of an image. The file on disk is never modified. Previews are built at full resolution first, trying higher JPEG quality before shrinking, so a preview uses the budget for sharpness instead of stopping far below it. At the default budget the effective per-image cap is about 712,000 binary bytes (after base64 inflation), so the separate 3.5 MB per-image preview ceiling only binds when the budget is raised for a host with a larger limit. HISTORY: before v0.1.1 this server had NO total budget, so a bundled read whose base64 exceeded the host limit was rejected wholesale by the host — that is what happened to the first read of an 813.5 KB image (~1.11 MB as base64). (3) MODEL: once the model receives an image it scales it by pixels into tokens under its own limits — a separate layer from the byte limits above, not something this server controls. TWO-STEP READING — USE THIS WHENEVER A DOCUMENT REFERENCES SEVERAL IMAGES, OR ONE LARGE IMAGE: Step 1, call read_file with include_images=false to read the text and get the list of referenced image paths. Step 2, call read_file once per referenced image, passing that image path itself as path, so the image alone gets the whole response budget and keeps the best quality the budget allows. Reading an image file directly is also limited by the same total budget: a single image is returned untouched when it fits, and downscaled in memory only when the image itself exceeds the budget. Text files: returned as text (truncated at the smaller of the 1 MB text cap and the total budget, with a note when truncated). Markdown files: with include_images=true (the default), the text is returned TOGETHER WITH every locally-referenced image that fits the remaining budget in the same response — each image becomes an image content block, so the model sees words and pictures together. Remote (http) and data: images are skipped with a note. Images over the 3.5 MB preview cap are downscaled in memory only; the file on disk is never modified. Image files: returned as a single image content block (downscaled in memory only when over the preview cap or the total budget). If an image cannot be fitted within the budget at all, the result is text explaining that, not an error — the original is untouched. SVG files are returned as text (they are XML), never as image blocks. Paths are relative to the library root (MEMDRIVE_ROOT). Absolute paths are accepted only when they stay inside the root.
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | File to read, relative to the library root (for example "notes/2026-10-28.md"). | |
| include_images | No | For Markdown files: true (default) returns the text together with its referenced images, within the total response budget; false returns text only plus the list of referenced image paths (step 1 of two-step reading). Ignored for non-Markdown files. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does so: it states the file on disk is never modified (read-only), that images are downscaled in memory or skipped with a note rather than failing the read, that SVG is returned as text, that remote/data: images are skipped, and that text is truncated with a note. Error and degradation semantics are all disclosed.
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 purpose is front-loaded, but the body is an essay: three-layer budget theory, host-specific notes on ChatGPT/Grok being untested, env-var clamping ranges, and a historical anecdote about a v0.1.1 813.5 KB image failure that an agent cannot act on. A large fraction of the text does not help selection or invocation.
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?
No output schema exists, and the description compensates fully: return forms per file type (text, markdown with image blocks, single image block, text explaining an unfittable image), truncation behavior, and path/root constraints are all covered. Nothing an agent needs to call it correctly 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 description coverage is 100%, so both parameters are already documented in the schema, including that include_images defaults to true and is ignored for non-Markdown files. The description largely restates that (the two-step guidance is usage rather than parameter semantics), so 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?
Opens with a specific verb and resource ("Read a file from the MemDrive memory library") plus a scope statement on paths. It never explicitly distinguishes itself from the sibling open_image, which is a plausible source of confusion since read_file also returns image content blocks for image files.
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 "TWO-STEP READING" block gives explicit when-to-use guidance: use it whenever a document references several images or one large image, with the exact sequence (include_images=false, then one call per image path). No guidance is given for choosing between read_file and siblings like search_files or list_directory, but within its own workflow the routing is clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
save_fileA
CLIPBOARD FIRST — READ THIS BEFORE ANYTHING ELSE: When the user says to save a screenshot or an image from the clipboard — for example "把截图存下来", "把剪贴板里的图存下来", "save the screenshot", or any equivalent wording — pass images: ["clipboard"]. That is all it takes: the server reads the clipboard directly on the user's own machine. You do NOT need to see the clipboard or the image. NEVER ask the user to paste, upload, or send the image into the chat. NEVER say you cannot read the clipboard, that you cannot see images, or that this memory library can only store text. If the clipboard holds no image, the server reports that in the result and the text is still saved — tell the user to take the screenshot again and retry; do not invent a clipboard failure. Interaction rule — read before calling: Before calling this tool, show the user the EXACT destination path and filename you intend to write (for example: "notes/2026-10-28.md") and get their explicit confirmation in the chat. Never call save_file with a path or filename the user has not confirmed. If the user has not confirmed a location yet, ask them first instead of calling. There is no popup or confirmation dialog: confirmation happens here, in the conversation, through you. Save text (usually Markdown) into the MemDrive memory library. Modes: "new" (default) fails when the file already exists; "overwrite" replaces it; "append" adds to the end, creating the file when missing. Parent directories are created automatically. Images: pass an "images" array with any mix of the literal string "clipboard" (capture the latest screenshot from the OS clipboard — see the clipboard rule above), local file paths, or http(s) image URLs. Images are copied/downloaded/captured into a sibling assets/ folder, renamed "-.", and for Markdown files a standard image reference is appended to the document automatically. The on-disk original is always kept at full quality; only the preview handed to a model is ever downscaled. Clipboard behavior: when the clipboard is empty or holds text instead of an image, the text is still saved and the result explains what to do (re-screenshot). Clipboard capture never crashes the server; in headless environments it reports itself as unsupported and suggests a file path or URL instead. Paths are relative to the library root (MEMDRIVE_ROOT). Absolute paths are accepted only when they stay inside the root. The root is a hard sandbox: "../" escapes and symlinks pointing outside are rejected. Path cleaning: surrounding quotes are stripped, a leading ~ expands to the home directory, and separators are normalized.
| Name | Required | Description | Default |
|---|---|---|---|
| mode | No | Write mode: "new" (default, fails if the file exists), "overwrite", or "append". | |
| path | Yes | Destination file path, relative to the library root (for example "notes/2026-10-28.md"). Must be confirmed with the user before calling. | |
| images | No | Images to archive with the document — CLIPBOARD FIRST: the literal string "clipboard" captures the latest screenshot/image from the OS clipboard on the machine running the server. Use it whenever the user mentions a screenshot or the clipboard: never ask them to paste the image into the chat, and never claim the clipboard cannot be read. Local file paths and http(s) image URLs are also accepted. | |
| content | Yes | Text content to save (usually Markdown). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does: it discloses that parent directories are auto-created, that images are copied into a sibling assets/ folder and renamed "<document-name>-<timestamp>.<ext>" with a Markdown reference appended, that the on-disk original stays full quality while only the model preview is downscaled, and that the root is a hard sandbox rejecting "../" and out-of-root symlinks. It also pre-empts failure interpretation — empty clipboard still saves text and reports re-screenshot guidance, headless environments report clipboard as unsupported rather than crashing.
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 clipboard rule is stated three separate times (the CLIPBOARD FIRST block, the Images paragraph, and the Clipboard behavior paragraph), and the "never ask the user to paste" instruction is repeated again in the schema. The most important fact — what the tool does — is not front-loaded, appearing only after the clipboard and confirmation sections.
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 4-parameter mutation tool with no annotations and no output schema, the description covers everything an agent needs: write-mode semantics, directory creation, image handling and placement, sandbox limits, path normalization, and how to read the result on clipboard failure. Nothing material is left to inference.
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 100%, so the baseline is 3, but the description adds meaning beyond the schema: path cleaning behavior (quote stripping, ~ expansion, separator normalization), sandbox containment rules for absolute paths, and the downstream effects of the images array (where files land, how they are named, what gets appended to Markdown). Only the mode and content parameters are left to the schema alone.
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 — "Save text (usually Markdown) into the MemDrive memory library" — and the images paragraph makes clear it also archives binary images, which separates it from read-only siblings like read_file and search_files. The purpose statement is buried in the fourth paragraph behind a clipboard preamble, so an agent must read past a lot of material before learning what the tool fundamentally does.
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 explicit routing rules for the clipboard case (use images: ["clipboard"] whenever the user mentions a screenshot, never ask for a paste), a mandatory pre-call confirmation workflow with a concrete example, and mode selection guidance ("new" fails when the file exists; "overwrite"; "append" creates when missing). These are when-to-use and how-to-behave rules an agent cannot infer from the schema.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_filesA
Search the memory library for files by keyword: matches file names (case-insensitive substring) and, for small text files, file contents. Searches recursively under the given directory. Returns root-relative paths with a match kind (name/content) and, for content matches, the first matching line. Paths are relative to the library root (MEMDRIVE_ROOT). Omit path or pass "" to search the whole library.
| Name | Required | Description | Default |
|---|---|---|---|
| path | No | Directory to search under, relative to the library root. Omit or pass "" for the whole library. | |
| keyword | Yes | Keyword to search for (case-insensitive substring). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does well: it discloses matching rules (case-insensitive substring), recursion, the small-text-file caveat for content scanning, the path base (MEMDRIVE_ROOT), and the return shape including match kind and first matching line. It stops short of noting result limits, ordering, or pagination behavior, which matters for a recursive 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?
Four sentences, front-loaded with the core match semantics before the return format and path defaults. The final sentence largely duplicates the schema's path description, a small redundancy, but nothing else is wasted.
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 read-only, two-parameter search with no output schema, the description is nearly complete: it explains matching, scope, base path, and the return structure. The remaining gap is absence of any note on result caps or ordering when a broad search hits many files.
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 100%, so both parameters are already documented in the schema; the description largely restates them (keyword matching semantics, path resolution). It adds only the MEMDRIVE_ROOT-relative framing, so baseline 3 is correct.
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 ("search the memory library for files by keyword") and defines exactly what is matched: file names via case-insensitive substring and, for small text files, contents. It does not explicitly name or contrast with the sibling tools list_directory or read_file, so the verb alone has to carry the 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?
Provides scope guidance ("omit path or pass \"\" to search the whole library") and implies usage via "searches recursively under the given directory." It never says when to prefer this over list_directory or read_file, nor when search is a poor fit (e.g. binary files, very large trees), leaving the choice to inference.
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.
6 tool updates
v0.6.0- First observed
list_directory - First observed
open_containing_folder - First observed
open_image - First observed
read_file - First observed
save_file - First observed
search_files
TDQS
Scored across 6 tools
Each tool maps to a distinct operation: browsing (list_directory), recursive lookup (search_files), write (save_file), read (read_file), and two explicit OS-side actions (open_image, open_containing_folder). The read_file vs open_image vs open_containing_folder boundary is spelled out in the descriptions ('returned to the model' vs 'opens a viewer window'), so misselection is unlikely.
All six tools follow a strict snake_case verb_noun pattern: list_directory, search_files, save_file, read_file, open_image, open_containing_folder. Verbs are accurate and never clash (no duplicate verbs across the set).
Six tools is well-scoped for a sandboxed file/memory library: one per core operation plus two narrowly gated OS-integration tools. Nothing feels redundant or padded.
Read, write (new/overwrite/append), list, and search are covered, but there is no delete, rename, or move operation — agents cannot clean up or reorganize the library, a likely dead end for memory-management workflows. The surface is usable but missing lifecycle operations.
Maintenance
Related MCP Connectors
Portable AI memory shared across models and harnesses - plain markdown you own.
Personal wiki and memory layer for AI assistants. Persistent, structured memory across sessions.
Markdown notes in folders, with files, that your AI assistant can read, write and organise.
Markdown notes in folders, with files, that your AI assistant can read, write and organise.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceProvides persistent long-term memory for AI assistants with tag-based retrieval, wiki-style linking, and source references, storing memories as markdown files with SQLite index.1MIT
- AlicenseNot gradedqualityAmaintenanceEnables AI assistants to search, read, create, update, and remove personal markdown notes stored locally, providing persistent memory across sessions.84 npm2MIT
- AlicenseNot gradedqualityBmaintenanceA personal, offline-first memory for AI assistants that enables them to read, search, and write to a shared folder of Markdown files, so they all remember you without needing a cloud.1MIT
- AlicenseNot gradedqualityAmaintenanceTurns a folder of Markdown notes into an agent-native knowledge base, providing long-term memory with provenance, token-budgeted retrieval, and safe write-back with versioning.MIT