move_note
Moves or renames a note in the vault and updates wikilinks/backlinks to the new path, with optional link rewriting and hash-based safety checks to prevent stale writes.
Instructions
Move or rename a note inside the vault. Requires write permission — a readwrite API key, or an OAuth token
carrying the readwrite scope.
Updates notes_metadata.file_path for the moved note and note_links.target_path
rows whose stored target matched the old path. Backlinks via target_note_id
keep working without rewriting source notes (the moved note's id is unchanged).
With rewrite_links=True, also opens every source note that linked to this
note and rewrites the link in place: [[Old]] → [[New]],
[[Old|alias]] → [[New|alias]], [[Old#anchor]] → [[New#anchor]],
![[Old]] → ![[New]], path-style [[folder/Old]] → [[new/folder/New]],
and markdown links [text](Old.md) → [text](<new path>), whose href is
written relative to the linking note's own folder (anchors preserved).
Aliases and anchors survive; only the target portion is rewritten.
The moved note's own body is rewritten as well, so a self-reference
does not end up pointing at the old path.
The rewrites are planned before anything changes: if one would push a source note past the 10 MiB note limit the whole move is refused, naming that source, before any file is touched. That preflight is also bounded in aggregate: if the originals plus rewrites for all backlink sources would exceed 256 MiB in memory the move is refused before anything changes, naming the note count and the limit.
The same preflight refuses the whole move, before the rename, when any
source it would rewrite — the moved note's own body included — contains a
fence opener indented by one to three spaces that nothing below it
closes. The refusal names each such source and where its opener sits. A
link under such an opener may be inside a list item's code block, which
this server does not parse, and a rewrite would mutate text whose
code-or-content status had to be guessed. Move with rewrite_links=False
(unaffected by this refusal) and fix the links yourself, or close the
fences first.
A rewrite can still fail after the move has committed. The move is one
rename and the rewrites follow it, so an I/O failure, a vault reassignment,
or a database that cannot be reached to confirm the assignment stops the
remaining rewrites — and the result then reads partial success: …, naming
the sources that still link to the old path. The move is not rolled back
and the index rows describe where the note now is. Treat the link graph as
agreeing with the vault bytes only when the result reports plain success;
on a partial outcome, fix the named sources with edit_note.
Writes are atomic. Either path is refused, naming the link's target, when
its final component is a symlink; symlinked folders inside the vault work
normally and the recorded paths are the real ones behind them. See
get_vault_guide for vault folder conventions.
expected_hash — binding a write to the bytes you read. Optional; omit
it and nothing changes. Pass the content_hash a read returned, verbatim
and canonical (sha256:<64 lowercase hex>), and the call is refused with
nothing written if the file changed in between. It is always the whole
file's hash, never a hash of the text you received. expected_hash
covers your read through this call's preflight read. The rename pins inode
identity but does not compare the bytes again: an in-place edit after that
comparison can still be moved. Each optional link rewrite retains its own
pre-publication byte comparison. Precondition refusals end with one
machine-readable MCP-REFUSAL {"code":…} line — stale_precondition (with
the file's current hash, ready to resend), concurrent_write,
no_incumbent, malformed_precondition, precondition_unavailable,
precondition_required — and each states what resolves it.
Here it binds from_path's own bytes and nothing else, compared before
the rename and before any rewrite; the backlink sources a
rewrite_links=True move would rewrite are not bound, because you never
read them. Success reports the content_hash of the bytes actually
published at to_path — the moved bytes for a plain move, the post-rewrite
bytes when the moved note's own body was rewritten — and that value binds a
following edit_note(to_path, …, expected_hash=…). A rewrite that fails
after the rename stays a partial success and never claims nothing was
written; if it failed because another writer changed to_path in between,
no hash is reported at all and the result says to re-read to_path
before writing to it.
Args:
from_path: Vault-relative path of the existing note.
to_path: Vault-relative path of the destination. Must not exist. Parent
directories are created automatically.
rewrite_links: If True, also rewrite incoming wikilinks and embeds in
source notes. Off by default — opting in is destructive (it modifies
other notes' bodies).
expected_hash: from_path's content_hash as you last read it.
Refuses the move, changing nothing, if that note has changed since.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| to_path | Yes | ||
| from_path | Yes | ||
| expected_hash | No | ||
| rewrite_links | No |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| result | Yes |