Skip to main content
Glama
aliasunder

Vault Cortex Obsidian MCP Server

Patch Note

vault_patch_note
Destructive

Surgically edit markdown notes: append, prepend, replace, or insert content by heading while preserving frontmatter.

Instructions

Surgical edits to a markdown note — append, prepend, replace, or insert content by heading. Frontmatter values are preserved; YAML formatting may be normalized to block style on first edit.

Example: vault_patch_note({ path: "TASKS.md", operation: "append", heading: "Active", content: "- [ ] New task" })

Cross-section move (e.g. completing a task on a board):

  1. vault_read_note to get current content and verify exact text

  2. vault_patch_note({ path, operation: "append", heading: "Done", content: "- [x] Task text" }) to add at target

  3. vault_replace_in_note({ path, old_text: "- [ ] Task text", new_text: "" }) to remove from source (for a large multi-line block, prefer vault_delete_span); on error, re-read and retry until the source copy is gone Add at the target before deleting from the source — the two writes are not atomic, so this order can briefly duplicate the moved block on a failure but never lose it.

When to use: Modifying part of an existing note without overwriting the entire body. Prefer vault_write_note for creating new notes, or full rewrites (with overwrite: true). Prefer vault_replace_in_note for in-place text changes (typos, renaming) that stay in the same location.

Operations:

  • append: add content at end of section (or end of file if no heading)

  • prepend: add content after heading line (or at the top of the body, below frontmatter, if no heading — how you add a leading callout). To start a new section above the note's current first heading, use insert_before on that heading, not a no-heading prepend.

  • replace: replace section body (heading preserved; requires heading; errors if the target has child headings unless include_children is set)

  • insert_before: insert content above the heading line (requires heading)

Heading-targeted ops keep the matched heading and write content verbatim — don't begin content with the target heading (it's rejected to avoid a duplicate). No separator is added around the content — end it with a newline to leave a blank line after the inserted block.

Limitation: A no-heading prepend inserts at body line 0. If the note has content above its first heading and your content starts with a heading, that content becomes the new section's body. The write still succeeds and the confirmation says so — use insert_before on the first heading to place a section above it instead.

Section boundaries: a section spans from its heading to the next heading of the same or higher level (or EOF). Child headings are included in the parent section. Empty headings ("##" with no text) act as boundaries but cannot be targeted — edit their content via vault_replace_in_note instead.

Editing a leading callout: read it via vault_read_note(outline: true), then vault_replace_in_note the old block for the new one (a no-heading prepend would stack a second callout above it).

Errors:

  • "note not found" — path does not exist; check vault_list_notes for valid paths

  • "heading not found" — no heading matches the text; error lists available headings

  • "ambiguous heading" — multiple headings match; use heading_level to disambiguate, or use vault_replace_in_note to target by text content when headings share the same level

  • "operation … requires a heading target" — replace and insert_before need a heading

  • "content begins with the heading … which would duplicate it" — content's first line repeats the target heading; omit it (the matched heading is kept automatically)

  • "section … has N child headings …" — the target section contains child headings that replace would destroy; pass include_children: true to confirm, or target the child heading directly

  • "absolute path blocked" — the path starts at the filesystem root; use a vault-relative path

  • "hidden path blocked" — the path targets a hidden (dot-prefixed) file or folder like ".obsidian/"; hidden paths are not editable, matching Obsidian

  • "concurrent write in progress" — another write to this note is in flight; re-read the note and retry

  • "content contains a control character" — content includes a non-printable control byte; remove it before writing

Obsidian syntax: Content is Obsidian Flavored Markdown (no escaping applied). Watch for: #word = tag, [[ = wikilink, %% = comment block. Inserting heading-level content (## New Section) changes the note's structure — future heading-targeted ops may resolve differently. Table rows: send only the data row ("| cell1 | cell2 |"), not the header or separator — duplicating them splits the table.

Returns: Confirmation message — "Applied to → ", where target is the matched heading (e.g. "## Active") or "file body" for a no-heading append/prepend. A no-heading prepend that nested existing content under an inserted heading adds a sentence naming the content's size and the call that would have avoided it.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
pathYesVault-relative path to the note, including the ".md" extension (e.g. "TASKS.md", "Projects/plan.md")
contentYesMarkdown content to insert, written verbatim with no separator added — end it with a newline to leave a blank line after the inserted block. Must not begin with the target heading text (it would duplicate the heading, which is kept automatically).
headingNoTarget heading text (case-sensitive exact match). Required for replace and insert_before. Optional for append/prepend (omit for file-level operation).
operationYesappend | prepend | replace | insert_before. replace and insert_before require a heading; append and prepend work with or without one.
heading_levelNoHeading level (1-6) for disambiguation when multiple headings share the same text
include_childrenNoWhen true, allows replace to overwrite a section that contains child headings. Without this, replace errors if children exist — preventing silent data loss.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed1 schema field changedv0.41.2
    • changedInput schema / properties / content / description
      Previous value: -"Markdown content to insert. Must not begin with the target heading text (it would duplicate the heading, which is kept automatically)."New value: +"Markdown content to insert, written verbatim with no separator added — end it with a newline to leave a blank line after the inserted block. Must not begin with the target heading text (it would duplicate the heading, which is kept automatically)."
  2. Changed1 schema field changedv0.37.1
    • addedInput schema / properties / include_children
      Added value: +{
      +  "description": "When true, allows replace to overwrite a section that contains child headings. Without this, replace errors if children exist — preventing silent data loss.",
      +  "type": "boolean"
      +}
  3. Changed1 schema field changedv0.23.10
    • changedInput schema / properties / path / description
      Previous value: -"Vault-relative path to the note (e.g. \"TASKS.md\", \"Projects/plan.md\")"New value: +"Vault-relative path to the note, including the \".md\" extension (e.g. \"TASKS.md\", \"Projects/plan.md\")"
  4. Changed3 schema fields changedv0.23.5
    • changedInput schema / properties / content / description
      Previous value: -"Content to insert or replace with"New value: +"Markdown content to insert. Must not begin with the target heading text (it would duplicate the heading, which is kept automatically)."
    • changedInput schema / properties / operation / description
      Previous value: -"Patch operation to apply"New value: +"append | prepend | replace | insert_before. replace and insert_before require a heading; append and prepend work with or without one."
    • changedInput schema / properties / path / description
      Previous value: -"Vault-relative path to the note"New value: +"Vault-relative path to the note (e.g. \"TASKS.md\", \"Projects/plan.md\")"
  5. Changed1 schema field changedv0.22.1
    • addedInput schema / properties / content / minLength
      Added value: +1
  6. Changed1 schema field changedv0.19.2
    • addedInput schema / properties / heading / minLength
      Added value: +1
  7. Added

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description goes far beyond the annotations by disclosing side effects: YAML normalization, section-boundary semantics, non-atomic writes, child-heading destruction risk, duplicate-heading rejection, verbatim content insertion, and control-character rejection. It does not contradict the destructiveHint/readOnlyHint annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long, but it is well-structured with labeled sections, bullet lists, and an early example. Every section addresses a real usage question or failure mode. A small amount of repetition around heading duplication and newline handling could be trimmed, but the complexity of the tool justifies most of the length.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given six parameters, no output schema, and a destructive mutation tool, the description is remarkably complete: it covers operations, edge cases, section boundaries, error messages, Obsidian syntax hazards, table-row handling, and the exact return confirmation string. An agent has enough information to invoke the tool correctly and recover from failures.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, and the description still adds substantial meaning for all parameters: operation-specific requirements for heading, content constraints (no leading target heading, newline guidance), heading_level for disambiguation, and include_children as an explicit confirmation of destructive intent. The worked example also clarifies parameter combination.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening sentence names a specific verb ('surgical edits'), a resource ('markdown note'), and the four concrete operations (append, prepend, replace, insert by heading). It clearly differentiates from sibling tools by framing itself as the targeted-edit tool rather than full write or text replacement.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is an explicit 'When to use' section that states when to prefer vault_patch_note versus vault_write_note and vault_replace_in_note. It also walks through a cross-section move scenario involving vault_read_note, vault_patch_note, and vault_replace_in_note, with explicit ordering guidance to avoid data loss.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.